Annotation of libwww/Library/src/HTFile.c, revision 1.132
1.72 frystyk 1: /* HTFile.c
2: ** FILE ACCESS
3: **
1.79 frystyk 4: ** (c) COPYRIGHT MIT 1995.
1.72 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.132 ! frystyk 6: ** @(#) $Id: HTFile.c,v 1.131 1996/08/19 18:30:32 frystyk Exp $
1.1 timbl 7: **
8: ** This is unix-specific code in general, with some VMS bits.
1.8 timbl 9: ** These are routines for file access used by browsers.
1.1 timbl 10: **
11: ** History:
12: ** Feb 91 Written Tim Berners-Lee CERN/CN
13: ** Apr 91 vms-vms access included using DECnet syntax
14: ** 26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
15: ** Fixed access bug for relative names on VMS.
1.28 duns 16: ** Sep 93 (MD) Access to VMS files allows sharing.
17: ** 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C
1.52 duns 18: ** 22 Feb 94 (MD) Excluded two routines if we are not READING directories
1.61 frystyk 19: ** 18 May 94 (HF) Directory stuff removed and stream handling updated,
20: ** error messages introduced etc.
1.120 frystyk 21: ** HFN Separated transport
1.1 timbl 22: **
23: ** Bugs:
1.2 timbl 24: ** FTP: Cannot access VMS files from a unix machine.
25: ** How can we know that the
1.1 timbl 26: ** target machine runs VMS?
27: */
28:
1.67 frystyk 29: /* Library Includes */
1.112 frystyk 30: #include "sysdep.h"
1.120 frystyk 31: #include "WWWUtil.h"
32: #include "WWWCore.h"
1.124 frystyk 33: #include "WWWDir.h"
34: #include "WWWTrans.h"
1.126 frystyk 35: #include "HTNetMan.h"
1.120 frystyk 36: #include "HTReqMan.h"
1.124 frystyk 37: #include "HTMulti.h"
1.67 frystyk 38: #include "HTFile.h" /* Implemented here */
39:
1.91 frystyk 40: /* Final states have negative value */
1.80 frystyk 41: typedef enum _FileState {
1.95 frystyk 42: FS_RETRY = -4,
43: FS_ERROR = -3,
44: FS_NO_DATA = -2,
45: FS_GOT_DATA = -1,
46: FS_BEGIN = 0,
47: FS_DO_CN,
48: FS_NEED_OPEN_FILE,
49: FS_NEED_BODY,
50: FS_PARSE_DIR,
51: FS_TRY_FTP
1.80 frystyk 52: } FileState;
53:
1.91 frystyk 54: /* This is the context structure for the this module */
1.77 frystyk 55: typedef struct _file_info {
1.80 frystyk 56: FileState state; /* Current state of the connection */
1.95 frystyk 57: char * local; /* Local representation of file name */
1.125 frystyk 58: struct stat stat_info; /* Contains actual file chosen */
1.77 frystyk 59: } file_info;
1.2 timbl 60:
1.80 frystyk 61: struct _HTStream {
1.112 frystyk 62: const HTStreamClass * isa;
1.80 frystyk 63: };
64:
1.120 frystyk 65: struct _HTInputStream {
66: const HTInputStreamClass * isa;
67: };
68:
1.123 frystyk 69: #if 0
1.95 frystyk 70: PRIVATE BOOL HTTakeBackup = YES;
1.123 frystyk 71: #endif
1.1 timbl 72:
1.95 frystyk 73: PRIVATE HTDirReadme dir_readme = HT_DIR_README_TOP;
74: PRIVATE HTDirAccess dir_access = HT_DIR_OK;
75: PRIVATE HTDirShow dir_show = HT_DS_SIZE+HT_DS_DATE+HT_DS_DES+HT_DS_ICON;
76: PRIVATE HTDirKey dir_key = HT_DK_CINS;
1.2 timbl 77:
1.61 frystyk 78: /* ------------------------------------------------------------------------- */
1.11 timbl 79:
1.95 frystyk 80: /* Directory Access
81: ** ----------------
82: */
83: PUBLIC BOOL HTFile_setDirAccess (HTDirAccess mode)
84: {
85: dir_access = mode;
86: return YES;
87: }
88:
89: PUBLIC HTDirAccess HTFile_dirAccess (void)
90: {
91: return dir_access;
92: }
93:
94: /* Directory Readme
95: ** ----------------
96: */
97: PUBLIC BOOL HTFile_setDirReadme (HTDirReadme mode)
98: {
99: dir_readme = mode;
100: return YES;
101: }
102:
103: PUBLIC HTDirReadme HTFile_dirReadme (void)
104: {
105: return dir_readme;
106: }
107:
108: /* HTFile_readDir
109: ** --------------
110: ** Reads the directory "path"
111: ** Returns:
112: ** HT_ERROR Error
1.107 frystyk 113: ** HT_FORBIDDEN Directory reading not allowed
1.95 frystyk 114: ** HT_LOADED Successfully read the directory
1.1 timbl 115: */
1.95 frystyk 116: PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
1.1 timbl 117: {
1.112 frystyk 118: #ifdef HAVE_READDIR
119: DIR * dp;
1.95 frystyk 120: struct stat file_info;
1.124 frystyk 121: HTParentAnchor * anchor = HTRequest_anchor(request);
122: char *url = HTAnchor_physical(anchor);
1.95 frystyk 123: char fullname[HT_MAX_PATH+1];
124: char *name;
1.111 eric 125: if (PROT_TRACE) HTTrace("Reading..... directory\n");
1.95 frystyk 126: if (dir_access == HT_DIR_FORBID) {
1.100 frystyk 127: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 128: NULL, 0, "HTFile_readDir");
1.107 frystyk 129: return HT_FORBIDDEN;
1.95 frystyk 130: }
131:
132: /* Initialize path name for stat() */
133: if (*(name = (url+strlen(url)-1)) != '/') {
134: char *newurl = NULL;
135: StrAllocCopy(newurl, url);
136: StrAllocCat(newurl, "/");
1.110 frystyk 137: HT_FREE(file->local);
1.123 frystyk 138: file->local = HTWWWToLocal(newurl, "", HTRequest_userProfile(request));
1.110 frystyk 139: HT_FREE(newurl);
1.95 frystyk 140: }
141: strcpy(fullname, file->local);
142: name = fullname+strlen(fullname); /* Point to end of fullname */
143:
144: /* Check if access is enabled */
145: if (dir_access == HT_DIR_SELECTIVE) {
146: strcpy(name, DEFAULT_DIR_FILE);
147: if (HT_STAT(fullname, &file_info)) {
1.80 frystyk 148: if (PROT_TRACE)
1.111 eric 149: HTTrace(
1.95 frystyk 150: "Read dir.... `%s\' not found\n", DEFAULT_DIR_FILE);
1.100 frystyk 151: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 152: NULL, 0, "HTFile_readDir");
1.107 frystyk 153: return HT_FORBIDDEN;
1.1 timbl 154: }
155: }
156:
1.95 frystyk 157: if ((dp = opendir(file->local))) {
1.112 frystyk 158: struct dirent * dirbuf;
1.95 frystyk 159: HTDir *dir = HTDir_new(request, dir_show, dir_key);
160: char datestr[20];
161: char sizestr[10];
162: HTFileMode mode;
163: #ifdef HT_REENTRANT
1.130 frystyk 164: struct dirent result; /* For readdir_r */
1.129 frystyk 165: while ((dirbuf = (struct dirent *) readdir_r(dp, &result)))
1.95 frystyk 166: #else
167: while ((dirbuf = readdir(dp)))
168: #endif /* HT_REENTRANT */
169: {
170: /* Current and parent directories are never shown in list */
1.112 frystyk 171: #ifdef HAVE_DIRENT_INO
1.95 frystyk 172: if (!dirbuf->d_ino ||
173: !strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
1.112 frystyk 174: #else
175: if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
176: #endif
1.95 frystyk 177: continue;
178:
179: /* Make a lstat on the file */
180: strcpy(name, dirbuf->d_name);
181: if (HT_LSTAT(fullname, &file_info)) {
182: if (PROT_TRACE)
1.111 eric 183: HTTrace("Read dir.... lstat failed: %s\n",fullname);
1.95 frystyk 184: continue;
185: }
1.1 timbl 186:
1.95 frystyk 187: /* Convert stat info to fit our setup */
1.103 frystyk 188: if (((mode_t) file_info.st_mode & S_IFMT) == S_IFDIR) {
1.95 frystyk 189: #ifdef VMS
190: char *dot = strstr(name, ".DIR"); /* strip .DIR part... */
191: if (dot) *dot = '\0';
192: #endif /* VMS */
193: mode = HT_IS_DIR;
194: if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
195: } else {
196: mode = HT_IS_FILE;
197: if (dir_show & HT_DS_SIZE)
198: HTNumToStr(file_info.st_size, sizestr, 10);
199: }
200: if (dir_show & HT_DS_DATE)
201: HTDateDirStr(&file_info.st_mtime, datestr, 20);
1.1 timbl 202:
1.95 frystyk 203: /* Add to the list */
204: if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
205: break;
206: }
207: closedir(dp);
208: HTDir_free(dir);
1.127 frystyk 209: return HT_LOADED;
210: } else {
1.100 frystyk 211: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "opendir");
1.127 frystyk 212: return HT_ERROR;
213: }
1.112 frystyk 214: #else
1.114 eric 215: return HT_ERROR; /* needed for WWW_MSWINDOWS */
1.112 frystyk 216: #endif /* HAVE_READDIR */
1.1 timbl 217: }
218:
219: /* Determine write access to a file
1.2 timbl 220: ** --------------------------------
1.80 frystyk 221: ** If stat_info is NULL then the function calls stat() on it's own,
222: ** otherwise it uses the information found in stat_info
1.2 timbl 223: ** On exit,
224: ** return value YES if file can be accessed and can be written to.
225: **
226: ** Bugs:
227: ** 1. No code for non-unix systems.
228: ** 2. Isn't there a quicker way?
1.1 timbl 229: */
1.112 frystyk 230: PRIVATE BOOL HTEditable (const char * filename, struct stat * stat_info)
1.80 frystyk 231: {
1.112 frystyk 232: #ifdef GETGROUPS_T
1.80 frystyk 233: int i;
234: uid_t myUid;
235: int ngroups; /* The number of groups */
1.1 timbl 236: struct stat fileStatus;
1.80 frystyk 237: struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.112 frystyk 238: GETGROUPS_T groups[NGROUPS];
1.80 frystyk 239: if (!stat_info) {
1.90 frystyk 240: if (HT_STAT(filename, &fileStatus))
1.80 frystyk 241: return NO; /* Can't even access file! */
242: }
1.1 timbl 243: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
244: myUid = geteuid(); /* Get my user identifier */
245:
1.95 frystyk 246: if (PROT_TRACE) {
1.1 timbl 247: int i;
1.111 eric 248: HTTrace(
1.19 timbl 249: "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.80 frystyk 250: (unsigned int) fileptr->st_mode, (int) fileptr->st_uid,
251: (int) fileptr->st_gid, (int) myUid, ngroups);
1.111 eric 252: for (i=0; i<ngroups; i++) HTTrace(" %d", (int) groups[i]);
253: HTTrace(")\n");
1.1 timbl 254: }
255:
1.80 frystyk 256: if (fileptr->st_mode & 0002) /* I can write anyway? */
1.1 timbl 257: return YES;
258:
1.80 frystyk 259: if ((fileptr->st_mode & 0200) /* I can write my own file? */
260: && (fileptr->st_uid == myUid))
1.1 timbl 261: return YES;
262:
1.80 frystyk 263: if (fileptr->st_mode & 0020) /* Group I am in can write? */
1.1 timbl 264: {
265: for (i=0; i<ngroups; i++) {
1.80 frystyk 266: if (groups[i] == fileptr->st_gid)
1.1 timbl 267: return YES;
268: }
269: }
1.111 eric 270: if (PROT_TRACE) HTTrace("\tFile is not editable.\n");
1.1 timbl 271: return NO; /* If no excuse, can't do */
1.80 frystyk 272: #else
273: /*
274: ** We don't know and can't find out. Can we be sure that when opening
275: ** a file in mode "a" that the file is not modified?
276: */
277: return NO;
1.112 frystyk 278: #endif /* GETGROUPS_T */
1.1 timbl 279: }
1.80 frystyk 280:
1.91 frystyk 281: /* FileCleanup
282: ** -----------
1.80 frystyk 283: ** This function closes the connection and frees memory.
1.91 frystyk 284: ** Returns YES on OK, else NO
1.80 frystyk 285: */
1.91 frystyk 286: PRIVATE int FileCleanup (HTRequest *req, int status)
1.80 frystyk 287: {
1.126 frystyk 288: HTNet * net = HTRequest_net(req);
289: file_info * file = (file_info *) HTNet_context(net);
290: HTStream * input = HTRequest_inputStream(req);
1.106 frystyk 291:
292: /* Free stream with data TO Local file system */
1.107 frystyk 293: if (HTRequest_isDestination(req))
294: HTRequest_removeDestination(req);
1.126 frystyk 295: else if (input) {
1.106 frystyk 296: if (status == HT_INTERRUPTED)
1.126 frystyk 297: (*input->isa->abort)(input, NULL);
1.106 frystyk 298: else
1.126 frystyk 299: (*input->isa->_free)(input);
300: HTRequest_setInputStream(req, NULL);
1.106 frystyk 301: }
302:
1.91 frystyk 303: if (file) {
1.110 frystyk 304: HT_FREE(file->local);
305: HT_FREE(file);
1.80 frystyk 306: }
1.128 frystyk 307: HTNet_delete(net, status);
1.91 frystyk 308: return YES;
1.80 frystyk 309: }
310:
311:
1.1 timbl 312: /* Load a document
313: ** ---------------
314: **
315: ** On entry,
1.80 frystyk 316: ** request This is the request structure
1.1 timbl 317: ** On exit,
1.91 frystyk 318: ** returns HT_ERROR Error has occured in call back
319: ** HT_OK Call back was OK
1.1 timbl 320: */
1.91 frystyk 321: PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request, SockOps ops)
1.1 timbl 322: {
1.80 frystyk 323: int status = HT_ERROR;
1.124 frystyk 324: HTNet * net = HTRequest_net(request);
325: HTParentAnchor * anchor = HTRequest_anchor(request);
1.80 frystyk 326: file_info *file; /* Specific access information */
1.45 luotonen 327:
1.91 frystyk 328: /*
329: ** Initiate a new file structure and bind to request structure
330: ** This is actually state FILE_BEGIN, but it can't be in the state
331: ** machine as we need the structure first.
332: */
333: if (ops == FD_NONE) {
1.111 eric 334: if (PROT_TRACE) HTTrace("HTLoadFile.. Looking for `%s\'\n",
1.99 frystyk 335: HTAnchor_physical(anchor));
1.110 frystyk 336: if ((file = (file_info *) HT_CALLOC(1, sizeof(file_info))) == NULL)
337: HT_OUTOFMEM("HTLoadFILE");
1.95 frystyk 338: file->state = FS_BEGIN;
1.91 frystyk 339: net->context = file;
340: } if (ops == FD_CLOSE) { /* Interrupted */
1.107 frystyk 341: HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
1.131 frystyk 342: NULL, 0, "HTLoadFile");
1.107 frystyk 343: FileCleanup(request, HT_INTERRUPTED);
1.91 frystyk 344: return HT_OK;
345: } else
346: file = (file_info *) net->context; /* Get existing copy */
1.36 luotonen 347:
1.80 frystyk 348: /* Now jump into the machine. We know the state from the previous run */
349: while (1) {
350: switch (file->state) {
1.95 frystyk 351: case FS_BEGIN:
1.102 frystyk 352: if (HTLib_secure()) {
1.80 frystyk 353: if (PROT_TRACE)
1.111 eric 354: HTTrace("LoadFile.... No access to local file system\n");
1.95 frystyk 355: file->state = FS_TRY_FTP;
1.80 frystyk 356: break;
357: }
1.123 frystyk 358: file->local = HTWWWToLocal(HTAnchor_physical(anchor), "",
359: HTRequest_userProfile(request));
1.95 frystyk 360: if (!file->local) {
361: file->state = FS_TRY_FTP;
1.80 frystyk 362: break;
1.2 timbl 363: }
1.125 frystyk 364: file->state = FS_DO_CN;
1.86 frystyk 365: break;
366:
1.95 frystyk 367: case FS_DO_CN:
1.80 frystyk 368: /*
369: ** If we have to do content negotiation then find the object that
370: ** fits best into either what the client has indicated in the
1.86 frystyk 371: ** accept headers or what the client has registered on its own.
1.80 frystyk 372: ** The object chosen can in fact be a directory! However, content
373: ** negotiation only makes sense it we can read the directory!
374: ** We stat the file in order to find the size and to see it if
375: ** exists.
376: */
1.132 ! frystyk 377: if (HTRequest_negotiation(request) &&
! 378: HTMethod_isSafe(HTRequest_method(request))) {
1.125 frystyk 379: char * conneg = HTMulti(request, file->local,&file->stat_info);
380: if (conneg) {
381: HT_FREE(file->local);
382: file->local = conneg;
383: HTAnchor_setPhysical(anchor, conneg);
384: if (PROT_TRACE)
385: HTTrace("Load File... Found `%s\'\n", conneg);
1.80 frystyk 386: } else {
1.125 frystyk 387: if (PROT_TRACE)
388: HTTrace("Load File... Not found - even tried content negotiation\n");
1.126 frystyk 389: HTRequest_addError(request, ERR_INFO, NO, HTERR_NOT_FOUND,
390: NULL, 0, "HTLoadFile");
1.125 frystyk 391: file->state = FS_ERROR;
392: break;
1.80 frystyk 393: }
1.125 frystyk 394: } else {
395: if (HT_STAT(file->local, &file->stat_info) == -1) {
396: if (PROT_TRACE)
397: HTTrace("Load.File... Not found `%s\'\n", file->local);
398: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
399: NULL, 0, "HTLoadFile");
400: file->state = FS_ERROR;
401: break;
1.80 frystyk 402: }
1.125 frystyk 403: }
404:
405: /*
406: ** Check to see if the 'localname' is in fact a directory
407: */
408: if (((file->stat_info.st_mode) & S_IFMT) == S_IFDIR) {
409: file->state = FS_PARSE_DIR;
410: break;
411: }
412:
413: /*
1.132 ! frystyk 414: ** If empty file then only serve it if it is editable. We also get
! 415: ** the bindings for the file suffixes in lack of better bindings
1.125 frystyk 416: */
417: {
418: BOOL editable = HTEditable(file->local, &file->stat_info);
419: HTBind_getBindings(anchor);
420: if (editable) HTAnchor_appendMethods(anchor, METHOD_PUT);
421: if (file->stat_info.st_size)
422: HTAnchor_setLength(anchor, file->stat_info.st_size);
423: if (!editable && !file->stat_info.st_size) {
424: HTRequest_addError(request, ERR_FATAL,NO,HTERR_NO_CONTENT,
425: NULL, 0, "HTLoadFile");
426: file->state = FS_NO_DATA;
427: } else
428: file->state = FS_NEED_OPEN_FILE;
1.2 timbl 429: }
1.80 frystyk 430: break;
1.61 frystyk 431:
1.95 frystyk 432: case FS_NEED_OPEN_FILE:
1.120 frystyk 433: status = HTFileOpen(net, file->local, HT_FT_RDONLY);
434: if (status == HT_OK) {
435: /*
436: ** Create the stream pipe FROM the channel to the application.
437: ** The target for the input stream pipe is set up using the
1.132 ! frystyk 438: ** stream stack.
1.120 frystyk 439: */
1.124 frystyk 440: HTNet_getInput(net,
441: HTStreamStack(HTAnchor_format(anchor),
442: HTRequest_outputFormat(request),
443: HTRequest_outputStream(request),
444: request, YES), NULL, 0);
1.126 frystyk 445: HTRequest_setOutputConnected(request, YES);
446:
1.120 frystyk 447: /*
448: ** Create the stream pipe TO the channel from the application
449: ** and hook it up to the request object
450: */
451: {
452: HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
453: HTRequest_setInputStream(request, (HTStream *) output);
454: }
1.80 frystyk 455:
1.120 frystyk 456: /*
457: ** Set up concurrent read/write if this request isn't the
458: ** source for a PUT or POST. As source we don't start reading
459: ** before all destinations are ready. If destination then
460: ** register the input stream and get ready for read
461: */
462: if (HTRequest_isDestination(request)) {
1.122 eric 463: HTEvent_register(net->sockfd, request, (SockOps) FD_READ,
1.120 frystyk 464: HTLoadFile, net->priority);
465: HTRequest_linkDestination(request);
1.82 frystyk 466: }
1.120 frystyk 467: if (HTRequest_isSource(request) &&
468: !HTRequest_destinationsReady(request))
469: return HT_OK;
1.126 frystyk 470: HTRequest_addError(request, ERR_INFO, NO, HTERR_OK,
471: NULL, 0, "HTLoadFile");
1.120 frystyk 472: file->state = FS_NEED_BODY;
1.106 frystyk 473:
1.116 frystyk 474: #ifndef NO_UNIX_IO
1.120 frystyk 475: /* If we are _not_ using preemptive mode and we are Unix fd's
476: ** then return here to get the same effect as when we are
477: ** connecting to a socket. That way, HTFile acts just like any
478: ** other protocol module even though we are in fact doing
479: ** blocking connect
480: */
481: if (!net->preemptive) {
482: if (PROT_TRACE) HTTrace("HTLoadFile.. returning\n");
1.122 eric 483: HTEvent_register(net->sockfd, request, (SockOps) FD_READ,
1.120 frystyk 484: net->cbf, net->priority);
1.132 ! frystyk 485: return HT_OK;
1.120 frystyk 486: }
1.116 frystyk 487: #endif
1.131 frystyk 488: } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
1.120 frystyk 489: return HT_OK;
1.126 frystyk 490: else {
491: HTRequest_addError(request, ERR_INFO, NO, HTERR_INTERNAL,
492: NULL, 0, "HTLoadFile");
1.120 frystyk 493: file->state = FS_ERROR; /* Error or interrupt */
1.126 frystyk 494: }
1.107 frystyk 495: break;
1.82 frystyk 496:
1.95 frystyk 497: case FS_NEED_BODY:
1.120 frystyk 498: status = (*net->input->isa->read)(net->input);
1.80 frystyk 499: if (status == HT_WOULD_BLOCK)
1.91 frystyk 500: return HT_OK;
1.108 frystyk 501: else if (status == HT_LOADED || status == HT_CLOSED) {
1.95 frystyk 502: file->state = FS_GOT_DATA;
1.126 frystyk 503: } else {
504: HTRequest_addError(request, ERR_INFO, NO, HTERR_FORBIDDEN,
505: NULL, 0, "HTLoadFile");
1.95 frystyk 506: file->state = FS_ERROR;
1.126 frystyk 507: }
1.80 frystyk 508: break;
1.1 timbl 509:
1.95 frystyk 510: case FS_PARSE_DIR:
511: status = HTFile_readDir(request, file);
512: if (status == HT_LOADED)
513: file->state = FS_GOT_DATA;
1.127 frystyk 514: else
1.95 frystyk 515: file->state = FS_ERROR;
1.80 frystyk 516: break;
517:
1.95 frystyk 518: case FS_TRY_FTP:
1.80 frystyk 519: {
1.99 frystyk 520: char *url = HTAnchor_physical(anchor);
1.80 frystyk 521: HTAnchor *anchor;
522: char *newname = NULL;
523: StrAllocCopy(newname, "ftp:");
524: if (!strncmp(url, "file:", 5))
525: StrAllocCat(newname, url+5);
526: else
527: StrAllocCat(newname, url);
528: anchor = HTAnchor_findAddress(newname);
1.109 frystyk 529: HTRequest_setAnchor(request, anchor);
1.110 frystyk 530: HT_FREE(newname);
1.91 frystyk 531: FileCleanup(request, HT_IGNORE);
1.97 frystyk 532: return HTLoad(request, YES);
1.80 frystyk 533: }
534: break;
1.1 timbl 535:
1.95 frystyk 536: case FS_GOT_DATA:
1.83 frystyk 537: if (HTRequest_isPostWeb(request)) {
1.87 frystyk 538: if (HTRequest_isDestination(request)) {
1.124 frystyk 539: HTRequest * source = HTRequest_source(request);
1.87 frystyk 540: HTLink *link =
1.126 frystyk 541: HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99 frystyk 542: (HTAnchor *) anchor);
1.104 frystyk 543: HTLink_setResult(link, HT_LINK_OK);
1.87 frystyk 544: }
1.107 frystyk 545: }
546: FileCleanup(request, HT_LOADED);
1.91 frystyk 547: return HT_OK;
1.80 frystyk 548: break;
549:
1.95 frystyk 550: case FS_NO_DATA:
1.83 frystyk 551: if (HTRequest_isPostWeb(request)) {
1.87 frystyk 552: if (HTRequest_isDestination(request)) {
1.124 frystyk 553: HTRequest * source = HTRequest_source(request);
1.87 frystyk 554: HTLink *link =
1.126 frystyk 555: HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99 frystyk 556: (HTAnchor *) anchor);
1.104 frystyk 557: HTLink_setResult(link, HT_LINK_OK);
1.87 frystyk 558: }
1.107 frystyk 559: }
560: FileCleanup(request, HT_NO_DATA);
1.91 frystyk 561: return HT_OK;
1.80 frystyk 562: break;
563:
1.95 frystyk 564: case FS_RETRY:
1.83 frystyk 565: if (HTRequest_isPostWeb(request)) {
1.87 frystyk 566: if (HTRequest_isDestination(request)) {
1.124 frystyk 567: HTRequest * source = HTRequest_source(request);
1.87 frystyk 568: HTLink *link =
1.126 frystyk 569: HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99 frystyk 570: (HTAnchor *) anchor);
1.104 frystyk 571: HTLink_setResult(link, HT_LINK_ERROR);
1.87 frystyk 572: }
1.107 frystyk 573: HTRequest_killPostWeb(request);
574: }
575: FileCleanup(request, HT_RETRY);
1.91 frystyk 576: return HT_OK;
1.80 frystyk 577: break;
578:
1.95 frystyk 579: case FS_ERROR:
1.83 frystyk 580: if (HTRequest_isPostWeb(request)) {
1.87 frystyk 581: if (HTRequest_isDestination(request)) {
1.124 frystyk 582: HTRequest * source = HTRequest_source(request);
1.87 frystyk 583: HTLink *link =
1.126 frystyk 584: HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99 frystyk 585: (HTAnchor *) anchor);
1.104 frystyk 586: HTLink_setResult(link, HT_LINK_ERROR);
1.87 frystyk 587: }
1.107 frystyk 588: HTRequest_killPostWeb(request);
589: }
590: FileCleanup(request, HT_ERROR);
1.91 frystyk 591: return HT_OK;
1.80 frystyk 592: break;
593: }
594: } /* End of while(1) */
1.1 timbl 595: }
Webmaster