Annotation of libwww/Library/src/HTFWrite.c, revision 2.22
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:
123:
124: /* HTThroughLine
125: ** -------------
2.1 frystyk 126: **
2.3 frystyk 127: ** This function is a dummy function that returns the same output stream
128: ** as given as a parameter. Henrik 01/03-94
2.1 frystyk 129: */
2.16 frystyk 130: PUBLIC HTStream* HTThroughLine (HTRequest * request,
131: void * param,
132: HTFormat input_format,
133: HTFormat output_format,
134: HTStream * output_stream)
2.3 frystyk 135: {
136: return output_stream;
137: }
2.1 frystyk 138:
2.3 frystyk 139: /* ------------------------------------------------------------------------- */
140: /* SOCKET WRITER STREAM */
141: /* ------------------------------------------------------------------------- */
142:
2.16 frystyk 143: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3 frystyk 144: {
145: return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
146: }
147:
2.16 frystyk 148: PRIVATE int HTFWriter_put_string (HTStream * me, CONST char* s)
2.3 frystyk 149: {
150: if (*s) /* For vms :-( 10/04-94 */
151: return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
152: return HT_OK;
153: }
154:
2.16 frystyk 155: PRIVATE int HTFWriter_flush (HTStream * me)
2.3 frystyk 156: {
2.7 frystyk 157: return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3 frystyk 158: }
159:
2.7 frystyk 160:
2.16 frystyk 161: PRIVATE int HTFWriter_write (HTStream * me, CONST char* s, int l)
2.3 frystyk 162: {
2.7 frystyk 163: int status ;
164: status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
165: if (l > 1 && status == HT_OK)
166: (void)HTFWriter_flush( me) ;
167: return status ;
168:
169: /* return (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK; */
170:
2.3 frystyk 171: }
2.7 frystyk 172:
2.3 frystyk 173:
2.16 frystyk 174: PRIVATE int HTFWriter_free (HTStream * me)
2.3 frystyk 175: {
176: if (me->leave_open != YES) fclose(me->fp);
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: {
2.22 ! frystyk 196: if (PROT_TRACE) TTYPrint(TDEST, "FileWriter.. ABORTING...\n");
2.3 frystyk 197: if (me->leave_open != YES) fclose(me->fp);
198: if (me->end_command) { /* Temp file */
2.14 frystyk 199: if (STREAM_TRACE)
2.17 frystyk 200: TTYPrint(TDEST,"FileWriter.. Aborting: file %s not executed.\n",
2.3 frystyk 201: me->filename ? me->filename : "???" );
202: free (me->end_command);
203: if (me->remove_on_close) {
2.9 frystyk 204: REMOVE(me->filename);
2.3 frystyk 205: }
206: }
207:
208: if (me->filename) free(me->filename);
209: free(me);
210: return HT_ERROR;
211: }
212:
213: PRIVATE CONST HTStreamClass HTFWriter = /* As opposed to print etc */
214: {
215: "FileWriter",
216: HTFWriter_flush,
217: HTFWriter_free,
218: HTFWriter_abort,
219: HTFWriter_put_character,
220: HTFWriter_put_string,
221: HTFWriter_write
222: };
223:
2.16 frystyk 224: PUBLIC HTStream* HTFWriter_new (FILE * fp, BOOL leave_open)
2.3 frystyk 225: {
226: HTStream* me;
227:
228: if (!fp) {
2.14 frystyk 229: if (STREAM_TRACE)
2.17 frystyk 230: TTYPrint(TDEST, "FileWriter.. Bad file descriptor\n");
2.3 frystyk 231: return NULL;
232: }
233: me = (HTStream*)calloc(sizeof(*me),1);
234: if (me == NULL) outofmem(__FILE__, "HTFWriter_new");
235: me->isa = &HTFWriter;
236:
237: me->fp = fp;
238: me->leave_open = leave_open; /* HENRIK 08/02-94 */
239: me->end_command = NULL;
240: me->remove_on_close = NO;
241: me->announce = NO;
242: me->callback = NULL;
243: return me;
244: }
245:
246: /* ------------------------------------------------------------------------- */
247: /* FILE WRITER ROUTINES */
248: /* ------------------------------------------------------------------------- */
249:
250: /* Set TMP Root
251: ** --------------
252: ** If `tmp_root' is NULL use the current value (might be a define)
253: */
2.16 frystyk 254: PUBLIC BOOL HTTmp_setRoot (CONST char * tmp_root)
2.3 frystyk 255: {
256: StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
257: if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
258: StrAllocCat(HTTmpRoot, "/");
2.14 frystyk 259: if (STREAM_TRACE)
2.17 frystyk 260: TTYPrint(TDEST, "Tmp Root.... Root set to `%s\'\n", HTTmpRoot);
2.3 frystyk 261: return YES;
262: }
263:
264:
265: /* Get Tmp Root
266: ** --------------
2.1 frystyk 267: */
2.16 frystyk 268: PUBLIC CONST char * HTTmp_getRoot (void)
2.3 frystyk 269: {
270: return HTTmpRoot;
271: }
2.1 frystyk 272:
273:
2.3 frystyk 274: /* Free Tmp Root
275: ** --------------
276: ** For clean up memory
277: */
2.16 frystyk 278: PUBLIC void HTTmp_freeRoot (void)
2.3 frystyk 279: {
280: FREE(HTTmpRoot);
281: }
2.1 frystyk 282:
2.4 frystyk 283: /*
284: ** This function tries really hard to find a non-existent filename relative
285: ** to the path given. Returns a string that must be freed by the caller or
286: ** NULL on error. The base must be '/' terminated which!
287: */
2.16 frystyk 288: PRIVATE char *get_filename (char * base, CONST char * url, CONST char * suffix)
2.4 frystyk 289: {
290: char *path=NULL;
291: char filename[40];
292: int hash=0;
293:
294: /* Do this until we find a name that doesn't exist */
295: while (1)
296: {
297: CONST char *ptr=url;
298: for( ; *ptr; ptr++)
299: hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
300:
301: #ifndef NO_GETPID
302: sprintf(filename, "%d-%d", hash, (int) getpid());
303: #else
304: sprintf(filename, "%d-%d", hash, time(NULL));
305: #endif
306: StrAllocCopy(path, base);
307: StrAllocCat(path, filename);
308: if (suffix) StrAllocCat(path, suffix);
309:
310: {
311: FILE *fp = fopen(path, "r");
312: if (fp) /* This file does already exist */
313: fclose(fp);
314: else
315: break; /* Got the file name */
316: }
317: }
318: return path;
319: }
320:
321:
2.1 frystyk 322: /* Take action using a system command
323: ** ----------------------------------
324: **
325: ** Creates temporary file, writes to it, executes system command
326: ** on end-document. The suffix of the temp file can be given
327: ** in case the application is fussy, or so that a generic opener can
328: ** be used.
329: */
2.16 frystyk 330: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
331: void * param,
332: HTFormat input_format,
333: HTFormat output_format,
334: HTStream * output_stream)
2.1 frystyk 335: {
336: char *fnam;
337: HTStream* me;
338:
2.19 frystyk 339: if (HTLib_secure()) {
2.21 frystyk 340: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
341: NULL, 0, "HTSaveAndExecute");
2.1 frystyk 342: return HTBlackHole();
343: }
344:
2.3 frystyk 345: if (!HTTmpRoot) {
2.17 frystyk 346: if (STREAM_TRACE) TTYPrint(TDEST, "Save and execute turned off");
2.1 frystyk 347: return HTBlackHole();
348: }
349:
2.4 frystyk 350: /* Let's find a hash name for this file */
351: {
2.13 frystyk 352: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
353: char *suffix = HTBind_getSuffix(anchor);
354: fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.5 frystyk 355: FREE(suffix);
2.4 frystyk 356: if (!fnam) {
2.21 frystyk 357: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
358: NULL, 0, "HTSaveAndExecute");
2.4 frystyk 359: return HTBlackHole();
360: }
361: }
362:
2.1 frystyk 363: me = (HTStream*)calloc(sizeof(*me), 1);
364: if (me == NULL) outofmem(__FILE__, "Save and execute");
365: me->isa = &HTFWriter;
366: me->request = request; /* won't be freed */
2.12 frystyk 367: me->fp = fopen (fnam, "wb");
2.1 frystyk 368: if (!me->fp) {
2.21 frystyk 369: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
370: NULL, 0, "HTSaveAndExecute");
2.1 frystyk 371: free(fnam);
372: free(me);
2.4 frystyk 373: return HTBlackHole();
2.1 frystyk 374: }
375: StrAllocCopy(me->filename, fnam);
376:
2.4 frystyk 377: /* Make command to process file */
2.1 frystyk 378: me->end_command = (char *) malloc ((strlen((char *) param) + 10 +
379: 3*strlen(fnam)) * sizeof (char));
380: if (me == NULL) outofmem(__FILE__, "SaveAndExecute");
381:
382: sprintf (me->end_command, (char *) param, fnam, fnam, fnam);
383: me->remove_on_close = NO;
384: me->announce = NO;
385: free (fnam);
386: return me;
387: }
388:
389:
390: /* Save Locally
391: ** ------------
392: **
393: ** Bugs:
394: ** GUI Apps should open local Save panel here really.
395: **
396: */
2.16 frystyk 397: PUBLIC HTStream* HTSaveLocally (HTRequest * request,
398: void * param,
399: HTFormat input_format,
400: HTFormat output_format,
401: HTStream * output_stream)
2.1 frystyk 402: {
403: char *fnam = NULL;
404: char *answer = NULL;
405: HTStream* me;
406:
2.19 frystyk 407: if (HTLib_secure()) {
2.21 frystyk 408: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
409: NULL, 0, "HTSaveLocally");
2.1 frystyk 410: return HTBlackHole();
411: }
412:
2.3 frystyk 413: if (!HTTmpRoot) {
2.17 frystyk 414: if (STREAM_TRACE) TTYPrint(TDEST, "Save locally turned off");
2.1 frystyk 415: return HTBlackHole();
416: }
417:
2.4 frystyk 418: /* Let's find a file name for this file */
419: {
2.21 frystyk 420: HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
2.13 frystyk 421: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
422: char *suffix = HTBind_getSuffix(anchor);
423: fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.21 frystyk 424: if (cbf) {
425: HTAlertPar * reply = HTAlert_newReply();
426: if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME, fnam,NULL,reply))
427: answer = HTAlert_replyMessage(reply);
428: HTAlert_deleteReply(reply);
429: }
430: FREE(suffix);
2.4 frystyk 431: if (!answer) {
432: FREE(fnam);
433: return HTBlackHole();
434: }
435: FREE(fnam);
436: }
437:
2.1 frystyk 438: me = (HTStream*)calloc(sizeof(*me),1);
439: if (me == NULL) outofmem(__FILE__, "SaveLocally");
440: me->isa = &HTFWriter;
441: me->announce = YES;
442:
2.12 frystyk 443: me->fp = fopen (answer, "wb");
2.1 frystyk 444: if (!me->fp) {
2.21 frystyk 445: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
446: NULL, 0, "HTSaveLocally");
2.1 frystyk 447: FREE(answer);
448: free(me);
2.4 frystyk 449: return HTBlackHole();
2.1 frystyk 450: }
451: me->callback = NULL;
2.21 frystyk 452: me->request = request;
453: me->filename = answer;
2.1 frystyk 454: return me;
455: }
456:
457:
458: /* Save and Call Back
459: ** ------------------
460: **
461: **
462: ** The special case is a kludge. Better is everything uses streams
463: ** and nothing uses files. Then this routine will go too. :-))
464: */
2.16 frystyk 465: PUBLIC HTStream* HTSaveAndCallback (HTRequest * request,
466: void * param,
467: HTFormat input_format,
468: HTFormat output_format,
469: HTStream * output_stream)
2.1 frystyk 470: {
471: HTStream * me;
2.10 frystyk 472: #if 0
2.1 frystyk 473: if (request->using_cache) { /* Special case! file wanted && cache hit */
474: (*request->callback)(request,
2.13 frystyk 475: ((HTCache*) request->using_cache)->filename);
2.3 frystyk 476: return HTBlackHole();
2.1 frystyk 477: } else {
478: me = HTCacheWriter(request, param,
479: input_format, output_format, output_stream);
480: if (me) {
481: me->callback = request->callback;
482: }
483: }
2.20 frystyk 484: return me;
485: #else
486: return HTBlackHole();
2.10 frystyk 487: #endif
2.1 frystyk 488: }
489:
Webmaster