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

Last change on this file since 3898 was 3898, checked in by bird, 25 years ago

Added the CVS Id keyword to the header.

File size: 38.0 KB
Line 
1/* $Id: ftp.c,v 1.2 2000-07-29 14:10:08 bird 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 MAX_REPLY_LEN 0x5B4
37#define DATA_PACKET_SIZE 0x2000
38#define szCRLF "\r\n"
39#define MAX_BACKLOG 5
40
41typedef enum {
42 /* FTP commands with arguments. */
43 FTP_CMD_ACCT,
44 FTP_CMD_CWD,
45 FTP_CMD_DELE,
46 FTP_CMD_MKD,
47 FTP_CMD_PASS,
48 FTP_CMD_PORT,
49 FTP_CMD_RETR,
50 FTP_CMD_RMD,
51 FTP_CMD_RNFR,
52 FTP_CMD_RNTO,
53 FTP_CMD_STOR,
54 FTP_CMD_TYPE,
55 FTP_CMD_USER,
56
57 /* FTP commands without arguments. */
58 FTP_CMD_ABOR,
59 FTP_CMD_LIST,
60 FTP_CMD_NLST,
61 FTP_CMD_PWD,
62 FTP_CMD_QUIT,
63} FTP_COMMAND;
64
65static const char *szFtpCommands[] = {
66 "ACCT",
67 "CWD",
68 "DELE",
69 "MKD",
70 "PASS",
71 "PORT",
72 "RETR",
73 "RMD",
74 "RNFR",
75 "RNTO",
76 "STOR",
77 "TYPE",
78 "USER",
79 "ABOR",
80 "LIST",
81 "NLST",
82 "PWD",
83 "QUIT",
84};
85
86static const char szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
87
88BOOL FTP_SendCommand(int nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam);
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);
93DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
94BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, int nDataSocket, DWORD nBytes, HANDLE hFile);
95BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
96BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
97BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
98BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
99BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
100BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
101BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
102BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, int nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
103HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, int nSocket, LPWIN32_FIND_DATAA lpFindFileData);
104LPSTR FTP_GetNextLine(int nSocket, LPSTR lpszBuffer, DWORD dwBuffer);
105
106/***********************************************************************
107 * FtpPutFileA (WININET.43)
108 *
109 * Uploads a file to the FTP server
110 *
111 * RETURNS
112 * TRUE on success
113 * FALSE on failure
114 *
115 */
116BOOLAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
117 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
118{
119 HANDLE hFile = (HANDLE)NULL;
120 BOOL bSuccess = FALSE;
121 DWORD nRC = ERROR_SUCCESS;
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 SetLastError(ERROR_INVALID_HANDLE);
129 nRC = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
130 goto lend;
131 }
132
133 /* Open file to be uploaded */
134 if (NULL == (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
135 {
136 SetLastError(ERROR_FILE_NOT_FOUND);
137 nRC = ERROR_FILE_NOT_FOUND;
138 goto lend;
139 }
140
141 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
142 if (hIC->lpfnStatusCB)
143 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
144
145 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
146 {
147 int nDataSocket;
148
149 /* Accept connection from ftp server */
150 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
151 {
152 FTP_SendData(lpwfs, nDataSocket, hFile);
153 bSuccess = TRUE;
154 close(nDataSocket);
155 }
156 }
157
158lend:
159 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
160 {
161 INTERNET_ASYNC_RESULT iar;
162
163 iar.dwResult = (DWORD)bSuccess;
164 iar.dwError = nRC;
165 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
166 &iar, sizeof(INTERNET_ASYNC_RESULT));
167 }
168
169 if (hFile)
170 CloseHandle(hFile);
171
172 return bSuccess;
173}
174
175
176/***********************************************************************
177 * FtpSetCurrentDirectoryA (WININET.49)
178 *
179 * Change the working directory on the FTP server
180 *
181 * RETURNS
182 * TRUE on success
183 * FALSE on failure
184 *
185 */
186BOOLAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
187{
188 int nResCode;
189 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
190 LPWININETAPPINFOA hIC = NULL;
191 DWORD nRC = ERROR_SUCCESS;
192 DWORD bSuccess = FALSE;
193
194 TRACE("lpszDirectory(%s)\n", lpszDirectory);
195
196 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
197 {
198 SetLastError(ERROR_INVALID_HANDLE);
199 nRC = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
200 return FALSE;
201 }
202
203 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory))
204 goto lend;
205
206 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
207 if (nResCode)
208 {
209 if (nResCode == 250)
210 bSuccess = TRUE;
211 else
212 ERR("Unable to set directory %s\n", lpszDirectory);
213 }
214
215lend:
216 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
217 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
218 {
219 INTERNET_ASYNC_RESULT iar;
220
221 iar.dwResult = (DWORD)bSuccess;
222 iar.dwError = nRC;
223 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
224 &iar, sizeof(INTERNET_ASYNC_RESULT));
225 }
226 return bSuccess;
227}
228
229
230/***********************************************************************
231 * FtpCreateDirectoryA (WININET.31)
232 *
233 * Create new directory on the FTP server
234 *
235 * RETURNS
236 * TRUE on success
237 * FALSE on failure
238 *
239 */
240BOOLAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
241{
242 int nResCode;
243 BOOL bSuccess = FALSE;
244 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
245
246 TRACE("\n");
247 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
248 {
249 SetLastError(ERROR_INVALID_HANDLE);
250 return FALSE;
251 }
252
253 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory))
254 goto lend;
255
256 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
257 if (nResCode)
258 {
259 if (nResCode == 257)
260 bSuccess = TRUE;
261 else
262 ERR("Unable to create directory: %s\n", lpszDirectory);
263 }
264lend:
265 return bSuccess;
266}
267
268
269/***********************************************************************
270 * FtpFindFirstFileA (WININET.35)
271 *
272 * Search the specified directory
273 *
274 * RETURNS
275 * HINTERNET on success
276 * NULL on failure
277 *
278 */
279INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
280 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
281{
282 int nResCode;
283 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
284 LPWININETFINDNEXTA hFindNext = NULL;
285
286 TRACE("\n");
287
288 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
289 {
290 SetLastError(ERROR_INVALID_HANDLE);
291 return FALSE;
292 }
293
294 if (!FTP_InitListenSocket(lpwfs))
295 goto lend;
296
297 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
298 goto lend;
299
300 if (!FTP_SendPort(lpwfs))
301 goto lend;
302
303 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile))
304 goto lend;
305
306 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
307 if (nResCode)
308 {
309 if (nResCode == 125 || nResCode == 150)
310 {
311 int nDataSocket;
312
313 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
314 {
315 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
316 if (nResCode == 226)
317 SetLastError(ERROR_NO_MORE_FILES);
318 else
319 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData);
320 close(nDataSocket);
321 }
322 }
323 else if (nResCode == 226)
324 {
325 /* Closing data connection, requested file action successful */
326 }
327 else
328 {
329 TRACE("Unable to retrieve directory listing\n");
330 }
331 }
332
333lend:
334 if (lpwfs->lstnSocket != INVALID_SOCKET)
335 close(lpwfs->lstnSocket);
336
337 return (HINTERNET)hFindNext;
338}
339
340
341/***********************************************************************
342 * FtpGetCurrentDirectoryA (WININET.37)
343 *
344 * Retrieves the current directory
345 *
346 * RETURNS
347 * TRUE on success
348 * FALSE on failure
349 *
350 */
351BOOLAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
352 LPDWORD lpdwCurrentDirectory)
353{
354 int nResCode;
355 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
356 LPWININETAPPINFOA hIC = NULL;
357 DWORD bSuccess = FALSE;
358
359 TRACE("\n");
360
361 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
362 {
363 SetLastError(ERROR_INVALID_HANDLE);
364 return FALSE;
365 }
366
367 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL))
368 goto lend;
369
370 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
371 if (nResCode)
372 {
373 if (nResCode == 257) /* Extract directory name */
374 {
375 int firstpos, lastpos, len;
376
377 for (firstpos = 0, lastpos = 0; lpwfs->lpszResponseBuffer[lastpos]; lastpos++)
378 {
379 if ('"' == lpwfs->lpszResponseBuffer[lastpos])
380 {
381 if (!firstpos)
382 firstpos = lastpos;
383 else
384 break;
385 }
386 }
387
388 len = lastpos - firstpos + 1;
389 strncpy(lpszCurrentDirectory, &lpwfs->lpszResponseBuffer[firstpos],
390 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
391 lpszCurrentDirectory[len] = '\0';
392 *lpdwCurrentDirectory = len;
393 bSuccess = TRUE;
394 }
395 else
396 ERR("Unable to get current directory\n");
397 }
398
399lend:
400 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
401 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
402 {
403 INTERNET_ASYNC_RESULT iar;
404
405 iar.dwResult = (DWORD)bSuccess;
406 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_SUCCESS;
407 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
408 &iar, sizeof(INTERNET_ASYNC_RESULT));
409
410 }
411
412 return (DWORD) bSuccess;
413}
414
415
416/***********************************************************************
417 * FtpOpenFileA (WININET.41)
418 *
419 * Open a remote file for writing or reading
420 *
421 * RETURNS
422 * HINTERNET handle on success
423 * NULL on failure
424 *
425 */
426INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
427 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
428 DWORD dwContext)
429{
430 int nDataSocket;
431 DWORD nSuccess = 0;
432 LPWININETFILE hFile = NULL;
433 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
434
435 TRACE("\n");
436 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
437 {
438 SetLastError(ERROR_INVALID_HANDLE);
439 return FALSE;
440 }
441
442 if (GENERIC_READ == fdwAccess)
443 {
444 /* Set up socket to retrieve data */
445 nSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
446 }
447 else if (GENERIC_WRITE == fdwAccess)
448 {
449 /* Set up socket to send data */
450 nSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
451 }
452
453 /* Accept connection from server */
454 if (nSuccess && FTP_InitDataSocket(lpwfs, &nDataSocket))
455 {
456 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
457 hFile->hdr.htype = WH_HFILE;
458 hFile->hdr.dwFlags = dwFlags;
459 hFile->hdr.dwContext = dwContext;
460 hFile->hdr.lpwhparent = hFtpSession;
461 hFile->nDataSocket = nDataSocket;
462 }
463
464 return (HINTERNET)hFile;
465}
466
467
468/***********************************************************************
469 * FtpGetFileA (WININET.39)
470 *
471 * Retrieve file from the FTP server
472 *
473 * RETURNS
474 * TRUE on success
475 * FALSE on failure
476 *
477 */
478BOOLAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
479 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
480 DWORD dwContext)
481{
482 DWORD nBytes;
483 BOOL bSuccess = FALSE;
484 HANDLE hFile;
485 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
486
487 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
488 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
489 {
490 SetLastError(ERROR_INVALID_HANDLE);
491 return FALSE;
492 }
493
494 /* Ensure we can write to lpszNewfile by opening it */
495 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
496 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
497 if (INVALID_HANDLE_VALUE == hFile)
498 return FALSE;
499
500 /* Set up socket to retrieve data */
501 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
502
503 if (nBytes > 0)
504 {
505 int nDataSocket;
506
507 /* Accept connection from ftp server */
508 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
509 {
510 int nResCode;
511
512 /* Receive data */
513 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
514 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
515 if (nResCode)
516 {
517 if (nResCode == 226)
518 bSuccess = TRUE;
519
520 }
521 close(nDataSocket);
522 }
523 }
524
525 if (hFile)
526 CloseHandle(hFile);
527 return bSuccess;
528}
529
530
531/***********************************************************************
532 * FTP_Connect (internal)
533 *
534 * Connect to a ftp server
535 *
536 * RETURNS
537 * HINTERNET a session handle on success
538 * NULL on failure
539 *
540 */
541
542HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
543 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
544 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
545{
546 struct sockaddr_in socketAddr;
547 struct hostent *phe = NULL;
548 int nsocket = INVALID_SOCKET;
549 LPWININETAPPINFOA hIC = NULL;
550 BOOL result, bSuccess = FALSE;
551 LPWININETFTPSESSIONA lpwfs = NULL;
552
553 TRACE(" Server(%s) Port(%d) User(%s)\n", lpszServerName, nServerPort,
554 lpszUserName);
555
556 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
557 goto lerror;
558
559 hIC = (LPWININETAPPINFOA) hInternet;
560
561 if (NULL == lpszUserName && NULL != lpszPassword)
562 goto lerror;
563
564 if (hIC->lpfnStatusCB)
565 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
566 lpszServerName, strlen(lpszServerName));
567
568 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
569 goto lerror;
570
571 if (hIC->lpfnStatusCB)
572 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
573 lpszServerName, strlen(lpszServerName));
574
575 if (INVALID_SOCKET == (nsocket = socket(phe->h_addrtype,SOCK_STREAM,0)))
576 {
577 ERR("Unable to create socket\n");
578 goto lerror;
579 }
580
581 result = connect(nsocket, (struct sockaddr *)&socketAddr,
582 sizeof(socketAddr));
583
584 if (!result)
585 {
586 TRACE("Connected to server\n");
587 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
588 if (NULL == lpwfs)
589 {
590 SetLastError(ERROR_OUTOFMEMORY);
591 goto lerror;
592 }
593
594 lpwfs->hdr.htype = WH_HFTPSESSION;
595 lpwfs->hdr.dwFlags = dwFlags;
596 lpwfs->hdr.dwContext = dwContext;
597 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
598 lpwfs->sndSocket = nsocket;
599 memcpy(&lpwfs->socketAddress, &socketAddr, sizeof(socketAddr));
600 lpwfs->phostent = phe;
601
602 if (NULL == lpszUserName)
603 {
604 lpwfs->lpszUserName = strdup("anonymous");
605 lpwfs->lpszPassword = strdup("user@server");
606 }
607 else
608 {
609 lpwfs->lpszUserName = strdup(lpszUserName);
610 lpwfs->lpszPassword = strdup(lpszPassword);
611 }
612
613 lpwfs->lpszResponseBuffer = HeapAlloc(GetProcessHeap(), 0, MAX_REPLY_LEN);
614 if (NULL == lpwfs)
615 {
616 SetLastError(ERROR_OUTOFMEMORY);
617 goto lerror;
618 }
619
620 if (hIC->lpfnStatusCB)
621 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
622 &lpwfs->socketAddress, sizeof(struct sockaddr_in));
623
624 if (FTP_ConnectToHost(lpwfs))
625 {
626 if (hIC->lpfnStatusCB)
627 {
628 INTERNET_ASYNC_RESULT iar;
629
630 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
631 &lpwfs->socketAddress, sizeof(struct sockaddr_in));
632
633 iar.dwResult = (DWORD)lpwfs;
634 iar.dwError = ERROR_SUCCESS;
635
636 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
637 &iar, sizeof(INTERNET_ASYNC_RESULT));
638 }
639 TRACE("Successfully logged into server\n");
640 bSuccess = TRUE;
641 }
642 }
643
644lerror:
645 if (!bSuccess && INVALID_SOCKET != nsocket)
646 close(nsocket);
647
648 if (!bSuccess && lpwfs)
649 {
650 HeapFree(GetProcessHeap(), 0, lpwfs);
651 lpwfs = NULL;
652 }
653
654 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
655 {
656 INTERNET_ASYNC_RESULT iar;
657
658 iar.dwResult = (DWORD)lpwfs;
659 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_CANNOT_CONNECT;
660 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
661 &iar, sizeof(INTERNET_ASYNC_RESULT));
662
663 }
664
665 return (HINTERNET) lpwfs;
666}
667
668
669/***********************************************************************
670 * FTP_ConnectHost (internal)
671 *
672 * Connect to a ftp server
673 *
674 * RETURNS
675 * TRUE on success
676 * NULL on failure
677 *
678 */
679BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
680{
681 int nResCode;
682 BOOL bSuccess = FALSE;
683
684 TRACE("\n");
685 FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
686
687 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName))
688 goto lend;
689
690 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
691 if (nResCode)
692 {
693 /* Login successful... */
694 if (nResCode == 230)
695 bSuccess = TRUE;
696 /* User name okay, need password... */
697 else if (nResCode == 331)
698 bSuccess = FTP_SendPassword(lpwfs);
699 /* Need account for login... */
700 else if (nResCode == 332)
701 bSuccess = FTP_SendAccount(lpwfs);
702 }
703
704 TRACE("Returning %d\n", bSuccess);
705lend:
706 return bSuccess;
707}
708
709
710/***********************************************************************
711 * FTP_SendCommand (internal)
712 *
713 * Send command to server
714 *
715 * RETURNS
716 * TRUE on success
717 * NULL on failure
718 *
719 */
720BOOL FTP_SendCommand(int nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam)
721{
722 int len;
723 char *buf;
724 int nBytesSent = 0;
725 int nRC = 0;
726 BOOL bParamHasLen;
727
728 TRACE("%d: (%s)\n", ftpCmd, lpszParam);
729
730 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
731 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
732 strlen(szCRLF)+ 1;
733 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
734 {
735 SetLastError(ERROR_OUTOFMEMORY);
736 return FALSE;
737 }
738 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
739 bParamHasLen ? lpszParam : "", szCRLF);
740
741 TRACE("Sending (%s)\n", buf);
742 while((nBytesSent < len) && (nRC != SOCKET_ERROR))
743 {
744 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
745 /* Here, we shall call the callback function to update the status. */
746 nBytesSent += nRC;
747 }
748
749 HeapFree(GetProcessHeap(), 0, buf);
750 return (nRC != SOCKET_ERROR);
751}
752
753
754/***********************************************************************
755 * FTP_ReceiveResponse (internal)
756 *
757 * Receive response from server
758 *
759 * RETURNS
760 * Reply code on success
761 * 0 on failure
762 *
763 */
764
765int FTP_ReceiveResponse(int nSocket, LPSTR lpszResponse, DWORD dwResponse)
766{
767 int nRecv = 0;
768 char resp[4];
769 int rc = 0;
770
771 TRACE("\n");
772 while(1)
773 {
774 while (nRecv < dwResponse)
775 {
776 if (recv(nSocket, &lpszResponse[nRecv], 1, 0) < 0)
777 goto lerror;
778
779 if (lpszResponse[nRecv] == '\n')
780 break;
781 if (lpszResponse[nRecv] != '\r')
782 nRecv++;
783 }
784
785 if (nRecv > 3 && lpszResponse[3] != '-')
786 break;
787
788 nRecv = 0;
789 }
790
791 if (nRecv > 0)
792 {
793 memset(lpszResponse+nRecv-1, 0, dwResponse-nRecv);
794 memcpy(resp, lpszResponse, 3*sizeof(char));
795 resp[3] = '\0';
796 rc = atoi(resp);
797 TRACE(" Reply(%d) bytes(%d) %s\n", rc, nRecv, lpszResponse);
798 }
799
800lerror:
801 return rc;
802}
803
804
805/***********************************************************************
806 * FTP_SendPassword (internal)
807 *
808 * Send password to ftp server
809 *
810 * RETURNS
811 * TRUE on success
812 * NULL on failure
813 *
814 */
815BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
816{
817 int nResCode;
818 BOOL bSuccess = FALSE;
819
820 TRACE("\n");
821 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword))
822 goto lend;
823
824 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
825 if (nResCode)
826 {
827 TRACE("Received reply code %d\n", nResCode);
828 /* Login successful... */
829 if (nResCode == 230)
830 bSuccess = TRUE;
831 /* Command not implemented, superfluous at the server site... */
832 /* Need account for login... */
833 else if (nResCode == 332)
834 bSuccess = FTP_SendAccount(lpwfs);
835 else
836 TRACE("Password failed\n");
837 }
838lend:
839 TRACE("Returning %d\n", bSuccess);
840 return bSuccess;
841}
842
843
844/***********************************************************************
845 * FTP_SendAccount (internal)
846 *
847 *
848 *
849 * RETURNS
850 * TRUE on success
851 * FALSE on failure
852 *
853 */
854BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
855{
856 int nResCode;
857 BOOL bSuccess = FALSE;
858
859 TRACE("\n");
860 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT))
861 goto lend;
862
863 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
864 if (nResCode)
865 {
866 bSuccess = TRUE;
867 }
868
869lend:
870 return bSuccess;
871}
872
873
874/***********************************************************************
875 * FTP_SendStore (internal)
876 *
877 * Send request to upload file to ftp server
878 *
879 * RETURNS
880 * TRUE on success
881 * FALSE on failure
882 *
883 */
884BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
885{
886 int nResCode;
887 BOOL bSuccess = FALSE;
888
889 TRACE("\n");
890 if (!FTP_InitListenSocket(lpwfs))
891 goto lend;
892
893 if (!FTP_SendType(lpwfs, dwType))
894 goto lend;
895
896 if (!FTP_SendPort(lpwfs))
897 goto lend;
898
899 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile))
900 goto lend;
901
902 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
903 if (nResCode)
904 {
905 if (nResCode == 150)
906 bSuccess = TRUE;
907 }
908
909lend:
910 if (!bSuccess && INVALID_SOCKET != lpwfs->lstnSocket)
911 {
912 close(lpwfs->lstnSocket);
913 lpwfs->lstnSocket = INVALID_SOCKET;
914 }
915
916 return bSuccess;
917}
918
919
920/***********************************************************************
921 * FTP_InitListenSocket (internal)
922 *
923 * Create a socket to listen for server response
924 *
925 * RETURNS
926 * TRUE on success
927 * FALSE on failure
928 *
929 */
930BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
931{
932 BOOL bSuccess = FALSE;
933 socklen_t namelen = sizeof(struct sockaddr_in);
934
935 TRACE("\n");
936
937 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
938 if (INVALID_SOCKET == lpwfs->lstnSocket)
939 {
940 TRACE("Unable to create listening socket\n");
941 goto lend;
942 }
943
944 lpwfs->lstnSocketAddress.sin_family = AF_INET;
945 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
946 lpwfs->lstnSocketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
947 if (SOCKET_ERROR == bind(lpwfs->lstnSocket,&lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)))
948 {
949 TRACE("Unable to bind socket: %d\n", errno);
950 goto lend;
951 }
952
953 if (SOCKET_ERROR == listen(lpwfs->lstnSocket, MAX_BACKLOG))
954 {
955 TRACE("listen failed\n");
956 goto lend;
957 }
958
959 if (SOCKET_ERROR != getsockname(lpwfs->lstnSocket, &lpwfs->lstnSocketAddress, &namelen))
960 bSuccess = TRUE;
961
962lend:
963 if (!bSuccess && INVALID_SOCKET == lpwfs->lstnSocket)
964 {
965 close(lpwfs->lstnSocket);
966 lpwfs->lstnSocket = INVALID_SOCKET;
967 }
968
969 return bSuccess;
970}
971
972
973/***********************************************************************
974 * FTP_SendType (internal)
975 *
976 * Tell server type of data being transfered
977 *
978 * RETURNS
979 * TRUE on success
980 * FALSE on failure
981 *
982 */
983BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
984{
985 int nResCode;
986 char type[2] = { "I\0" };
987 BOOL bSuccess = FALSE;
988
989 TRACE("\n");
990 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
991 *type = 'A';
992
993 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type))
994 goto lend;
995
996 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN)/100;
997 if (nResCode)
998 {
999 if (nResCode == 2)
1000 bSuccess = TRUE;
1001 else if (nResCode == 4)
1002 {
1003 /* Possible to restart */
1004 }
1005 else if (nResCode == 5)
1006 {
1007 /* Nothing can be done here */
1008 }
1009 }
1010
1011lend:
1012 return bSuccess;
1013}
1014
1015
1016/***********************************************************************
1017 * FTP_SendPort (internal)
1018 *
1019 * Tell server which port to use
1020 *
1021 * RETURNS
1022 * TRUE on success
1023 * FALSE on failure
1024 *
1025 */
1026BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1027{
1028 int nResCode;
1029 char szIPAddress[64];
1030 BOOL bSuccess = FALSE;
1031
1032 TRACE("\n");
1033
1034 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1035 lpwfs->socketAddress.sin_addr.s_addr&0x000000FF,
1036 (lpwfs->socketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1037 (lpwfs->socketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1038 (lpwfs->socketAddress.sin_addr.s_addr&0xFF000000)>>24,
1039 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1040 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1041
1042 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress))
1043 goto lend;
1044
1045 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
1046 if (nResCode)
1047 {
1048 if (nResCode == 200)
1049 bSuccess = TRUE;
1050 else
1051 {
1052 TRACE("SendPort failed\n");
1053 }
1054 }
1055
1056lend:
1057 return bSuccess;
1058}
1059
1060
1061/***********************************************************************
1062 * FTP_InitDataSocket (internal)
1063 *
1064 *
1065 *
1066 * RETURNS
1067 * TRUE on success
1068 * FALSE on failure
1069 *
1070 */
1071BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1072{
1073 struct sockaddr_in saddr;
1074 socklen_t addrlen = sizeof(struct sockaddr);
1075
1076 TRACE("\n");
1077 *nDataSocket = accept(lpwfs->lstnSocket, &saddr, &addrlen);
1078 close(lpwfs->lstnSocket);
1079 lpwfs->lstnSocket = INVALID_SOCKET;
1080
1081 return *nDataSocket != INVALID_SOCKET;
1082}
1083
1084
1085/***********************************************************************
1086 * FTP_SendData (internal)
1087 *
1088 * Send data to the server
1089 *
1090 * RETURNS
1091 * TRUE on success
1092 * FALSE on failure
1093 *
1094 */
1095BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, int nDataSocket, HANDLE hFile)
1096{
1097 BY_HANDLE_FILE_INFORMATION fi;
1098 DWORD nBytesRead = 0;
1099 DWORD nBytesSent = 0;
1100 DWORD nTotalSent = 0;
1101 DWORD nBytesToSend, nLen, nRC = 1;
1102 time_t s_long_time, e_long_time;
1103 long nSeconds;
1104 char *lpszBuffer;
1105
1106 TRACE("\n");
1107 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char)*DATA_PACKET_SIZE);
1108 memset(lpszBuffer, 0, sizeof(char)*DATA_PACKET_SIZE);
1109
1110 /* Get the size of the file. */
1111 GetFileInformationByHandle(hFile, &fi);
1112 time(&s_long_time);
1113
1114 do
1115 {
1116 nBytesToSend = nBytesRead - nBytesSent;
1117
1118 if (nBytesToSend <= 0)
1119 {
1120 /* Read data from file. */
1121 nBytesSent = 0;
1122 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
1123 ERR("Failed reading from file\n");
1124
1125 if (nBytesRead > 0)
1126 nBytesToSend = nBytesRead;
1127 else
1128 break;
1129 }
1130
1131 nLen = DATA_PACKET_SIZE < nBytesToSend ?
1132 DATA_PACKET_SIZE : nBytesToSend;
1133 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
1134
1135 if (nRC != SOCKET_ERROR)
1136 {
1137 nBytesSent += nRC;
1138 nTotalSent += nRC;
1139 }
1140
1141 /* Do some computation to display the status. */
1142 time(&e_long_time);
1143 nSeconds = e_long_time - s_long_time;
1144 if( nSeconds / 60 > 0 )
1145 {
1146/*
1147 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remainig time %d sec\t\t\r",
1148 nTotalSent, fi.nFileSizeLow, nTotalSent*100/st.st_size, nSeconds / 60,
1149 nSeconds % 60, (st.st_size - nTotalSent) * nSeconds / nTotalSent );
1150*/
1151 }
1152 else
1153 {
1154/*
1155 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remainig time %d sec\t\t\r",
1156 nTotalSent, fi.nFileSizeLow, nTotalSent*100/st.st_size, nSeconds,
1157 (st.st_size - nTotalSent) * nSeconds / nTotalSent);
1158*/
1159
1160 }
1161 } while (nRC != SOCKET_ERROR);
1162
1163 TRACE("file transfer complete!\n");
1164
1165 if(lpszBuffer != NULL)
1166 HeapFree(GetProcessHeap(), 0, lpszBuffer);
1167
1168 return nTotalSent;
1169}
1170
1171
1172/***********************************************************************
1173 * FTP_SendRetrieve (internal)
1174 *
1175 * Send request to retrieve a file
1176 *
1177 * RETURNS
1178 * Number of bytes to be received on success
1179 * 0 on failure
1180 *
1181 */
1182DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1183{
1184 int nResCode;
1185 DWORD nResult = 0;
1186
1187 TRACE("\n");
1188 if (!FTP_InitListenSocket(lpwfs))
1189 goto lend;
1190
1191 if (!FTP_SendType(lpwfs, dwType))
1192 goto lend;
1193
1194 if (!FTP_SendPort(lpwfs))
1195 goto lend;
1196
1197 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile))
1198 goto lend;
1199
1200 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
1201 if (nResCode)
1202 {
1203 if (nResCode == 125 || nResCode == 150)
1204 {
1205 /* Parse size of data to be retrieved */
1206 int i, sizepos = -1;
1207 for (i = strlen(lpwfs->lpszResponseBuffer) - 1; i >= 0; i--)
1208 {
1209 if ('(' == lpwfs->lpszResponseBuffer[i])
1210 {
1211 sizepos = i;
1212 break;
1213 }
1214 }
1215
1216 if (sizepos >= 0)
1217 {
1218 nResult = atol(&lpwfs->lpszResponseBuffer[sizepos+1]);
1219 TRACE("Waiting to receive %d bytes\n", nResult);
1220 }
1221 }
1222 }
1223
1224lend:
1225 if (0 == nResult && INVALID_SOCKET != lpwfs->lstnSocket)
1226 {
1227 close(lpwfs->lstnSocket);
1228 lpwfs->lstnSocket = INVALID_SOCKET;
1229 }
1230
1231 return nResult;
1232}
1233
1234
1235/***********************************************************************
1236 * FTP_RetrieveData (internal)
1237 *
1238 * Retrieve data from server
1239 *
1240 * RETURNS
1241 * TRUE on success
1242 * FALSE on failure
1243 *
1244 */
1245BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, int nDataSocket, DWORD nBytes, HANDLE hFile)
1246{
1247 DWORD nBytesWritten;
1248 DWORD nBytesReceived = 0;
1249 int nRC = 0;
1250 char *lpszBuffer;
1251
1252 TRACE("\n");
1253
1254 if (INVALID_HANDLE_VALUE == hFile)
1255 return FALSE;
1256
1257 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char)*DATA_PACKET_SIZE);
1258 if (NULL == lpszBuffer)
1259 {
1260 SetLastError(ERROR_OUTOFMEMORY);
1261 return FALSE;
1262 }
1263
1264 while (nBytesReceived < nBytes && nRC != SOCKET_ERROR)
1265 {
1266 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
1267 if (nRC != SOCKET_ERROR)
1268 {
1269 /* other side closed socket. */
1270 if (nRC == 0)
1271 goto recv_end;
1272 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
1273 nBytesReceived += nRC;
1274 }
1275
1276 TRACE("%d bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
1277 nBytesReceived * 100 / nBytes);
1278 }
1279
1280 TRACE("Data transfer complete\n");
1281 if (NULL != lpszBuffer)
1282 HeapFree(GetProcessHeap(), 0, lpszBuffer);
1283
1284recv_end:
1285 return (nRC != SOCKET_ERROR);
1286}
1287
1288
1289/***********************************************************************
1290 * FTP_CloseSessionHandle (internal)
1291 *
1292 * Deallocate session handle
1293 *
1294 * RETURNS
1295 * TRUE on success
1296 * FALSE on failure
1297 *
1298 */
1299BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
1300{
1301 if (INVALID_SOCKET != lpwfs->sndSocket)
1302 close(lpwfs->sndSocket);
1303
1304 if (INVALID_SOCKET != lpwfs->lstnSocket)
1305 close(lpwfs->lstnSocket);
1306
1307 if (lpwfs->lpszPassword)
1308 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
1309
1310 if (lpwfs->lpszUserName)
1311 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
1312
1313 if (lpwfs->lpszResponseBuffer)
1314 HeapFree(GetProcessHeap(), 0, lpwfs->lpszResponseBuffer);
1315
1316 HeapFree(GetProcessHeap(), 0, lpwfs);
1317
1318 return TRUE;
1319}
1320
1321
1322/***********************************************************************
1323 * FTP_CloseSessionHandle (internal)
1324 *
1325 * Deallocate session handle
1326 *
1327 * RETURNS
1328 * TRUE on success
1329 * FALSE on failure
1330 *
1331 */
1332BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
1333{
1334 int i;
1335
1336 for (i = 0; i < lpwfn->size; i++)
1337 {
1338 if (NULL != lpwfn->lpafp[i].lpszName)
1339 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
1340 }
1341
1342 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
1343 HeapFree(GetProcessHeap(), 0, lpwfn);
1344
1345 return TRUE;
1346}
1347
1348
1349/***********************************************************************
1350 * FTP_ReceiveFileList (internal)
1351 *
1352 * Read file list from server
1353 *
1354 * RETURNS
1355 * Handle to file list on success
1356 * NULL on failure
1357 *
1358 */
1359HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, int nSocket, LPWIN32_FIND_DATAA lpFindFileData)
1360{
1361 DWORD dwSize;
1362 LPFILEPROPERTIESA lpafp = NULL;
1363 LPWININETFINDNEXTA lpwfn = NULL;
1364
1365 TRACE("\n");
1366
1367 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
1368 {
1369 DWORD access = mktime(&lpafp->tmLastModified);
1370
1371 /* Not all fields are filled in */
1372 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
1373 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
1374 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
1375 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
1376 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
1377
1378 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
1379 if (NULL != lpwfn)
1380 {
1381 lpwfn->hdr.htype = WH_HFINDNEXT;
1382 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
1383 lpwfn->index = 1;
1384 lpwfn->size = dwSize;
1385 lpwfn->lpafp = lpafp;
1386 }
1387 }
1388
1389 return (HINTERNET)lpwfn;
1390}
1391
1392
1393/***********************************************************************
1394 * FTP_ParseDirectory (internal)
1395 *
1396 * Parse string of directory information
1397 *
1398 * RETURNS
1399 * TRUE on success
1400 * FALSE on failure
1401 *
1402 */
1403#define MAX_MONTH_LEN 10
1404
1405BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, int nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
1406{
1407 /*
1408 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
1409 *
1410 * For instance:
1411 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
1412 */
1413 char* pszMinutes;
1414 char* pszHour;
1415 time_t aTime;
1416 struct tm* apTM;
1417 char pszMonth[MAX_MONTH_LEN];
1418 char* pszMatch;
1419 BOOL bSuccess = TRUE;
1420 LPFILEPROPERTIESA curFileProp = NULL;
1421 char* pszLine = NULL;
1422 char* pszToken = NULL;
1423 int nTokenToSkip = 3;
1424 int nCount = 0;
1425 int nSeconds = 0;
1426 int nMinutes = 0;
1427 int nHour = 0;
1428 int nDay = 0;
1429 int nMonth = 0;
1430 int nYear = 0;
1431 int sizeFilePropArray = 20;
1432 int indexFilePropArray = 0;
1433
1434 TRACE("\n");
1435
1436 /* Skip over the first line */
1437 FTP_GetNextLine(nSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN);
1438
1439 /* Allocate intial file properties array */
1440 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
1441 if (NULL == lpafp)
1442 {
1443 bSuccess = FALSE;
1444 goto lend;
1445 }
1446
1447 while ((pszLine = FTP_GetNextLine(nSocket, lpwfs->lpszResponseBuffer, MAX_REPLY_LEN)) != NULL)
1448 {
1449 if (sizeFilePropArray < indexFilePropArray)
1450 {
1451 LPFILEPROPERTIESA tmpafp;
1452
1453 sizeFilePropArray *= 2;
1454 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
1455 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
1456 if (NULL == tmpafp)
1457 {
1458 bSuccess = FALSE;
1459 goto lend;
1460 }
1461
1462 *lpafp = tmpafp;
1463 }
1464
1465 curFileProp = &((*lpafp)[indexFilePropArray]);
1466
1467 /* First Parse the permissions. */
1468 pszToken = strtok(pszLine, " \t" );
1469 FTP_ParsePermission(pszToken, curFileProp);
1470
1471 nTokenToSkip = 3;
1472 nCount = 0;
1473 do
1474 {
1475 pszToken = strtok( NULL, " \t" );
1476 nCount++;
1477 } while( nCount <= nTokenToSkip );
1478
1479 /* Store the size of the file in the param list. */
1480 if (pszToken != NULL)
1481 curFileProp->nSize = atol(pszToken);
1482
1483 /* Parse last modified time. */
1484 nSeconds = 0;
1485 nMinutes = 0;
1486 nHour = 0;
1487 nDay = 0;
1488 nMonth = 0;
1489 nYear = 0;
1490
1491 pszToken = strtok( NULL, " \t" );
1492 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
1493 strupr(pszMonth);
1494 pszMatch = strstr(szMonths, pszMonth);
1495 if( pszMatch != NULL )
1496 nMonth = (pszMatch - szMonths) / 3;
1497
1498 pszToken = strtok(NULL, " \t");
1499 if (pszToken != NULL)
1500 nDay = atoi(pszToken);
1501
1502 pszToken = strtok(NULL, " \t");
1503 pszMinutes = strchr(pszToken, ':');
1504 if( pszMinutes != NULL )
1505 {
1506 pszMinutes++;
1507 nMinutes = atoi(pszMinutes);
1508 pszHour = pszMinutes - 3;
1509 if (pszHour != NULL)
1510 nHour = atoi(pszHour);
1511 time(&aTime);
1512 apTM = localtime( &aTime );
1513 nYear = apTM->tm_year;
1514 }
1515 else
1516 {
1517 nYear = atoi(pszToken);
1518 nYear -= 1900;
1519 nHour = 12;
1520 }
1521
1522 curFileProp->tmLastModified.tm_sec = nSeconds;
1523 curFileProp->tmLastModified.tm_min = nMinutes;
1524 curFileProp->tmLastModified.tm_hour = nHour;
1525 curFileProp->tmLastModified.tm_mday = nDay;
1526 curFileProp->tmLastModified.tm_mon = nMonth;
1527 curFileProp->tmLastModified.tm_year = nYear;
1528
1529 pszToken = strtok(NULL, " \t");
1530 if(pszToken != NULL)
1531 {
1532 curFileProp->lpszName = strdup(pszToken);
1533 TRACE(": %s\n", curFileProp->lpszName);
1534 }
1535
1536 indexFilePropArray++;
1537 }
1538
1539 if (bSuccess)
1540 {
1541 if (indexFilePropArray < sizeFilePropArray - 1)
1542 {
1543 LPFILEPROPERTIESA tmpafp;
1544
1545 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
1546 sizeof(FILEPROPERTIESA)*indexFilePropArray);
1547 if (NULL == tmpafp)
1548 *lpafp = tmpafp;
1549 }
1550 *dwfp = indexFilePropArray;
1551 }
1552 else
1553 {
1554 HeapFree(GetProcessHeap(), 0, *lpafp);
1555 }
1556
1557lend:
1558 return bSuccess;
1559}
1560
1561
1562/***********************************************************************
1563 * FTP_ParsePermission (internal)
1564 *
1565 * Parse permission string of directory information
1566 *
1567 * RETURNS
1568 * TRUE on success
1569 * FALSE on failure
1570 *
1571 */
1572BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
1573{
1574 BOOL bSuccess = TRUE;
1575 unsigned short nPermission = 0;
1576 int nPos = 1;
1577 int nLast = 9;
1578
1579 TRACE("\n");
1580 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
1581 {
1582 bSuccess = FALSE;
1583 return bSuccess;
1584 }
1585
1586 lpfp->bIsDirectory = (*lpszPermission == 'd');
1587 do
1588 {
1589 switch (nPos)
1590 {
1591 case 1:
1592 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
1593 break;
1594 case 2:
1595 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
1596 break;
1597 case 3:
1598 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
1599 break;
1600 case 4:
1601 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
1602 break;
1603 case 5:
1604 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
1605 break;
1606 case 6:
1607 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
1608 break;
1609 case 7:
1610 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
1611 break;
1612 case 8:
1613 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
1614 break;
1615 case 9:
1616 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
1617 break;
1618 }
1619 nPos++;
1620 }while (nPos <= nLast);
1621
1622 lpfp->permissions = nPermission;
1623 return bSuccess;
1624}
1625
1626
1627/***********************************************************************
1628 * FTP_GetNextLine (internal)
1629 *
1630 * Parse next line in directory string listing
1631 *
1632 * RETURNS
1633 * Pointer to begining of next line
1634 * NULL on failure
1635 *
1636 */
1637
1638LPSTR FTP_GetNextLine(int nSocket, LPSTR lpszBuffer, DWORD dwBuffer)
1639{
1640 BOOL bSuccess = FALSE;
1641 int nRecv = 0;
1642
1643 TRACE("\n");
1644 while (nRecv < dwBuffer)
1645 {
1646 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) < 0)
1647 goto lend;
1648 if (lpszBuffer[nRecv] == '\n')
1649 {
1650 bSuccess = TRUE;
1651 break;
1652 }
1653 if (lpszBuffer[nRecv] != '\r')
1654 nRecv++;
1655 }
1656
1657lend:
1658 if (bSuccess)
1659 {
1660 lpszBuffer[nRecv] = '\0';
1661 TRACE(": %s\n", lpszBuffer);
1662 return lpszBuffer;
1663 }
1664 else
1665 return NULL;
1666}
1667
Note: See TracBrowser for help on using the repository browser.