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