Annotation of libwww/Library/src/HTFWrite.c, revision 2.23
2.1 frystyk 1: /* HTFWrite.c
2: ** FILE WRITER
3: **
2.6 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.1 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
6: **
7: ** This version of the stream object just writes to a C file.
8: ** The file is assumed open and left open.
9: **
10: ** Bugs:
11: ** strings written must be less than buffer size.
12: **
13: ** History:
14: ** HFN: wrote it
15: ** HWL: converted the caching scheme to be hierachical by taking
16: ** AL code from Deamon
2.10 frystyk 17: ** HFN: moved cache code to HTCache module
2.1 frystyk 18: **
19: */
20:
21: /* Library include files */
22: #include "tcp.h"
23: #include "HTUtils.h"
24: #include "HTString.h"
25: #include "HTFormat.h"
2.21 frystyk 26: #include "HTError.h"
2.1 frystyk 27: #include "HTAlert.h"
2.19 frystyk 28: #include "HTAccess.h"
2.4 frystyk 29: #include "HTBind.h"
2.1 frystyk 30: #include "HTList.h"
2.3 frystyk 31: #include "HTParse.h"
2.15 frystyk 32: #include "HTReq.h"
2.3 frystyk 33: #include "HTFWrite.h" /* Implemented here */
2.1 frystyk 34:
2.4 frystyk 35: #define HASH_SIZE 1001 /* Tunable */
36:
2.13 frystyk 37: /* The default directory for "save locally" and "save and execute" files: */
38: #ifndef HT_TMP_ROOT
39: #define HT_TMP_ROOT "/tmp"
40: #endif
41:
2.3 frystyk 42: struct _HTStream {
43: CONST HTStreamClass * isa;
44:
45: FILE * fp;
46: BOOL leave_open; /* Close file? HFN 08/02-94 */
47: char * end_command;
48: BOOL remove_on_close;
49: BOOL announce;
50: char * filename;
51: HTRequest * request; /* saved for callback */
2.15 frystyk 52: HTRequestCallback *callback;
2.3 frystyk 53: };
2.1 frystyk 54:
2.3 frystyk 55: PRIVATE HTStream HTBlackHoleInstance; /* Made static */
56: PRIVATE char * HTTmpRoot = NULL; /* Dest for tmp files */
2.1 frystyk 57:
2.3 frystyk 58: /* ------------------------------------------------------------------------- */
59: /* BASIC STREAM CLASSES */
60: /* ------------------------------------------------------------------------- */
2.1 frystyk 61:
2.3 frystyk 62: /*
2.1 frystyk 63: **
2.3 frystyk 64: ** B L A C K H O L E C L A S S
2.1 frystyk 65: **
2.3 frystyk 66: ** There is only one black hole instance shared by anyone
67: ** who wants a black hole. These black holes don't radiate,
68: ** they just absorb data.
69: */
2.16 frystyk 70: PRIVATE int HTBlackHole_put_character (HTStream * me, char c)
2.3 frystyk 71: {
72: return HT_OK;
73: }
74:
2.16 frystyk 75: PRIVATE int HTBlackHole_put_string (HTStream * me, CONST char * s)
2.3 frystyk 76: {
77: return HT_OK;
78: }
79:
2.16 frystyk 80: PRIVATE int HTBlackHole_write (HTStream * me, CONST char * s, int l)
2.3 frystyk 81: {
82: return HT_OK;
83: }
84:
2.16 frystyk 85: PRIVATE int HTBlackHole_flush (HTStream * me)
2.3 frystyk 86: {
87: return HT_OK;
88: }
89:
2.16 frystyk 90: PRIVATE int HTBlackHole_free (HTStream * me)
2.3 frystyk 91: {
92: return HT_OK;
93: }
94:
2.18 frystyk 95: PRIVATE int HTBlackHole_abort (HTStream * me, HTList * e)
2.3 frystyk 96: {
97: return HT_ERROR;
98: }
99:
100:
101: /* Black Hole stream
102: ** -----------------
103: */
104: PRIVATE CONST HTStreamClass HTBlackHoleClass =
105: {
106: "BlackHole",
107: HTBlackHole_flush,
108: HTBlackHole_free,
109: HTBlackHole_abort,
110: HTBlackHole_put_character,
111: HTBlackHole_put_string,
112: HTBlackHole_write
113: };
114:
2.16 frystyk 115: PUBLIC HTStream * HTBlackHole (void)
2.3 frystyk 116: {
2.14 frystyk 117: if (STREAM_TRACE)
2.17 frystyk 118: TTYPrint(TDEST, "BlackHole... Created\n");
2.3 frystyk 119: HTBlackHoleInstance.isa = &HTBlackHoleClass; /* The rest is random */
120: return &HTBlackHoleInstance;
121: }
122:
2.23 ! frystyk 123: PUBLIC HTStream * HTBlackHoleConverter (HTRequest * request,
! 124: void * param,
! 125: HTFormat input_format,
! 126: HTFormat output_format,
! 127: HTStream * output_stream)
! 128: {
! 129: return HTBlackHole();
! 130: }
2.3 frystyk 131:
132: /* HTThroughLine
133: ** -------------
2.1 frystyk 134: **
2.3 frystyk 135: ** This function is a dummy function that returns the same output stream
136: ** as given as a parameter. Henrik 01/03-94
2.1 frystyk 137: */
2.16 frystyk 138: PUBLIC HTStream* HTThroughLine (HTRequest * request,
139: void * param,
140: HTFormat input_format,
141: HTFormat output_format,
142: HTStream * output_stream)
2.3 frystyk 143: {
144: return output_stream;
145: }
2.1 frystyk 146:
2.3 frystyk 147: /* ------------------------------------------------------------------------- */
148: /* SOCKET WRITER STREAM */
149: /* ------------------------------------------------------------------------- */
150:
2.16 frystyk 151: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3 frystyk 152: {
153: return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
154: }
155:
2.16 frystyk 156: PRIVATE int HTFWriter_put_string (HTStream * me, CONST char* s)
2.3 frystyk 157: {
158: if (*s) /* For vms :-( 10/04-94 */
159: return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
160: return HT_OK;
161: }
162:
2.16 frystyk 163: PRIVATE int HTFWriter_flush (HTStream * me)
2.3 frystyk 164: {
2.7 frystyk 165: return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3 frystyk 166: }
167:
2.7 frystyk 168:
2.16 frystyk 169: PRIVATE int HTFWriter_write (HTStream * me, CONST char* s, int l)
2.3 frystyk 170: {
2.7 frystyk 171: int status ;
172: status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
173: if (l > 1 && status == HT_OK)
174: (void)HTFWriter_flush( me) ;
175: return status ;
176:
177: /* return (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK; */
178:
2.3 frystyk 179: }
2.7 frystyk 180:
2.3 frystyk 181:
2.16 frystyk 182: PRIVATE int HTFWriter_free (HTStream * me)
2.3 frystyk 183: {
184: if (me->leave_open != YES) fclose(me->fp);
185: if (me->end_command) { /* Temp file */
2.17 frystyk 186: #ifdef GOT_SYSTEM
2.3 frystyk 187: system(me->end_command); /* @@ Beware of security hole */
2.17 frystyk 188: #endif
2.3 frystyk 189: free (me->end_command);
190: if (me->remove_on_close) {
2.9 frystyk 191: REMOVE(me->filename);
2.3 frystyk 192: }
193: }
194: if (me->callback) {
195: (*me->callback)(me->request, me->filename);
196: }
197: if (me->filename) free(me->filename);
198: free(me);
199: return HT_OK;
200: }
201:
2.18 frystyk 202: PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
2.3 frystyk 203: {
2.22 frystyk 204: if (PROT_TRACE) TTYPrint(TDEST, "FileWriter.. ABORTING...\n");
2.3 frystyk 205: if (me->leave_open != YES) fclose(me->fp);
206: if (me->end_command) { /* Temp file */
2.14 frystyk 207: if (STREAM_TRACE)
2.17 frystyk 208: TTYPrint(TDEST,"FileWriter.. Aborting: file %s not executed.\n",
2.3 frystyk 209: me->filename ? me->filename : "???" );
210: free (me->end_command);
211: if (me->remove_on_close) {
2.9 frystyk 212: REMOVE(me->filename);
2.3 frystyk 213: }
214: }
215:
216: if (me->filename) free(me->filename);
217: free(me);
218: return HT_ERROR;
219: }
220:
221: PRIVATE CONST HTStreamClass HTFWriter = /* As opposed to print etc */
222: {
223: "FileWriter",
224: HTFWriter_flush,
225: HTFWriter_free,
226: HTFWriter_abort,
227: HTFWriter_put_character,
228: HTFWriter_put_string,
229: HTFWriter_write
230: };
231:
2.16 frystyk 232: PUBLIC HTStream* HTFWriter_new (FILE * fp, BOOL leave_open)
2.3 frystyk 233: {
234: HTStream* me;
235:
236: if (!fp) {
2.14 frystyk 237: if (STREAM_TRACE)
2.17 frystyk 238: TTYPrint(TDEST, "FileWriter.. Bad file descriptor\n");
2.3 frystyk 239: return NULL;
240: }
241: me = (HTStream*)calloc(sizeof(*me),1);
242: if (me == NULL) outofmem(__FILE__, "HTFWriter_new");
243: me->isa = &HTFWriter;
244:
245: me->fp = fp;
246: me->leave_open = leave_open; /* HENRIK 08/02-94 */
247: me->end_command = NULL;
248: me->remove_on_close = NO;
249: me->announce = NO;
250: me->callback = NULL;
251: return me;
252: }
253:
254: /* ------------------------------------------------------------------------- */
255: /* FILE WRITER ROUTINES */
256: /* ------------------------------------------------------------------------- */
257:
258: /* Set TMP Root
259: ** --------------
260: ** If `tmp_root' is NULL use the current value (might be a define)
261: */
2.16 frystyk 262: PUBLIC BOOL HTTmp_setRoot (CONST char * tmp_root)
2.3 frystyk 263: {
264: StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
265: if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
266: StrAllocCat(HTTmpRoot, "/");
2.14 frystyk 267: if (STREAM_TRACE)
2.17 frystyk 268: TTYPrint(TDEST, "Tmp Root.... Root set to `%s\'\n", HTTmpRoot);
2.3 frystyk 269: return YES;
270: }
271:
272:
273: /* Get Tmp Root
274: ** --------------
2.1 frystyk 275: */
2.16 frystyk 276: PUBLIC CONST char * HTTmp_getRoot (void)
2.3 frystyk 277: {
278: return HTTmpRoot;
279: }
2.1 frystyk 280:
281:
2.3 frystyk 282: /* Free Tmp Root
283: ** --------------
284: ** For clean up memory
285: */
2.16 frystyk 286: PUBLIC void HTTmp_freeRoot (void)
2.3 frystyk 287: {
288: FREE(HTTmpRoot);
289: }
2.1 frystyk 290:
2.4 frystyk 291: /*
292: ** This function tries really hard to find a non-existent filename relative
293: ** to the path given. Returns a string that must be freed by the caller or
294: ** NULL on error. The base must be '/' terminated which!
295: */
2.16 frystyk 296: PRIVATE char *get_filename (char * base, CONST char * url, CONST char * suffix)
2.4 frystyk 297: {
298: char *path=NULL;
299: char filename[40];
300: int hash=0;
301:
302: /* Do this until we find a name that doesn't exist */
303: while (1)
304: {
305: CONST char *ptr=url;
306: for( ; *ptr; ptr++)
307: hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
308:
309: #ifndef NO_GETPID
310: sprintf(filename, "%d-%d", hash, (int) getpid());
311: #else
312: sprintf(filename, "%d-%d", hash, time(NULL));
313: #endif
314: StrAllocCopy(path, base);
315: StrAllocCat(path, filename);
316: if (suffix) StrAllocCat(path, suffix);
317:
318: {
319: FILE *fp = fopen(path, "r");
320: if (fp) /* This file does already exist */
321: fclose(fp);
322: else
323: break; /* Got the file name */
324: }
325: }
326: return path;
327: }
328:
329:
2.1 frystyk 330: /* Take action using a system command
331: ** ----------------------------------
332: **
333: ** Creates temporary file, writes to it, executes system command
334: ** on end-document. The suffix of the temp file can be given
335: ** in case the application is fussy, or so that a generic opener can
336: ** be used.
337: */
2.16 frystyk 338: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
339: void * param,
340: HTFormat input_format,
341: HTFormat output_format,
342: HTStream * output_stream)
2.1 frystyk 343: {
344: char *fnam;
345: HTStream* me;
346:
2.19 frystyk 347: if (HTLib_secure()) {
2.21 frystyk 348: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
349: NULL, 0, "HTSaveAndExecute");
2.1 frystyk 350: return HTBlackHole();
351: }
352:
2.3 frystyk 353: if (!HTTmpRoot) {
2.17 frystyk 354: if (STREAM_TRACE) TTYPrint(TDEST, "Save and execute turned off");
2.1 frystyk 355: return HTBlackHole();
356: }
357:
2.4 frystyk 358: /* Let's find a hash name for this file */
359: {
2.13 frystyk 360: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
361: char *suffix = HTBind_getSuffix(anchor);
362: fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.5 frystyk 363: FREE(suffix);
2.4 frystyk 364: if (!fnam) {
2.21 frystyk 365: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
366: NULL, 0, "HTSaveAndExecute");
2.4 frystyk 367: return HTBlackHole();
368: }
369: }
370:
2.1 frystyk 371: me = (HTStream*)calloc(sizeof(*me), 1);
372: if (me == NULL) outofmem(__FILE__, "Save and execute");
373: me->isa = &HTFWriter;
374: me->request = request; /* won't be freed */
2.12 frystyk 375: me->fp = fopen (fnam, "wb");
2.1 frystyk 376: if (!me->fp) {
2.21 frystyk 377: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
378: NULL, 0, "HTSaveAndExecute");
2.1 frystyk 379: free(fnam);
380: free(me);
2.4 frystyk 381: return HTBlackHole();
2.1 frystyk 382: }
383: StrAllocCopy(me->filename, fnam);
384:
2.4 frystyk 385: /* Make command to process file */
2.1 frystyk 386: me->end_command = (char *) malloc ((strlen((char *) param) + 10 +
387: 3*strlen(fnam)) * sizeof (char));
388: if (me == NULL) outofmem(__FILE__, "SaveAndExecute");
389:
390: sprintf (me->end_command, (char *) param, fnam, fnam, fnam);
391: me->remove_on_close = NO;
392: me->announce = NO;
393: free (fnam);
394: return me;
395: }
396:
397:
398: /* Save Locally
399: ** ------------
400: **
401: ** Bugs:
402: ** GUI Apps should open local Save panel here really.
403: **
404: */
2.16 frystyk 405: PUBLIC HTStream* HTSaveLocally (HTRequest * request,
406: void * param,
407: HTFormat input_format,
408: HTFormat output_format,
409: HTStream * output_stream)
2.1 frystyk 410: {
411: char *fnam = NULL;
412: char *answer = NULL;
413: HTStream* me;
414:
2.19 frystyk 415: if (HTLib_secure()) {
2.21 frystyk 416: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
417: NULL, 0, "HTSaveLocally");
2.1 frystyk 418: return HTBlackHole();
419: }
420:
2.3 frystyk 421: if (!HTTmpRoot) {
2.17 frystyk 422: if (STREAM_TRACE) TTYPrint(TDEST, "Save locally turned off");
2.1 frystyk 423: return HTBlackHole();
424: }
425:
2.4 frystyk 426: /* Let's find a file name for this file */
427: {
2.21 frystyk 428: HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
2.13 frystyk 429: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
430: char *suffix = HTBind_getSuffix(anchor);
431: fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.21 frystyk 432: if (cbf) {
433: HTAlertPar * reply = HTAlert_newReply();
434: if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME, fnam,NULL,reply))
435: answer = HTAlert_replyMessage(reply);
436: HTAlert_deleteReply(reply);
437: }
438: FREE(suffix);
2.4 frystyk 439: if (!answer) {
440: FREE(fnam);
441: return HTBlackHole();
442: }
443: FREE(fnam);
444: }
445:
2.1 frystyk 446: me = (HTStream*)calloc(sizeof(*me),1);
447: if (me == NULL) outofmem(__FILE__, "SaveLocally");
448: me->isa = &HTFWriter;
449: me->announce = YES;
450:
2.12 frystyk 451: me->fp = fopen (answer, "wb");
2.1 frystyk 452: if (!me->fp) {
2.21 frystyk 453: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
454: NULL, 0, "HTSaveLocally");
2.1 frystyk 455: FREE(answer);
456: free(me);
2.4 frystyk 457: return HTBlackHole();
2.1 frystyk 458: }
459: me->callback = NULL;
2.21 frystyk 460: me->request = request;
461: me->filename = answer;
2.1 frystyk 462: return me;
463: }
464:
465:
466: /* Save and Call Back
467: ** ------------------
468: **
469: **
470: ** The special case is a kludge. Better is everything uses streams
471: ** and nothing uses files. Then this routine will go too. :-))
472: */
2.16 frystyk 473: PUBLIC HTStream* HTSaveAndCallback (HTRequest * request,
474: void * param,
475: HTFormat input_format,
476: HTFormat output_format,
477: HTStream * output_stream)
2.1 frystyk 478: {
479: HTStream * me;
2.10 frystyk 480: #if 0
2.1 frystyk 481: if (request->using_cache) { /* Special case! file wanted && cache hit */
482: (*request->callback)(request,
2.13 frystyk 483: ((HTCache*) request->using_cache)->filename);
2.3 frystyk 484: return HTBlackHole();
2.1 frystyk 485: } else {
486: me = HTCacheWriter(request, param,
487: input_format, output_format, output_stream);
488: if (me) {
489: me->callback = request->callback;
490: }
491: }
2.20 frystyk 492: return me;
493: #else
494: return HTBlackHole();
2.10 frystyk 495: #endif
2.1 frystyk 496: }
497:
Webmaster