source: trunk/src/wininet/ftp.c@ 4845

Last change on this file since 4845 was 4845, checked in by sandervl, 25 years ago

JH: Resync with latest Wine + fixes/additions

File size: 75.1 KB
Line 
1/* $Id: ftp.c,v 1.4 2000-12-27 23:15:05 sandervl Exp $
2 *
3 * WININET - Ftp implementation
4 *
5 * Copyright 1999 Corel Corporation
6 *
7 * Ulrich Czekalla
8 *
9 */
10
11#include <windows.h>
12#include <wininet.h>
13#include <debugtools.h>
14#include <winerror.h>
15#include <tchar.h>
16#include <winsock.h>
17
18#ifdef __WIN32OS2__
19#include <stdlib.h>
20#include <string.h>
21#else
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netdb.h>
25#include <stdlib.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <errno.h>
29#endif
30
31#include "internet.h"
32
33DEFAULT_DEBUG_CHANNEL(wininet)
34
35#define NOACCOUNT "noaccount"
36#define DATA_PACKET_SIZE 0x2000
37#define szCRLF "\r\n"
38#define MAX_BACKLOG 5
39
40typedef enum {
41 /* FTP commands with arguments. */
42 FTP_CMD_ACCT,
43 FTP_CMD_CWD,
44 FTP_CMD_DELE,
45 FTP_CMD_MKD,
46 FTP_CMD_PASS,
47 FTP_CMD_PORT,
48 FTP_CMD_RETR,
49 FTP_CMD_RMD,
50 FTP_CMD_RNFR,
51 FTP_CMD_RNTO,
52 FTP_CMD_STOR,
53 FTP_CMD_TYPE,
54 FTP_CMD_USER,
55
56 /* FTP commands without arguments. */
57 FTP_CMD_ABOR,
58 FTP_CMD_LIST,
59 FTP_CMD_NLST,
60 FTP_CMD_PWD,
61 FTP_CMD_QUIT,
62} FTP_COMMAND;
63
64static const char *szFtpCommands[] = {
65 "ACCT",
66 "CWD",
67 "DELE",
68 "MKD",
69 "PASS",
70 "PORT",
71 "RETR",
72 "RMD",
73 "RNFR",
74 "RNTO",
75 "STOR",
76 "TYPE",
77 "USER",
78 "ABOR",
79 "LIST",
80 "NLST",
81 "PWD",
82 "QUIT",
83};
84
85static const char szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
86
87BOOL FTP_SendCommand(int nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
88 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
89BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
90BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
91BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, int nDataSocket, HANDLE hFile);
92int FTP_ReceiveResponse(int nSocket, LPSTR lpszResponse, DWORD dwResponse,
93 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
94DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType, LONG *lBytesAvailable);
95BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, int nDataSocket, DWORD nBytes, HANDLE hFile);
96BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
97BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
98BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
99BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
100BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
101BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
102BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
103BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, int nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
104HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, int nSocket,
105 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
106/*LPSTR FTP_GetNextLine(int nSocket, LPSTR lpszBuffer, DWORD dwBuffer);*/
107DWORD FTP_SetResponseError(DWORD dwResponse);
108
109/***********************************************************************
110 * FtpPutFileA (WININET.43)
111 *
112 * Uploads a file to the FTP server
113 *
114 * RETURNS
115 * TRUE on success
116 * FALSE on failure
117 *
118 */
119BOOLAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
120 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
121{
122 LPWININETAPPINFOA hIC = NULL;
123 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
124
125 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
126 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
127 {
128 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
129 return FALSE;
130 }
131
132 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
133 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
134 {
135 WORKREQUEST workRequest;
136
137 workRequest.asyncall = FTPPUTFILEA;
138 workRequest.HFTPSESSION = (DWORD)hConnect;
139 workRequest.LPSZLOCALFILE = (DWORD)strdup(lpszLocalFile);
140 workRequest.LPSZNEWREMOTEFILE = (DWORD)strdup(lpszNewRemoteFile);
141 workRequest.DWFLAGS = dwFlags;
142 workRequest.DWCONTEXT = dwContext;
143
144 return INTERNET_AsyncCall(&workRequest);
145 }
146 else
147 {
148 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
149 lpszNewRemoteFile, dwFlags, dwContext);
150 }
151}
152
153/***********************************************************************
154 * FTP_FtpPutFileA (Internal)
155 *
156 * Uploads a file to the FTP server
157 *
158 * RETURNS
159 * TRUE on success
160 * FALSE on failure
161 *
162 */
163BOOL FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
164 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
165{
166 HANDLE hFile = (HANDLE)NULL;
167 BOOL bSuccess = FALSE;
168 LPWININETAPPINFOA hIC = NULL;
169 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
170 INT nResCode;
171
172 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
173 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
174 {
175 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
176 return FALSE;
177 }
178
179 /* Clear any error information */
180 INTERNET_SetLastError(0);
181
182 /* Open file to be uploaded */
183 if (INVALID_HANDLE_VALUE == (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
184 {
185 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
186 goto lend;
187 }
188
189 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
190 if (hIC->lpfnStatusCB)
191 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
192
193 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
194 {
195 int nDataSocket;
196
197 /* Accept connection from ftp server */
198 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
199 {
200 FTP_SendData(lpwfs, nDataSocket, hFile);
201 close(nDataSocket);
202 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
203 MAX_REPLY_LEN, 0, 0, 0);
204
205 if(nResCode)
206 {
207 if(nResCode == 226)
208 bSuccess = TRUE;
209 else
210 FTP_SetResponseError(nResCode);
211 }
212 }
213 }
214
215lend:
216 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
217 {
218 INTERNET_ASYNC_RESULT iar;
219
220 iar.dwResult = (DWORD)bSuccess;
221 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
222 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
223 &iar, sizeof(INTERNET_ASYNC_RESULT));
224 }
225
226 if (hFile)
227 CloseHandle(hFile);
228
229 return bSuccess;
230}
231
232/***********************************************************************
233 * FtpSetCurrentDirectoryA (WININET.49)
234 *
235 * Change the working directory on the FTP server
236 *
237 * RETURNS
238 * TRUE on success
239 * FALSE on failure
240 *
241 */
242BOOLAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
243{
244 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
245 LPWININETAPPINFOA hIC = NULL;
246
247 TRACE("lpszDirectory(%s)\n", lpszDirectory);
248
249 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
250 {
251 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
252 return FALSE;
253 }
254
255 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
256 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
257 {
258 WORKREQUEST workRequest;
259
260 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
261 workRequest.HFTPSESSION = (DWORD)hConnect;
262 workRequest.LPSZDIRECTORY = (DWORD)strdup(lpszDirectory);
263
264 return INTERNET_AsyncCall(&workRequest);
265 }
266 else
267 {
268 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
269 }
270}
271
272/***********************************************************************
273 * FTP_FtpSetCurrentDirectoryA (Internal)
274 *
275 * Change the working directory on the FTP server
276 *
277 * RETURNS
278 * TRUE on success
279 * FALSE on failure
280 *
281 */
282BOOL FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
283{
284 int nResCode;
285 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
286 LPWININETAPPINFOA hIC = NULL;
287 DWORD bSuccess = FALSE;
288
289 TRACE("lpszDirectory(%s)\n", lpszDirectory);
290
291 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
292 {
293 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
294 return FALSE;
295 }
296
297 /* Clear any error information */
298 INTERNET_SetLastError(0);
299
300 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
301 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
302 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
303 goto lend;
304
305 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
306 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
307 if (nResCode)
308 {
309 if (nResCode == 250)
310 bSuccess = TRUE;
311 else
312 FTP_SetResponseError(nResCode);
313 }
314
315lend:
316 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
317 {
318 INTERNET_ASYNC_RESULT iar;
319
320 iar.dwResult = (DWORD)bSuccess;
321 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
322 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
323 &iar, sizeof(INTERNET_ASYNC_RESULT));
324 }
325 return bSuccess;
326}
327
328
329/***********************************************************************
330 * FtpCreateDirectoryA (WININET.31)
331 *
332 * Create new directory on the FTP server
333 *
334 * RETURNS
335 * TRUE on success
336 * FALSE on failure
337 *
338 */
339BOOLAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
340{
341 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
342 LPWININETAPPINFOA hIC = NULL;
343
344 TRACE("\n");
345 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
346 {
347 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
348 return FALSE;
349 }
350
351 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
352 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
353 {
354 WORKREQUEST workRequest;
355
356 workRequest.asyncall = FTPCREATEDIRECTORYA;
357 workRequest.HFTPSESSION = (DWORD)hConnect;
358 workRequest.LPSZDIRECTORY = (DWORD)strdup(lpszDirectory);
359
360 return INTERNET_AsyncCall(&workRequest);
361 }
362 else
363 {
364 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
365 }
366}
367
368/***********************************************************************
369 * FTP_FtpCreateDirectoryA (Internal)
370 *
371 * Create new directory on the FTP server
372 *
373 * RETURNS
374 * TRUE on success
375 * FALSE on failure
376 *
377 */
378BOOL FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
379{
380 int nResCode;
381 BOOL bSuccess = FALSE;
382 LPWININETAPPINFOA hIC = NULL;
383 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
384
385 TRACE("\n");
386 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
387 {
388 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
389 return FALSE;
390 }
391
392 /* Clear any error information */
393 INTERNET_SetLastError(0);
394
395 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
396 goto lend;
397
398 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
399 MAX_REPLY_LEN, 0, 0, 0);
400 if (nResCode)
401 {
402 if (nResCode == 257)
403 bSuccess = TRUE;
404 else
405 FTP_SetResponseError(nResCode);
406 }
407lend:
408 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
409 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
410 {
411 INTERNET_ASYNC_RESULT iar;
412
413 iar.dwResult = (DWORD)bSuccess;
414 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
415 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
416 &iar, sizeof(INTERNET_ASYNC_RESULT));
417 }
418
419 return bSuccess;
420}
421
422
423/***********************************************************************
424 * FtpFindFirstFileA (WININET.35)
425 *
426 * Search the specified directory
427 *
428 * RETURNS
429 * HINTERNET on success
430 * NULL on failure
431 *
432 */
433INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
434 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
435{
436 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
437 LPWININETAPPINFOA hIC = NULL;
438
439 TRACE("\n");
440
441 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
442 {
443 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
444 return FALSE;
445 }
446
447 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
448 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
449 {
450 WORKREQUEST workRequest;
451
452 workRequest.asyncall = FTPFINDFIRSTFILEA;
453 workRequest.HFTPSESSION = (DWORD)hConnect;
454 workRequest.LPSZSEARCHFILE = (DWORD)strdup(lpszSearchFile);
455 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
456 workRequest.DWFLAGS = dwFlags;
457 workRequest.DWCONTEXT = dwContext;
458
459 INTERNET_AsyncCall(&workRequest);
460 return NULL;
461 }
462 else
463 {
464 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
465 dwFlags, dwContext);
466 }
467}
468
469/***********************************************************************
470 * FTP_FtpFindFirstFileA (Internal)
471 *
472 * Search the specified directory
473 *
474 * RETURNS
475 * HINTERNET on success
476 * NULL on failure
477 *
478 */
479HINTERNET FTP_FtpFindFirstFileA(HINTERNET hConnect,
480 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
481{
482 int nResCode;
483 LPWININETAPPINFOA hIC = NULL;
484 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
485 LPWININETFINDNEXTA hFindNext = NULL;
486
487 TRACE("\n");
488
489 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
490 {
491 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
492 return FALSE;
493 }
494
495 /* Clear any error information */
496 INTERNET_SetLastError(0);
497
498 if (!FTP_InitListenSocket(lpwfs))
499 goto lend;
500
501 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
502 goto lend;
503
504 if (!FTP_SendPort(lpwfs))
505 goto lend;
506
507 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
508 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
509 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
510 goto lend;
511
512 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
513 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
514 if (nResCode)
515 {
516 if (nResCode == 125 || nResCode == 150)
517 {
518 int nDataSocket;
519
520 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
521 {
522 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
523
524 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
525 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
526 if (nResCode != 226 && nResCode != 250)
527 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
528
529 close(nDataSocket);
530 }
531 }
532 else
533 FTP_SetResponseError(nResCode);
534 }
535
536lend:
537 if (lpwfs->lstnSocket != INVALID_SOCKET)
538 close(lpwfs->lstnSocket);
539
540 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
541 {
542 INTERNET_ASYNC_RESULT iar;
543
544 if(hFindNext)
545 {
546 iar.dwResult = (DWORD)hFindNext;
547 iar.dwError = ERROR_SUCCESS;
548 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
549 &iar, sizeof(INTERNET_ASYNC_RESULT));
550 }
551
552 iar.dwResult = (DWORD)hFindNext;
553 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
554 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
555 &iar, sizeof(INTERNET_ASYNC_RESULT));
556 }
557
558 return (HINTERNET)hFindNext;
559}
560
561
562/***********************************************************************
563 * FtpGetCurrentDirectoryA (WININET.37)
564 *
565 * Retrieves the current directory
566 *
567 * RETURNS
568 * TRUE on success
569 * FALSE on failure
570 *
571 */
572BOOLAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
573 LPDWORD lpdwCurrentDirectory)
574{
575 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
576 LPWININETAPPINFOA hIC = NULL;
577
578 TRACE("\n");
579
580 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
581 {
582 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
583 return FALSE;
584 }
585
586 hIC = (LPWININETAPPINFOA)lpwfs->hdr.lpwhparent;
587 if( hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
588 {
589 WORKREQUEST workRequest;
590
591 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
592 workRequest.HFTPSESSION = (DWORD)hFtpSession;
593 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
594 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
595
596 return INTERNET_AsyncCall(&workRequest);
597 }
598 else
599 {
600 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
601 lpdwCurrentDirectory);
602 }
603}
604
605/***********************************************************************
606 * FTP_FtpGetCurrentDirectoryA (Internal)
607 *
608 * Retrieves the current directory
609 *
610 * RETURNS
611 * TRUE on success
612 * FALSE on failure
613 *
614 */
615BOOL FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
616 LPDWORD lpdwCurrentDirectory)
617{
618 int nResCode;
619 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
620 LPWININETAPPINFOA hIC = NULL;
621 DWORD bSuccess = FALSE;
622
623 TRACE("\n");
624
625 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
626 {
627 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
628 return FALSE;
629 }
630
631 /* Clear any error information */
632 INTERNET_SetLastError(0);
633
634 memset(lpszCurrentDirectory, 0, *lpdwCurrentDirectory);
635
636 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
637 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
638 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
639 goto lend;
640
641 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
642 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
643 if (nResCode)
644 {
645 if (nResCode == 257) /* Extract directory name*/
646 {
647 int firstpos, lastpos, len;
648 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
649
650 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
651 {
652 if ('"' == lpszResponseBuffer[lastpos])
653 {
654 if (!firstpos)
655 firstpos = lastpos;
656 else
657 break;
658 }
659 }
660
661 len = lastpos - firstpos + 1;
662 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
663 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
664 *lpdwCurrentDirectory = len;
665 bSuccess = TRUE;
666 }
667 else
668 FTP_SetResponseError(nResCode);
669 }
670
671lend:
672 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
673 {
674 INTERNET_ASYNC_RESULT iar;
675
676 iar.dwResult = (DWORD)bSuccess;
677 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_SUCCESS;
678 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
679 &iar, sizeof(INTERNET_ASYNC_RESULT));
680
681 }
682
683 return (DWORD) bSuccess;
684}
685
686
687/***********************************************************************
688 * FtpOpenFileA (WININET.41)
689 *
690 * Open a remote file for writing or reading
691 *
692 * RETURNS
693 * HINTERNET handle on success
694 * NULL on failure
695 *
696 */
697INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
698 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
699 DWORD dwContext)
700{
701 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
702 LPWININETAPPINFOA hIC = NULL;
703
704 TRACE("\n");
705 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
706 {
707 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
708 return FALSE;
709 }
710
711 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
712
713 if( hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
714 {
715 WORKREQUEST workRequest;
716
717 workRequest.asyncall = FTPOPENFILEA;
718 workRequest.HFTPSESSION = (DWORD)hFtpSession;
719 workRequest.LPSZFILENAME = (DWORD)strdup(lpszFileName);
720 workRequest.FDWACCESS = fdwAccess;
721 workRequest.DWFLAGS = dwFlags;
722 workRequest.DWCONTEXT = dwContext;
723
724 INTERNET_AsyncCall(&workRequest);
725 return NULL;
726 }
727 else
728 {
729 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
730 }
731}
732
733/***********************************************************************
734 * FTP_FtpOpenFileA (Internal)
735 *
736 * Open a remote file for writing or reading
737 *
738 * RETURNS
739 * HINTERNET handle on success
740 * NULL on failure
741 *
742 */
743HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
744 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
745 DWORD dwContext)
746{
747 int nDataSocket;
748 LONG lBytesAvailable = 0;
749 BOOL bSuccess = 0;
750 LPWININETFILE hFile = NULL;
751 LPWININETAPPINFOA hIC = NULL;
752 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
753
754 TRACE("\n");
755 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
756 {
757 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
758 return FALSE;
759 }
760
761 /* Clear any error information */
762 INTERNET_SetLastError(0);
763
764 if (GENERIC_READ == fdwAccess)
765 {
766 /* Set up socket to retrieve data */
767 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags, &lBytesAvailable);
768 }
769 else if (GENERIC_WRITE == fdwAccess)
770 {
771 /* Set up socket to send data */
772 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
773 }
774
775 /* Accept connection from server */
776 if (bSuccess && FTP_InitDataSocket(lpwfs, &nDataSocket))
777 {
778 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
779 WriteLog("Created hFile (OPEN) at %x (%d)",hFile,lBytesAvailable);
780 hFile->hdr.htype = WH_HFILE;
781 hFile->hdr.dwFlags = dwFlags;
782 hFile->hdr.dwContext = dwContext;
783 hFile->hdr.lpwhparent = hFtpSession;
784 hFile->nDataSocket = nDataSocket;
785 hFile->lBytesAvailable = lBytesAvailable;
786 }
787
788 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
789 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
790 {
791 INTERNET_ASYNC_RESULT iar;
792
793 if(hFile)
794 {
795 iar.dwResult = (DWORD)hFile;
796 iar.dwError = ERROR_SUCCESS;
797 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
798 &iar, sizeof(INTERNET_ASYNC_RESULT));
799 }
800
801 iar.dwResult = (DWORD)bSuccess;
802 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
803 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
804 &iar, sizeof(INTERNET_ASYNC_RESULT));
805 }
806
807 return (HINTERNET)hFile;
808}
809
810/***********************************************************************
811 * FtpGetFileA (WININET.39)
812 *
813 * Retrieve file from the FTP server
814 *
815 * RETURNS
816 * TRUE on success
817 * FALSE on failure
818 *
819 */
820BOOLAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
821 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
822 DWORD dwContext)
823{
824 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
825 LPWININETAPPINFOA hIC = NULL;
826
827 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
828 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
829 {
830 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
831 return FALSE;
832 }
833
834 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
835 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
836 {
837 WORKREQUEST workRequest;
838
839 workRequest.asyncall = FTPGETFILEA;
840 workRequest.HFTPSESSION = (DWORD)hInternet;
841 workRequest.LPSZREMOTEFILE = (DWORD)strdup(lpszRemoteFile);
842 workRequest.LPSZNEWFILE = (DWORD)strdup(lpszNewFile);
843 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
844 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
845 workRequest.DWFLAGS = dwInternetFlags;
846 workRequest.DWCONTEXT = dwContext;
847
848 return INTERNET_AsyncCall(&workRequest);
849 }
850 else
851 {
852 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
853 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
854 }
855}
856
857/***********************************************************************
858 * FTP_FtpGetFileA (Internal)
859 *
860 * Retrieve file from the FTP server
861 *
862 * RETURNS
863 * TRUE on success
864 * FALSE on failure
865 *
866 */
867BOOL FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
868 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
869 DWORD dwContext)
870{
871 DWORD nBytes;
872 BOOL bSuccess = FALSE;
873 HANDLE hFile;
874 LPWININETAPPINFOA hIC = NULL;
875 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
876
877 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
878 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
879 {
880 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
881 return FALSE;
882 }
883
884 /* Clear any error information */
885 INTERNET_SetLastError(0);
886
887 /* Ensure we can write to lpszNewfile by opening it */
888 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
889 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
890 if (INVALID_HANDLE_VALUE == hFile)
891 goto lend;
892
893 /* Set up socket to retrieve data */
894 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags, NULL);
895
896 if (nBytes > 0)
897 {
898 int nDataSocket;
899
900 /* Accept connection from ftp server */
901 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
902 {
903 int nResCode;
904
905 /* Receive data */
906 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
907 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
908 MAX_REPLY_LEN, 0, 0, 0);
909 if (nResCode)
910 {
911 if (nResCode == 226)
912 bSuccess = TRUE;
913 else
914 FTP_SetResponseError(nResCode);
915
916 }
917 close(nDataSocket);
918 }
919 }
920
921lend:
922 if (hFile)
923 CloseHandle(hFile);
924
925 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
926 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
927 {
928 INTERNET_ASYNC_RESULT iar;
929
930 iar.dwResult = (DWORD)bSuccess;
931 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
932 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
933 &iar, sizeof(INTERNET_ASYNC_RESULT));
934 }
935
936 return bSuccess;
937}
938
939/***********************************************************************
940 * FTP_DeleteFileA (WININET.33)
941 *
942 * Delete a file on the ftp server
943 *
944 * RETURNS
945 * TRUE on success
946 * FALSE on failure
947 *
948 */
949BOOLAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
950{
951 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
952 LPWININETAPPINFOA hIC = NULL;
953
954 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
955 {
956 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
957 return FALSE;
958 }
959
960 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
961 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
962 {
963 WORKREQUEST workRequest;
964
965 workRequest.asyncall = FTPDELETEFILEA;
966 workRequest.HFTPSESSION = (DWORD)hFtpSession;
967 workRequest.LPSZFILENAME = (DWORD)strdup(lpszFileName);
968
969 return INTERNET_AsyncCall(&workRequest);
970 }
971 else
972 {
973 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
974 }
975}
976
977/***********************************************************************
978 * FTP_FtpDeleteFileA (Internal)
979 *
980 * Delete a file on the ftp server
981 *
982 * RETURNS
983 * TRUE on success
984 * FALSE on failure
985 *
986 */
987BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
988{
989 INT nResCode;
990 BOOL bSuccess = FALSE;
991 LPWININETAPPINFOA hIC = NULL;
992 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
993
994 TRACE("0x%08lx\n", (ULONG) hFtpSession);
995 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
996 {
997 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
998 return FALSE;
999 }
1000
1001 /* Clear any error information*/
1002 INTERNET_SetLastError(0);
1003
1004 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1005 goto lend;
1006
1007 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1008 MAX_REPLY_LEN, 0, 0, 0);
1009 if (nResCode)
1010 {
1011 if (nResCode == 250)
1012 bSuccess = TRUE;
1013 else
1014 FTP_SetResponseError(nResCode);
1015 }
1016lend:
1017 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1018 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1019 {
1020 INTERNET_ASYNC_RESULT iar;
1021
1022 iar.dwResult = (DWORD)bSuccess;
1023 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1024 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1025 &iar, sizeof(INTERNET_ASYNC_RESULT));
1026 }
1027
1028 return bSuccess;
1029}
1030
1031/***********************************************************************
1032 * FtpRemoveDirectoryA (WININET.45)
1033 *
1034 * Remove a directory on the ftp server
1035 *
1036 * RETURNS
1037 * TRUE on success
1038 * FALSE on failure
1039 *
1040 */
1041BOOLAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1042{
1043 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1044 LPWININETAPPINFOA hIC = NULL;
1045
1046 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1047 {
1048 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1049 return FALSE;
1050 }
1051
1052 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1053 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1054 {
1055 WORKREQUEST workRequest;
1056
1057 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1058 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1059 workRequest.LPSZDIRECTORY = (DWORD)strdup(lpszDirectory);
1060
1061 return INTERNET_AsyncCall(&workRequest);
1062 }
1063 else
1064 {
1065 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1066 }
1067}
1068
1069/************************************************************************
1070 * FTP_FtpRemoveDirectoryA (Internal)
1071 *
1072 * Remove a directory on the ftp server
1073 *
1074 * RETURNS
1075 * TRUE on success
1076 * FALSE on failure
1077 *
1078 */
1079BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1080{
1081 INT nResCode;
1082 BOOL bSuccess = FALSE;
1083 LPWININETAPPINFOA hIC = NULL;
1084 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1085
1086 TRACE("\n");
1087 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1088 {
1089 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1090 return FALSE;
1091 }
1092
1093 /* Clear any error information*/
1094 INTERNET_SetLastError(0);
1095
1096 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1097 goto lend;
1098
1099 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1100 MAX_REPLY_LEN, 0, 0, 0);
1101 if (nResCode)
1102 {
1103 if (nResCode == 250)
1104 bSuccess = TRUE;
1105 else
1106 FTP_SetResponseError(nResCode);
1107 }
1108
1109lend:
1110 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1111 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1112 {
1113 INTERNET_ASYNC_RESULT iar;
1114
1115 iar.dwResult = (DWORD)bSuccess;
1116 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1117 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1118 &iar, sizeof(INTERNET_ASYNC_RESULT));
1119 }
1120
1121 return bSuccess;
1122}
1123
1124/***********************************************************************
1125 * FtpRenameFileA (WININET.47)
1126 *
1127 * Rename a file on the ftp server
1128 *
1129 * RETURNS
1130 * TRUE on success
1131 * FALSE on failure
1132 *
1133 */
1134BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1135{
1136 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1137 LPWININETAPPINFOA hIC = NULL;
1138
1139 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1140 {
1141 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1142 return FALSE;
1143 }
1144
1145 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1146 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1147 {
1148 WORKREQUEST workRequest;
1149
1150 workRequest.asyncall = FTPRENAMEFILEA;
1151 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1152 workRequest.LPSZSRCFILE = (DWORD)strdup(lpszSrc);
1153 workRequest.LPSZDESTFILE = (DWORD)strdup(lpszDest);
1154
1155 return INTERNET_AsyncCall(&workRequest);
1156 }
1157 else
1158 {
1159 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1160 }
1161}
1162
1163/************************************************************************
1164 * FTP_FtpRenameFileA (Internal)
1165 *
1166 * Rename a file on the ftp server
1167 *
1168 * RETURNS
1169 * TRUE on success
1170 * FALSE on failure
1171 *
1172 */
1173BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1174{
1175 INT nResCode;
1176 BOOL bSuccess = FALSE;
1177 LPWININETAPPINFOA hIC = NULL;
1178 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1179
1180 TRACE("\n");
1181 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1182 {
1183 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1184 return FALSE;
1185 }
1186
1187 /* Clear any error information*/
1188 INTERNET_SetLastError(0);
1189
1190 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1191 goto lend;
1192
1193 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1194 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1195 if (nResCode == 350)
1196 {
1197 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1198 goto lend;
1199
1200 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1201 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1202 }
1203
1204 if (nResCode == 250)
1205 bSuccess = TRUE;
1206 else
1207 FTP_SetResponseError(nResCode);
1208
1209lend:
1210 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1211 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1212 {
1213 INTERNET_ASYNC_RESULT iar;
1214
1215 iar.dwResult = (DWORD)bSuccess;
1216 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1217 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1218 &iar, sizeof(INTERNET_ASYNC_RESULT));
1219 }
1220
1221 return bSuccess;
1222}
1223
1224
1225/***********************************************************************
1226 * FTP_Connect (internal)
1227 *
1228 * Connect to a ftp server
1229 *
1230 * RETURNS
1231 * HINTERNET a session handle on success
1232 * NULL on failure
1233 *
1234 */
1235
1236HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1237 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1238 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1239{
1240 struct sockaddr_in socketAddr;
1241 struct hostent *phe = NULL;
1242 int nsocket = INVALID_SOCKET, sock_namelen;
1243 LPWININETAPPINFOA hIC = NULL;
1244 BOOL result, bSuccess = FALSE;
1245 LPWININETFTPSESSIONA lpwfs = NULL;
1246
1247 TRACE(" Server(%s) Port(%d) User(%s)\n", lpszServerName, nServerPort,
1248 lpszUserName);
1249
1250 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1251 goto lerror;
1252
1253 hIC = (LPWININETAPPINFOA) hInternet;
1254
1255 if (NULL == lpszUserName && NULL != lpszPassword)
1256 {
1257 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1258 goto lerror;
1259 }
1260
1261 if(nServerPort == INTERNET_INVALID_PORT_NUMBER)
1262 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1263
1264 if (hIC->lpfnStatusCB)
1265 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1266 (LPSTR)lpszServerName, strlen(lpszServerName));
1267
1268 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1269 {
1270 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1271 goto lerror;
1272 }
1273
1274 if (hIC->lpfnStatusCB)
1275 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1276 (LPSTR)lpszServerName, strlen(lpszServerName));
1277
1278 if (INVALID_SOCKET == (nsocket = socket(AF_INET, SOCK_STREAM, 0)))
1279 {
1280 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1281 goto lerror;
1282 }
1283
1284 if(hIC->lpfnStatusCB)
1285 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1286 &socketAddr, sizeof(struct sockaddr_in));
1287
1288 if(connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1289 {
1290 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1291 }
1292 else
1293 {
1294 TRACE("Connected to server\n");
1295
1296 if(hIC->lpfnStatusCB)
1297 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1298 &socketAddr, sizeof(struct sockaddr_in));
1299
1300 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1301 if (NULL == lpwfs)
1302 {
1303 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1304 goto lerror;
1305 }
1306
1307 lpwfs->hdr.htype = WH_HFTPSESSION;
1308 lpwfs->hdr.dwFlags = dwFlags;
1309 lpwfs->hdr.dwContext = dwContext;
1310 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1311 lpwfs->sndSocket = nsocket;
1312 sock_namelen = sizeof(lpwfs->socketAddress);
1313 getsockname(nsocket,(struct sockaddr *)&lpwfs->socketAddress, &sock_namelen);
1314 lpwfs->phostent = phe;
1315
1316 if (NULL == lpszUserName)
1317 {
1318 lpwfs->lpszUserName = strdup("anonymous");
1319 lpwfs->lpszPassword = strdup("user@server");
1320 }
1321 else
1322 {
1323 lpwfs->lpszUserName = strdup(lpszUserName);
1324 lpwfs->lpszPassword = strdup(lpszPassword);
1325 }
1326
1327 if (FTP_ConnectToHost(lpwfs))
1328 {
1329 if (hIC->lpfnStatusCB)
1330 {
1331 INTERNET_ASYNC_RESULT iar;
1332
1333 iar.dwResult = (DWORD)lpwfs;
1334 iar.dwError = ERROR_SUCCESS;
1335
1336 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1337 &iar, sizeof(INTERNET_ASYNC_RESULT));
1338 }
1339 TRACE("Successfully logged into server\n");
1340 bSuccess = TRUE;
1341 }
1342 }
1343
1344lerror:
1345 if (!bSuccess && INVALID_SOCKET != nsocket)
1346 close(nsocket);
1347
1348 if (!bSuccess && lpwfs)
1349 {
1350 HeapFree(GetProcessHeap(), 0, lpwfs);
1351 lpwfs = NULL;
1352 }
1353
1354 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1355 {
1356 INTERNET_ASYNC_RESULT iar;
1357
1358 iar.dwResult = (DWORD)lpwfs;
1359 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1360 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1361 &iar, sizeof(INTERNET_ASYNC_RESULT));
1362 }
1363
1364 return (HINTERNET) lpwfs;
1365}
1366
1367
1368/***********************************************************************
1369 * FTP_ConnectHost (internal)
1370 *
1371 * Connect to a ftp server
1372 *
1373 * RETURNS
1374 * TRUE on success
1375 * NULL on failure
1376 *
1377 */
1378BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1379{
1380 int nResCode;
1381 BOOL bSuccess = FALSE;
1382
1383 TRACE("\n");
1384 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1385
1386 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1387 goto lend;
1388
1389 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1390 MAX_REPLY_LEN, 0, 0, 0);
1391 if (nResCode)
1392 {
1393 /* Login successful... */
1394 if (nResCode == 230)
1395 bSuccess = TRUE;
1396 /* User name okay, need password... */
1397 else if (nResCode == 331)
1398 bSuccess = FTP_SendPassword(lpwfs);
1399 /* Need account for login... */
1400 else if (nResCode == 332)
1401 bSuccess = FTP_SendAccount(lpwfs);
1402 else
1403 FTP_SetResponseError(nResCode);
1404 }
1405
1406 TRACE("Returning %d\n", bSuccess);
1407lend:
1408 return bSuccess;
1409}
1410
1411
1412/***********************************************************************
1413 * FTP_SendCommand (internal)
1414 *
1415 * Send command to server
1416 *
1417 * RETURNS
1418 * TRUE on success
1419 * NULL on failure
1420 *
1421 */
1422BOOL FTP_SendCommand(int nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1423 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1424{
1425 int len;
1426 char *buf;
1427 int nBytesSent = 0;
1428 int nRC = 0;
1429 BOOL bParamHasLen;
1430
1431 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1432
1433 if(lpfnStatusCB)
1434 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1435
1436 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1437 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1438 strlen(szCRLF)+ 1;
1439 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1440 {
1441 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1442 return FALSE;
1443 }
1444 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1445 bParamHasLen ? lpszParam : "", szCRLF);
1446
1447 TRACE("Sending (%s)\n", buf);
1448 while((nBytesSent < len) && (nRC != SOCKET_ERROR))
1449 {
1450 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1451 /* Here, we shall call the callback function to update the status. */
1452 nBytesSent += nRC;
1453 }
1454
1455 HeapFree(GetProcessHeap(), 0, buf);
1456
1457 if(lpfnStatusCB)
1458 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1459 &nBytesSent, sizeof(DWORD));
1460
1461 return (nRC != SOCKET_ERROR);
1462}
1463
1464
1465/***********************************************************************
1466 * FTP_ReceiveResponse (internal)
1467 *
1468 * Receive response from server
1469 *
1470 * RETURNS
1471 * Reply code on success
1472 * 0 on failure
1473 *
1474 */
1475
1476int FTP_ReceiveResponse(int nSocket, LPSTR lpszResponse, DWORD dwResponse,
1477 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1478{
1479 DWORD nRecv = 0;
1480 int rc = 0;
1481 char firstprefix[5];
1482 BOOL multiline = FALSE;
1483
1484 TRACE("\n");
1485
1486 if(lpfnStatusCB)
1487 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1488
1489 while(1)
1490 {
1491 nRecv = dwResponse;
1492
1493 if(!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1494 goto lerror;
1495
1496 if (nRecv >= 3)
1497 {
1498 if(!multiline)
1499 {
1500 if(lpszResponse[3] != '-')
1501 break;
1502 else
1503 {
1504 /* Start multiline response. Loop until we get 'nnn' */
1505 multiline = TRUE;
1506 memcpy(firstprefix, lpszResponse, 3);
1507 firstprefix[3] = ' ';
1508 firstprefix[4] = '\0';
1509 }
1510 }
1511 else
1512 {
1513 if(!memcmp(firstprefix, lpszResponse, 4))
1514 break;
1515 }
1516 }
1517 }
1518
1519 if (nRecv >= 3)
1520 {
1521 lpszResponse[nRecv] = '\0';
1522 rc = atoi(lpszResponse);
1523
1524 if(lpfnStatusCB)
1525 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1526 &nRecv, sizeof(DWORD));
1527 }
1528
1529lerror:
1530 return rc;
1531}
1532
1533
1534/***********************************************************************
1535 * FTP_SendPassword (internal)
1536 *
1537 * Send password to ftp server
1538 *
1539 * RETURNS
1540 * TRUE on success
1541 * NULL on failure
1542 *
1543 */
1544BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1545{
1546 int nResCode;
1547 BOOL bSuccess = FALSE;
1548
1549 TRACE("\n");
1550 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1551 goto lend;
1552
1553 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1554 MAX_REPLY_LEN, 0, 0, 0);
1555 if (nResCode)
1556 {
1557 TRACE("Received reply code %d\n", nResCode);
1558 /* Login successful... */
1559 if (nResCode == 230)
1560 bSuccess = TRUE;
1561 /* Command not implemented, superfluous at the server site... */
1562 /* Need account for login... */
1563 else if (nResCode == 332)
1564 bSuccess = FTP_SendAccount(lpwfs);
1565 else
1566 FTP_SetResponseError(nResCode);
1567 }
1568lend:
1569 TRACE("Returning %d\n", bSuccess);
1570 return bSuccess;
1571}
1572
1573
1574/***********************************************************************
1575 * FTP_SendAccount (internal)
1576 *
1577 *
1578 *
1579 * RETURNS
1580 * TRUE on success
1581 * FALSE on failure
1582 *
1583 */
1584BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1585{
1586 int nResCode;
1587 BOOL bSuccess = FALSE;
1588
1589 TRACE("\n");
1590 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1591 goto lend;
1592
1593 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1594 MAX_REPLY_LEN, 0, 0, 0);
1595 if (nResCode)
1596 {
1597 bSuccess = TRUE;
1598 }
1599 else
1600 FTP_SetResponseError(nResCode);
1601
1602lend:
1603 return bSuccess;
1604}
1605
1606
1607/***********************************************************************
1608 * FTP_SendStore (internal)
1609 *
1610 * Send request to upload file to ftp server
1611 *
1612 * RETURNS
1613 * TRUE on success
1614 * FALSE on failure
1615 *
1616 */
1617BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1618{
1619 int nResCode;
1620 BOOL bSuccess = FALSE;
1621
1622 TRACE("\n");
1623 if (!FTP_InitListenSocket(lpwfs))
1624 goto lend;
1625
1626 if (!FTP_SendType(lpwfs, dwType))
1627 goto lend;
1628
1629 if (!FTP_SendPort(lpwfs))
1630 goto lend;
1631
1632 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1633 goto lend;
1634
1635 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1636 MAX_REPLY_LEN, 0, 0, 0);
1637 if (nResCode)
1638 {
1639 if (nResCode == 150)
1640 bSuccess = TRUE;
1641 else
1642 FTP_SetResponseError(nResCode);
1643 }
1644
1645lend:
1646 if (!bSuccess && INVALID_SOCKET != lpwfs->lstnSocket)
1647 {
1648 close(lpwfs->lstnSocket);
1649 lpwfs->lstnSocket = INVALID_SOCKET;
1650 }
1651
1652 return bSuccess;
1653}
1654
1655
1656/***********************************************************************
1657 * FTP_InitListenSocket (internal)
1658 *
1659 * Create a socket to listen for server response
1660 *
1661 * RETURNS
1662 * TRUE on success
1663 * FALSE on failure
1664 *
1665 */
1666BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1667{
1668 BOOL bSuccess = FALSE;
1669 socklen_t namelen = sizeof(struct sockaddr_in);
1670
1671 TRACE("\n");
1672
1673 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1674 if (INVALID_SOCKET == lpwfs->lstnSocket)
1675 {
1676 TRACE("Unable to create listening socket\n");
1677 goto lend;
1678 }
1679
1680 /* We obtain our IP addr from the name of the command cgannel socket */
1681 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1682
1683 /* and get the system to assign us a port */
1684 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1685
1686 if (SOCKET_ERROR == bind(lpwfs->lstnSocket, (struct sockaddr *)&lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)))
1687 {
1688 TRACE("Unable to bind socket: %d\n", errno);
1689 goto lend;
1690 }
1691
1692 if (SOCKET_ERROR == listen(lpwfs->lstnSocket, MAX_BACKLOG))
1693 {
1694 TRACE("listen failed\n");
1695 goto lend;
1696 }
1697
1698 if (SOCKET_ERROR != getsockname(lpwfs->lstnSocket, (struct sockaddr *)&lpwfs->lstnSocketAddress, &namelen))
1699 bSuccess = TRUE;
1700
1701lend:
1702 if (!bSuccess && INVALID_SOCKET == lpwfs->lstnSocket)
1703 {
1704 close(lpwfs->lstnSocket);
1705 lpwfs->lstnSocket = INVALID_SOCKET;
1706 }
1707
1708 return bSuccess;
1709}
1710
1711
1712/***********************************************************************
1713 * FTP_SendType (internal)
1714 *
1715 * Tell server type of data being transfered
1716 *
1717 * RETURNS
1718 * TRUE on success
1719 * FALSE on failure
1720 *
1721 */
1722BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1723{
1724 int nResCode;
1725 char type[2] = { "I\0" };
1726 BOOL bSuccess = FALSE;
1727
1728 TRACE("\n");
1729 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1730 *type = 'A';
1731
1732 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1733 goto lend;
1734
1735 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1736 MAX_REPLY_LEN, 0, 0, 0)/100;
1737 if (nResCode)
1738 {
1739 if (nResCode == 2)
1740 bSuccess = TRUE;
1741 else
1742 FTP_SetResponseError(nResCode);
1743 }
1744
1745lend:
1746 return bSuccess;
1747}
1748
1749
1750/***********************************************************************
1751 * FTP_SendPort (internal)
1752 *
1753 * Tell server which port to use
1754 *
1755 * RETURNS
1756 * TRUE on success
1757 * FALSE on failure
1758 *
1759 */
1760BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1761{
1762 int nResCode;
1763 char szIPAddress[64];
1764 BOOL bSuccess = FALSE;
1765
1766 TRACE("\n");
1767
1768 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1769 lpwfs->socketAddress.sin_addr.s_addr&0x000000FF,
1770 (lpwfs->socketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1771 (lpwfs->socketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1772 (lpwfs->socketAddress.sin_addr.s_addr&0xFF000000)>>24,
1773 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1774 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1775
1776 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1777 goto lend;
1778
1779 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1780 MAX_REPLY_LEN, 0, 0, 0);
1781 if (nResCode)
1782 {
1783 if (nResCode == 200)
1784 bSuccess = TRUE;
1785 else
1786 FTP_SetResponseError(nResCode);
1787 }
1788
1789lend:
1790 return bSuccess;
1791}
1792
1793
1794/***********************************************************************
1795 * FTP_InitDataSocket (internal)
1796 *
1797 *
1798 *
1799 * RETURNS
1800 * TRUE on success
1801 * FALSE on failure
1802 *
1803 */
1804BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1805{
1806 struct sockaddr_in saddr;
1807 socklen_t addrlen = sizeof(struct sockaddr);
1808
1809 TRACE("\n");
1810 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *)&saddr, &addrlen);
1811 close(lpwfs->lstnSocket);
1812 lpwfs->lstnSocket = INVALID_SOCKET;
1813
1814 return *nDataSocket != INVALID_SOCKET;
1815}
1816
1817
1818/***********************************************************************
1819 * FTP_SendData (internal)
1820 *
1821 * Send data to the server
1822 *
1823 * RETURNS
1824 * TRUE on success
1825 * FALSE on failure
1826 *
1827 */
1828BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, int nDataSocket, HANDLE hFile)
1829{
1830 BY_HANDLE_FILE_INFORMATION fi;
1831 DWORD nBytesRead = 0;
1832 DWORD nBytesSent = 0;
1833 DWORD nTotalSent = 0;
1834 LONG nBytesToSend;
1835 DWORD nLen, nRC = 1;
1836 time_t s_long_time, e_long_time;
1837 long nSeconds;
1838 char *lpszBuffer;
1839
1840 TRACE("\n");
1841 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char)*DATA_PACKET_SIZE);
1842 memset(lpszBuffer, 0, sizeof(char)*DATA_PACKET_SIZE);
1843
1844 /* Get the size of the file. */
1845 GetFileInformationByHandle(hFile, &fi);
1846 time(&s_long_time);
1847
1848 do
1849 {
1850 nBytesToSend = nBytesRead - nBytesSent;
1851
1852 if (nBytesToSend <= 0)
1853 {
1854 /* Read data from file. */
1855 nBytesSent = 0;
1856 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
1857 ERR("Failed reading from file\n");
1858
1859 if (nBytesRead > 0)
1860 nBytesToSend = nBytesRead;
1861 else
1862 break;
1863 }
1864
1865 nLen = DATA_PACKET_SIZE < nBytesToSend ?
1866 DATA_PACKET_SIZE : nBytesToSend;
1867 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
1868
1869 if (nRC != SOCKET_ERROR)
1870 {
1871 nBytesSent += nRC;
1872 nTotalSent += nRC;
1873 }
1874
1875 /* Do some computation to display the status. */
1876 time(&e_long_time);
1877 nSeconds = e_long_time - s_long_time;
1878 if( nSeconds / 60 > 0 )
1879 {
1880/*
1881 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remainig time %d sec\t\t\r",
1882 nTotalSent, fi.nFileSizeLow, nTotalSent*100/st.st_size, nSeconds / 60,
1883 nSeconds % 60, (st.st_size - nTotalSent) * nSeconds / nTotalSent );
1884*/
1885 }
1886 else
1887 {
1888/*
1889 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remainig time %d sec\t\t\r",
1890 nTotalSent, fi.nFileSizeLow, nTotalSent*100/st.st_size, nSeconds,
1891 (st.st_size - nTotalSent) * nSeconds / nTotalSent);
1892*/
1893
1894 }
1895 } while (nRC != SOCKET_ERROR);
1896
1897 TRACE("file transfer complete!\n");
1898
1899 if(lpszBuffer != NULL)
1900 HeapFree(GetProcessHeap(), 0, lpszBuffer);
1901
1902 return nTotalSent;
1903}
1904
1905
1906/***********************************************************************
1907 * FTP_SendRetrieve (internal)
1908 *
1909 * Send request to retrieve a file
1910 *
1911 * RETURNS
1912 * Number of bytes to be received on success
1913 * 0 on failure
1914 *
1915 */
1916DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType, LONG *lBytesAvailable)
1917{
1918 int nResCode;
1919 DWORD nResult = 0;
1920
1921 TRACE("\n");
1922 if (!FTP_InitListenSocket(lpwfs))
1923 goto lend;
1924
1925 if (!FTP_SendType(lpwfs, dwType))
1926 goto lend;
1927
1928 if (!FTP_SendPort(lpwfs))
1929 goto lend;
1930
1931 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
1932 goto lend;
1933
1934 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1935 MAX_REPLY_LEN, 0, 0, 0);
1936 if (nResCode)
1937 {
1938 if (nResCode == 125 || nResCode == 150)
1939 {
1940 /* Parse size of data to be retrieved */
1941 int i, sizepos = -1;
1942 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1943 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
1944 {
1945 if ('(' == lpszResponseBuffer[i])
1946 {
1947 sizepos = i;
1948 break;
1949 }
1950 }
1951
1952 if (sizepos >= 0)
1953 {
1954 nResult = atol(&lpszResponseBuffer[sizepos+1]);
1955 TRACE("Waiting to receive %d bytes\n", nResult);
1956
1957 if(lBytesAvailable)
1958 *lBytesAvailable = nResult;
1959 }
1960 else
1961 if(lBytesAvailable)
1962 *lBytesAvailable = -1;
1963 }
1964 }
1965
1966lend:
1967 if (0 == nResult && INVALID_SOCKET != lpwfs->lstnSocket)
1968 {
1969 close(lpwfs->lstnSocket);
1970 lpwfs->lstnSocket = INVALID_SOCKET;
1971 }
1972
1973 return nResult;
1974}
1975
1976
1977/***********************************************************************
1978 * FTP_RetrieveData (internal)
1979 *
1980 * Retrieve data from server
1981 *
1982 * RETURNS
1983 * TRUE on success
1984 * FALSE on failure
1985 *
1986 */
1987BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, int nDataSocket, DWORD nBytes, HANDLE hFile)
1988{
1989 DWORD nBytesWritten;
1990 DWORD nBytesReceived = 0;
1991 int nRC = 0;
1992 char *lpszBuffer;
1993
1994 TRACE("\n");
1995
1996 if (INVALID_HANDLE_VALUE == hFile)
1997 return FALSE;
1998
1999 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char)*DATA_PACKET_SIZE);
2000 if (NULL == lpszBuffer)
2001 {
2002 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2003 return FALSE;
2004 }
2005
2006 while (nBytesReceived < nBytes && nRC != SOCKET_ERROR)
2007 {
2008 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2009 if (nRC != SOCKET_ERROR)
2010 {
2011 /* other side closed socket. */
2012 if (nRC == 0)
2013 goto recv_end;
2014 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2015 nBytesReceived += nRC;
2016
2017// INTERNET_SubstractFromDataAvailable(lpwfs,nRC);
2018 }
2019
2020 TRACE("%d bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2021 nBytesReceived * 100 / nBytes);
2022 }
2023
2024 TRACE("Data transfer complete\n");
2025 if (NULL != lpszBuffer)
2026 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2027
2028recv_end:
2029 return (nRC != SOCKET_ERROR);
2030}
2031
2032
2033/***********************************************************************
2034 * FTP_CloseSessionHandle (internal)
2035 *
2036 * Deallocate session handle
2037 *
2038 * RETURNS
2039 * TRUE on success
2040 * FALSE on failure
2041 *
2042 */
2043BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2044{
2045 if (INVALID_SOCKET != lpwfs->sndSocket)
2046 close(lpwfs->sndSocket);
2047
2048 if (INVALID_SOCKET != lpwfs->lstnSocket)
2049 close(lpwfs->lstnSocket);
2050
2051 if (lpwfs->lpszPassword)
2052 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2053
2054 if (lpwfs->lpszUserName)
2055 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2056
2057 if (INTERNET_GetResponseBuffer())
2058 HeapFree(GetProcessHeap(), 0, INTERNET_GetResponseBuffer());
2059
2060 HeapFree(GetProcessHeap(), 0, lpwfs);
2061
2062 return TRUE;
2063}
2064
2065
2066/***********************************************************************
2067 * FTP_CloseSessionHandle (internal)
2068 *
2069 * Deallocate session handle
2070 *
2071 * RETURNS
2072 * TRUE on success
2073 * FALSE on failure
2074 *
2075 */
2076BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2077{
2078 int i;
2079
2080 for (i = 0; i < lpwfn->size; i++)
2081 {
2082 if (NULL != lpwfn->lpafp[i].lpszName)
2083 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2084 }
2085
2086 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2087 HeapFree(GetProcessHeap(), 0, lpwfn);
2088
2089 return TRUE;
2090}
2091
2092
2093/***********************************************************************
2094 * FTP_ReceiveFileList (internal)
2095 *
2096 * Read file list from server
2097 *
2098 * RETURNS
2099 * Handle to file list on success
2100 * NULL on failure
2101 *
2102 */
2103HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, int nSocket,
2104 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2105{
2106 DWORD dwSize;
2107 LPFILEPROPERTIESA lpafp = NULL;
2108 LPWININETFINDNEXTA lpwfn = NULL;
2109
2110 TRACE("\n");
2111
2112 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2113 {
2114 FTP_ConvertFileProp(lpafp, lpFindFileData);
2115
2116 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2117 if (NULL != lpwfn)
2118 {
2119 lpwfn->hdr.htype = WH_HFINDNEXT;
2120 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2121 lpwfn->index = 1;
2122 lpwfn->size = dwSize;
2123 lpwfn->lpafp = lpafp;
2124 }
2125 }
2126
2127 return (HINTERNET)lpwfn;
2128}
2129
2130
2131/***********************************************************************
2132 * FTP_ConvertFileProp (internal)
2133 *
2134 Converts FILEPROPERTIESA struct to WIN32_FILE_DATAA
2135 *
2136 * RETURNS
2137 * TRUE on success
2138 * FALSE on failure
2139 *
2140 */
2141BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2142{
2143 BOOL bSuccess = FALSE;
2144
2145 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2146
2147 if(lpafp)
2148 {
2149 DWORD access = mktime(&lpafp->tmLastModified);
2150
2151 /* Not all fields are filled in */
2152 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2153 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2154 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2155 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2156
2157 if(lpafp->bIsDirectory)
2158 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2159
2160 if(lpafp->lpszName)
2161 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2162
2163 bSuccess = TRUE;
2164 }
2165
2166 return bSuccess;
2167}
2168
2169/***********************************************************************
2170 * FTP_ParseDirectory (internal)
2171 *
2172 * Parse string of directory information
2173 *
2174 * RETURNS
2175 * TRUE on success
2176 * FALSE on failure
2177 *
2178 */
2179#define MAX_MONTH_LEN 10
2180#define MIN_LEN_DIR_ENTRY 15
2181
2182BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, int nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2183{
2184 /*
2185 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2186 *
2187 * For instance:
2188 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2189 */
2190 char* pszMinutes;
2191 char* pszHour;
2192 time_t aTime;
2193 struct tm* apTM;
2194 char pszMonth[MAX_MONTH_LEN];
2195 char* pszMatch;
2196 BOOL bSuccess = TRUE;
2197 DWORD nBufLen = MAX_REPLY_LEN;
2198 LPFILEPROPERTIESA curFileProp = NULL;
2199 char* pszLine = NULL;
2200 char* pszToken = NULL;
2201 int nTokenToSkip = 3;
2202 int nCount = 0;
2203 int nSeconds = 0;
2204 int nMinutes = 0;
2205 int nHour = 0;
2206 int nDay = 0;
2207 int nMonth = 0;
2208 int nYear = 0;
2209 int sizeFilePropArray = 20;
2210 int indexFilePropArray = 0;
2211
2212 TRACE("\n");
2213
2214 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2215 if(NULL == lpafp)
2216 {
2217 bSuccess = FALSE;
2218 goto lend;
2219 }
2220
2221 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2222 {
2223 if (sizeFilePropArray < indexFilePropArray)
2224 {
2225 LPFILEPROPERTIESA tmpafp;
2226
2227 sizeFilePropArray *= 2;
2228 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2229 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2230 if (NULL == tmpafp)
2231 {
2232 bSuccess = FALSE;
2233 goto lend;
2234 }
2235
2236 *lpafp = tmpafp;
2237 }
2238
2239 curFileProp = &((*lpafp)[indexFilePropArray]);
2240
2241 /* First Parse the permissions. */
2242 pszToken = strtok(pszLine, " \t" );
2243
2244 if(!pszToken || 10 != strlen(pszToken) || nBufLen < MIN_LEN_DIR_ENTRY)
2245 {
2246 nBufLen = MAX_REPLY_LEN;
2247 continue;
2248 }
2249
2250 FTP_ParsePermission(pszToken, curFileProp);
2251
2252 nTokenToSkip = 3;
2253 nCount = 0;
2254 do
2255 {
2256 pszToken = strtok( NULL, " \t" );
2257 nCount++;
2258 } while( nCount <= nTokenToSkip );
2259
2260 /* Store the size of the file in the param list. */
2261 if (pszToken != NULL)
2262 curFileProp->nSize = atol(pszToken);
2263
2264 /* Parse last modified time. */
2265 nSeconds = 0;
2266 nMinutes = 0;
2267 nHour = 0;
2268 nDay = 0;
2269 nMonth = 0;
2270 nYear = 0;
2271
2272 pszToken = strtok( NULL, " \t" );
2273 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2274 strupr(pszMonth);
2275 pszMatch = strstr(szMonths, pszMonth);
2276 if( pszMatch != NULL )
2277 nMonth = (pszMatch - szMonths) / 3;
2278
2279 pszToken = strtok(NULL, " \t");
2280 if (pszToken != NULL)
2281 nDay = atoi(pszToken);
2282
2283 pszToken = strtok(NULL, " \t");
2284 pszMinutes = strchr(pszToken, ':');
2285 if( pszMinutes != NULL )
2286 {
2287 pszMinutes++;
2288 nMinutes = atoi(pszMinutes);
2289 pszHour = pszMinutes - 3;
2290 if (pszHour != NULL)
2291 nHour = atoi(pszHour);
2292 time(&aTime);
2293 apTM = localtime( &aTime );
2294 nYear = apTM->tm_year;
2295 }
2296 else
2297 {
2298 nYear = atoi(pszToken);
2299 nYear -= 1900;
2300 nHour = 12;
2301 }
2302
2303 curFileProp->tmLastModified.tm_sec = nSeconds;
2304 curFileProp->tmLastModified.tm_min = nMinutes;
2305 curFileProp->tmLastModified.tm_hour = nHour;
2306 curFileProp->tmLastModified.tm_mday = nDay;
2307 curFileProp->tmLastModified.tm_mon = nMonth;
2308 curFileProp->tmLastModified.tm_year = nYear;
2309
2310 pszToken = strtok(NULL, " \t");
2311 if(pszToken != NULL)
2312 {
2313 curFileProp->lpszName = strdup(pszToken);
2314 TRACE(": %s\n", curFileProp->lpszName);
2315 }
2316
2317 nBufLen = MAX_REPLY_LEN;
2318 indexFilePropArray++;
2319 }
2320
2321 if (bSuccess && indexFilePropArray)
2322 {
2323 if (indexFilePropArray < sizeFilePropArray - 1)
2324 {
2325 LPFILEPROPERTIESA tmpafp;
2326
2327 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2328 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2329 if (NULL == tmpafp)
2330 *lpafp = tmpafp;
2331 }
2332 *dwfp = indexFilePropArray;
2333 }
2334 else
2335 {
2336 HeapFree(GetProcessHeap(), 0, *lpafp);
2337 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2338 bSuccess = FALSE;
2339 }
2340
2341lend:
2342 return bSuccess;
2343}
2344
2345
2346/***********************************************************************
2347 * FTP_ParsePermission (internal)
2348 *
2349 * Parse permission string of directory information
2350 *
2351 * RETURNS
2352 * TRUE on success
2353 * FALSE on failure
2354 *
2355 */
2356BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2357{
2358 BOOL bSuccess = TRUE;
2359 unsigned short nPermission = 0;
2360 int nPos = 1;
2361 int nLast = 9;
2362
2363 TRACE("\n");
2364 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2365 {
2366 bSuccess = FALSE;
2367 return bSuccess;
2368 }
2369
2370 lpfp->bIsDirectory = (*lpszPermission == 'd');
2371 do
2372 {
2373 switch (nPos)
2374 {
2375 case 1:
2376 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2377 break;
2378 case 2:
2379 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2380 break;
2381 case 3:
2382 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2383 break;
2384 case 4:
2385 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2386 break;
2387 case 5:
2388 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2389 break;
2390 case 6:
2391 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2392 break;
2393 case 7:
2394 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2395 break;
2396 case 8:
2397 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2398 break;
2399 case 9:
2400 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2401 break;
2402 }
2403 nPos++;
2404 }while (nPos <= nLast);
2405
2406 lpfp->permissions = nPermission;
2407 return bSuccess;
2408}
2409
2410/***********************************************************************
2411 * FTP_SetResponseError (internal)
2412 *
2413 * Set the appropriate error code for a given response from the server
2414 *
2415 * RETURNS
2416 *
2417 */
2418DWORD FTP_SetResponseError(DWORD dwResponse)
2419{
2420 DWORD dwCode = 0;
2421
2422 switch(dwResponse)
2423 {
2424 case 421: /* Service not available - Server may be shutting down.*/
2425 dwCode = ERROR_INTERNET_TIMEOUT;
2426 break;
2427
2428 case 425: /* Cannot open data connection.*/
2429 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2430 break;
2431
2432 case 426: /* Connection closed, transer aborted.*/
2433 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2434 break;
2435
2436 case 500: /* Syntax error. Command unrecognized.*/
2437 case 501: /* Syntax error. Error in parameters or arguments.*/
2438 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2439 break;
2440
2441 case 530: /* Not logged in. Login incorrect.*/
2442 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2443 break;
2444
2445 case 550: /* File action not taken. File not found or no access.*/
2446 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2447 break;
2448
2449 case 450: /* File action not taken. File may be busy.*/
2450 case 451: /* Action aborted. Server error.*/
2451 case 452:/* Action not taken. Insufficient storage space on server.*/
2452 case 502: /* Command not implemented.*/
2453 case 503: /* Bad sequence of command.*/
2454 case 504: /* Command not implemented for that parameter.*/
2455 case 532: /* Need account for storing files*/
2456 case 551: /* Requested action aborted. Page type unknown*/
2457 case 552: /* Action aborted. Exceeded storage allocation*/
2458 case 553: /* Action not taken. File name not allowed.*/
2459
2460 default:
2461 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2462 break;
2463 }
2464
2465 INTERNET_SetLastError(dwCode);
2466 return dwCode;
2467}
Note: See TracBrowser for help on using the repository browser.