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