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

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