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