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