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

Last change on this file since 2912 was 2624, checked in by sandervl, 26 years ago

Ported Corel wininet Wine version

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