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