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