Annotation of libwww/Library/src/HTFTPDir.c, revision 2.9
2.1 frystyk 1: /* HTFTPDir.c
2: ** FILE TRANSFER PROTOCOL (FTP) DIRECTORY LISTINGS
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
6: **
7: ** Authors
8: ** HF Henrik Frystyk <frystyk@w3.org>
9: **
10: ** History:
11: ** Sep 95 Spawned off from HTFTP.c and made a stream
12: **
13: */
14:
15: /* Library include files */
16: #include "tcp.h"
17: #include "HTUtils.h"
18: #include "HTString.h"
19: #include "HTParse.h"
20: #include "HTSocket.h"
21: #include "HTStream.h"
2.7 frystyk 22: #include "HTFWrite.h"
2.6 frystyk 23: #include "HTWWWStr.h"
2.1 frystyk 24: #include "HTDir.h"
25: #include "HTIcons.h"
26: #include "HTFTPDir.h" /* Implemented here */
27:
28: struct _HTStream {
29: CONST HTStreamClass * isa;
30: HTRequest * request;
31: FTPServerType server;
32: HTSocketEOL state;
33: HTDir * dir;
34: BOOL first;
35: BOOL junk;
36: char buffer[MAX_FTP_LINE+1];
37: int buflen;
38: };
39:
40: PRIVATE HTDirShow dir_show = HT_DS_SIZE+HT_DS_DATE+HT_DS_DES+HT_DS_ICON;
41: PRIVATE HTDirKey dir_key = HT_DK_CINS;
42:
43: /* ------------------------------------------------------------------------- */
44:
45: /* ParseUnix
46: ** ---------
47: ** Extract the name, size, and date from an 'ls'. The function expects
48: ** the following format of the ls-line:
49: **
50: ** <permission> <nlink> <owner> [<group>] <size> <date> <filename>
51: **
52: ** Returns YES if OK, NO on error
53: */
54: PRIVATE BOOL ParseUnix (HTDir *dir, char * line)
55: {
56: int cnt;
57: char *ptr = line;
58: char *column = NULL;
59: char *date = NULL;
60: char sizestr[10];
61: HTFileMode mode = (*line == 'd') ? HT_IS_DIR : HT_IS_FILE;
62:
63: /* Spool past permission, link, and owner */
64: for (cnt=0; cnt<4; cnt++) {
65: if ((column = HTNextField(&ptr)) == NULL) break;
66: }
67:
68: /*
69: ** This field can either be group or size. We find out by looking at the
70: ** next field. If this is a non-digit then this field is the size.
71: */
72: while (*ptr && WHITE(*ptr)) ptr++;
73: if (isdigit(*ptr)) {
74: column = HTNextField(&ptr);
75: while (*ptr && WHITE(*ptr)) ptr++;
76: }
77:
78: if (mode == HT_IS_FILE) {
79: long ls = atol(column);
80: HTNumToStr(ls, sizestr, 10);
81: } else
82: strcpy(sizestr, "-");
83:
84: /* Find date field */
85: date = ptr;
86: ptr += 12;
87: *ptr++ = '\0';
88: date = HTStrip(date);
89:
90: /* Take the reminder as the filename */
91: while (*ptr && WHITE(*ptr)) ptr++;
92: if ((column = strstr(ptr, " -> ")))
93: *column = '\0'; /* Strip any '->' */
94:
95: /* Add the element with what we've got */
96: return HTDir_addElement(dir, ptr, date, sizestr, mode);
97: }
98:
99:
100: /* ParseVMS
101: ** --------
102: ** Parse the VMS line and send it to the directory module
103: ** Returns YES if OK, NO on error
104: */
105: PRIVATE BOOL ParseVMS (HTDir *dir, char * line)
106: {
107: char *ptr = NULL;
108: char *date = NULL;
109: char *size = NULL;
110: char sizestr[10];
111: HTFileMode mode;
112:
113: /* Valid lines have the semi-colon version number token */
114: if ((ptr = strchr(line, ';')) == NULL)
115: return YES;
116: *ptr++ ='\0';
117: if (HTNextField(&ptr) == NULL) return YES;
118:
119: /* Cast VMS file and directory names to lowercase except .Z and _Z */
120: {
121: char *lp = line;
122: while (*lp) {
123: if (strcmp(lp, ".Z")==0 || strcmp(lp, "_Z")==0) break;
124: *lp = TOLOWER(*lp);
125: lp++;
126: }
127: if ((lp = strstr(line, ".dir"))) { /* Strip any .dir */
128: mode = HT_IS_DIR;
129: *lp = '\0';
130: } else
131: mode = HT_IS_FILE;
132: }
133:
134: /* Find the size */
135: if ((size = HTNextField(&ptr))) {
136: if (mode == HT_IS_FILE) {
137: long ls = atol(size) * 512; /* Assume blocks */
138: HTNumToStr(ls, sizestr, 10);
139: } else
140: strcpy(sizestr, "-");
141: } else
142: *sizestr = '\0';
143:
144: /* Find the date */
145: {
146: char *end = strchr(ptr, '[');
147: if (end) *end = '\0';
148: date = HTStrip(ptr);
149: }
150: return HTDir_addElement(dir, line, date, sizestr, mode);
151: }
152:
153:
154: /* ParseFTPLine
155: ** -----------
156: ** Determines what to do with a line read from a FTP listing
157: ** Returns YES if OK, else NO
158: */
159: PRIVATE BOOL ParseFTPLine (HTStream *me)
160: {
161: if (!me->buflen) return YES; /* If empty line */
162: switch (me->server) {
163: case FTP_WINNT:
164: case FTP_UNIX:
165: case FTP_PETER_LEWIS:
166: case FTP_MACHTEN:
167: if (me->first) {
168: if (strncmp(me->buffer, "total ", 6) &&
169: !strstr(me->buffer, "not available"))
170: ParseUnix(me->dir, me->buffer);
171: me->first = NO;
172: } else
173: ParseUnix(me->dir, me->buffer);
174: break;
175:
176: case FTP_VMS:
177: /* Interpret and edit LIST output from VMS server */
178: /* and convert information lines to zero length. */
179: ParseVMS(me->dir, me->buffer);
180: break;
181:
182: case FTP_NCSA:
183: case FTP_TCPC:
184: /* Directories identified by trailing "/" characters */
185: {
186: HTFileMode mode = (*(me->buffer+me->buflen-1)=='/') ?
187: HT_IS_DIR : HT_IS_FILE;
188: return HTDir_addElement(me->dir, me->buffer, NULL, NULL, mode);
189: }
190: break;
191:
192: default:
193: return HTDir_addElement(me->dir, me->buffer, NULL, NULL, 0);
194: break;
195: }
196: return NO;
197: }
198:
199: /*
200: ** Searches for FTP line until buffer fills up or a CRLF or LF is found
201: */
2.3 frystyk 202: PRIVATE int FTPDir_put_block (HTStream * me, CONST char * b, int l)
2.1 frystyk 203: {
204: while (l-- > 0) {
205: if (me->state == EOL_FCR) {
206: if (*b == LF && me->buflen) {
207: if (!me->junk) {
208: *(me->buffer+me->buflen) = '\0';
209: ParseFTPLine(me);
210: } else
211: me->junk = NO; /* back to normal */
212: }
213: me->buflen = 0;
214: me->state = EOL_BEGIN;
215: } else if (*b == CR) {
216: me->state = EOL_FCR;
217: } else if (*b == LF && me->buflen) {
218: if (!me->junk) {
219: *(me->buffer+me->buflen) = '\0';
220: ParseFTPLine(me);
221: } else
222: me->junk = NO; /* back to normal */
223: me->buflen = 0;
224: me->state = EOL_BEGIN;
225: } else {
226: *(me->buffer+me->buflen++) = *b;
227: if (me->buflen >= MAX_FTP_LINE) {
228: if (PROT_TRACE)
2.4 frystyk 229: TTYPrint(TDEST, "FTP Dir..... Line too long - ignored\n");
2.1 frystyk 230: me->buflen = 0;
231: me->junk = YES;
232: }
233: }
234: b++;
235: }
236: return HT_OK;
237: }
238:
2.3 frystyk 239: PRIVATE int FTPDir_put_string (HTStream * me, CONST char * s)
2.1 frystyk 240: {
241: return FTPDir_put_block(me, s, (int) strlen(s));
242: }
243:
2.3 frystyk 244: PRIVATE int FTPDir_put_character (HTStream * me, char c)
2.1 frystyk 245: {
246: return FTPDir_put_block(me, &c, 1);
247: }
248:
2.3 frystyk 249: PRIVATE int FTPDir_flush (HTStream * me)
2.1 frystyk 250: {
251: return HT_OK;
252: }
253:
2.3 frystyk 254: PRIVATE int FTPDir_free (HTStream * me)
2.1 frystyk 255: {
256: HTDir_free(me->dir);
2.9 ! frystyk 257: HT_FREE(me);
2.1 frystyk 258: return HT_OK;
259: }
260:
2.5 frystyk 261: PRIVATE int FTPDir_abort (HTStream * me, HTList * e)
2.1 frystyk 262: {
2.4 frystyk 263: if (PROT_TRACE) TTYPrint(TDEST, "FTPDir...... ABORTING...\n");
2.1 frystyk 264: FTPDir_free(me);
265: return HT_ERROR;
266: }
267:
268: /* FTPDir Stream
269: ** -----------------
270: */
271: PRIVATE CONST HTStreamClass FTPDirClass =
272: {
273: "FTPDir",
274: FTPDir_flush,
275: FTPDir_free,
276: FTPDir_abort,
277: FTPDir_put_character,
278: FTPDir_put_string,
279: FTPDir_put_block
280: };
281:
282: PUBLIC HTStream * HTFTPDir_new (HTRequest * request,
283: FTPServerType server,
284: char list)
285: {
2.9 ! frystyk 286: HTStream * me;
! 287: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
! 288: HT_OUTOFMEM("HTFTPDir");
2.1 frystyk 289: me->isa = &FTPDirClass;
290: me->request = request;
291: me->server = server;
292: me->state = EOL_BEGIN;
293: me->dir = HTDir_new(request, (list=='L' ? dir_show : 0), dir_key);
294: me->first = YES;
2.7 frystyk 295: if (me->dir == NULL) {
2.9 ! frystyk 296: HT_FREE(me);
2.8 frystyk 297: return HTErrorStream();
2.7 frystyk 298: }
2.1 frystyk 299: return me;
300: }
Webmaster