Annotation of libwww/Library/src/HTFWrite.c, revision 2.35
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.
2.35 ! frystyk 6: ** @(#) $Id: HTFWrite.c,v 2.34 1996/06/08 01:52:07 frystyk Exp $
2.1 frystyk 7: **
8: ** This version of the stream object just writes to a C file.
9: ** The file is assumed open and left open.
10: **
11: ** Bugs:
12: ** strings written must be less than buffer size.
13: **
14: ** History:
15: ** HFN: wrote it
16: ** HWL: converted the caching scheme to be hierachical by taking
17: ** AL code from Deamon
2.10 frystyk 18: ** HFN: moved cache code to HTCache module
2.1 frystyk 19: **
20: */
21:
22: /* Library include files */
2.28 frystyk 23: #include "sysdep.h"
2.35 ! frystyk 24: #include "WWWUtil.h"
2.1 frystyk 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.35 ! frystyk 29: #include "HTLib.h"
2.4 frystyk 30: #include "HTBind.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.3 frystyk 37: struct _HTStream {
2.28 frystyk 38: const HTStreamClass *isa;
2.24 frystyk 39:
40: FILE * fp;
2.31 frystyk 41: BOOL leave_open; /* Close file when free? */
2.24 frystyk 42: char * end_command; /* Command to execute */
43: BOOL remove_on_close; /* Remove file? */
44: char * filename; /* Name of file */
45: HTRequest * request; /* saved for callback */
46: HTRequestCallback * callback;
2.3 frystyk 47: };
2.1 frystyk 48:
2.3 frystyk 49: /* ------------------------------------------------------------------------- */
2.1 frystyk 50:
2.16 frystyk 51: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3 frystyk 52: {
53: return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
54: }
55:
2.28 frystyk 56: PRIVATE int HTFWriter_put_string (HTStream * me, const char* s)
2.3 frystyk 57: {
58: if (*s) /* For vms :-( 10/04-94 */
59: return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
60: return HT_OK;
61: }
62:
2.16 frystyk 63: PRIVATE int HTFWriter_flush (HTStream * me)
2.3 frystyk 64: {
2.7 frystyk 65: return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3 frystyk 66: }
67:
2.28 frystyk 68: PRIVATE int HTFWriter_write (HTStream * me, const char* s, int l)
2.3 frystyk 69: {
2.7 frystyk 70: int status ;
71: status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
2.24 frystyk 72: if (l > 1 && status == HT_OK) (void) HTFWriter_flush(me);
2.7 frystyk 73: return status ;
2.3 frystyk 74: }
2.7 frystyk 75:
2.30 frystyk 76: PRIVATE int HTFWriter_free (HTStream * me)
2.3 frystyk 77: {
2.24 frystyk 78: if (me) {
79: if (me->leave_open != YES) fclose(me->fp);
2.28 frystyk 80: #ifdef HAVE_SYSTEM
2.24 frystyk 81: if (me->end_command) system(me->end_command); /* SECURITY HOLE!!! */
2.17 frystyk 82: #endif
2.24 frystyk 83: if (me->remove_on_close) REMOVE(me->filename);
84: if (me->callback) (*me->callback)(me->request, me->filename);
2.26 frystyk 85: HT_FREE(me->end_command);
86: HT_FREE(me->filename);
87: HT_FREE(me);
2.3 frystyk 88: }
89: return HT_OK;
90: }
91:
2.18 frystyk 92: PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
2.3 frystyk 93: {
2.27 eric 94: if (STREAM_TRACE) HTTrace("FileWriter.. ABORTING...\n");
2.24 frystyk 95: if (me) {
96: if (me->leave_open != YES) fclose(me->fp);
97: if (me->remove_on_close) REMOVE(me->filename);
2.26 frystyk 98: HT_FREE(me->end_command);
99: HT_FREE(me->filename);
100: HT_FREE(me);
2.3 frystyk 101: }
102: return HT_ERROR;
103: }
104:
2.28 frystyk 105: PRIVATE const HTStreamClass HTFWriter = /* As opposed to print etc */
2.3 frystyk 106: {
107: "FileWriter",
108: HTFWriter_flush,
2.30 frystyk 109: HTFWriter_free,
2.3 frystyk 110: HTFWriter_abort,
111: HTFWriter_put_character,
112: HTFWriter_put_string,
113: HTFWriter_write
114: };
115:
2.24 frystyk 116: PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
117: BOOL leave_open)
2.3 frystyk 118: {
2.24 frystyk 119: HTStream * me = NULL;
2.3 frystyk 120: if (!fp) {
2.27 eric 121: if (STREAM_TRACE)HTTrace("FileWriter.. Bad file descriptor\n");
2.24 frystyk 122: return HTErrorStream();
2.3 frystyk 123: }
2.26 frystyk 124: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
125: HT_OUTOFMEM("HTFWriter_new");
2.3 frystyk 126: me->isa = &HTFWriter;
127: me->fp = fp;
2.24 frystyk 128: me->leave_open = leave_open;
129: me->request = request;
2.3 frystyk 130: return me;
131: }
132:
133: /* ------------------------------------------------------------------------- */
134: /* FILE WRITER ROUTINES */
135: /* ------------------------------------------------------------------------- */
136:
2.4 frystyk 137: /*
138: ** This function tries really hard to find a non-existent filename relative
2.31 frystyk 139: ** to the path given. Returns a string that must be freed by the caller or
2.4 frystyk 140: ** NULL on error. The base must be '/' terminated which!
141: */
2.28 frystyk 142: PRIVATE char *get_filename (char * base, const char * url, const char * suffix)
2.4 frystyk 143: {
144: char *path=NULL;
145: char filename[40];
146: int hash=0;
147:
148: /* Do this until we find a name that doesn't exist */
149: while (1)
150: {
2.28 frystyk 151: const char *ptr=url;
2.4 frystyk 152: for( ; *ptr; ptr++)
153: hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
154:
2.28 frystyk 155: #ifdef HAVE_GETPID
2.4 frystyk 156: sprintf(filename, "%d-%d", hash, (int) getpid());
157: #else
158: sprintf(filename, "%d-%d", hash, time(NULL));
159: #endif
160: StrAllocCopy(path, base);
161: StrAllocCat(path, filename);
162: if (suffix) StrAllocCat(path, suffix);
163:
164: {
165: FILE *fp = fopen(path, "r");
166: if (fp) /* This file does already exist */
167: fclose(fp);
168: else
169: break; /* Got the file name */
170: }
171: }
2.34 frystyk 172: if (STREAM_TRACE) HTTrace("Save file... Temporaray file `%s\'\n", path);
2.4 frystyk 173: return path;
174: }
175:
176:
2.24 frystyk 177: /* Save Locally
178: ** ------------
179: ** Saves a file to local disk. This can for example be used to dump
180: ** date objects of unknown media types to local disk. The stream prompts
181: ** for a file name for the temporary file.
2.1 frystyk 182: */
2.24 frystyk 183: PUBLIC HTStream* HTSaveLocally (HTRequest * request,
184: void * param,
185: HTFormat input_format,
186: HTFormat output_format,
187: HTStream * output_stream)
2.1 frystyk 188: {
2.24 frystyk 189: FILE * fp = NULL;
190: char * filename = NULL;
2.33 frystyk 191: HTUserProfile * up = HTRequest_userProfile(request);
192: char * tmproot = HTUserProfile_tmp(up);
2.19 frystyk 193: if (HTLib_secure()) {
2.21 frystyk 194: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
2.24 frystyk 195: NULL, 0, "HTSaveLocally");
196: return HTErrorStream();
2.1 frystyk 197: }
2.33 frystyk 198: if (!tmproot) {
2.27 eric 199: if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24 frystyk 200: return HTErrorStream();
2.1 frystyk 201: }
202:
2.24 frystyk 203: /* Let's prompt the user for a file name for this file */
2.4 frystyk 204: {
2.24 frystyk 205: HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
2.13 frystyk 206: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
207: char *suffix = HTBind_getSuffix(anchor);
2.33 frystyk 208: char *deflt = get_filename(tmproot,HTAnchor_physical(anchor),suffix);
2.24 frystyk 209: if (cbf) {
210: HTAlertPar * reply = HTAlert_newReply();
211: if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
212: filename = HTAlert_replyMessage(reply);
213: HTAlert_deleteReply(reply);
214: }
2.26 frystyk 215: HT_FREE(suffix);
216: HT_FREE(deflt);
2.24 frystyk 217: if (filename) {
218: if ((fp = fopen(filename, "wb")) == NULL) {
219: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
220: filename, strlen(filename),"HTSaveLocally");
2.26 frystyk 221: HT_FREE(filename);
2.24 frystyk 222: return HTErrorStream();
223: }
224: } else {
2.27 eric 225: if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24 frystyk 226: return HTErrorStream();
2.4 frystyk 227: }
228: }
2.24 frystyk 229:
230: /* Now we are ready for creating the file writer stream */
231: if (fp) {
232: HTStream * me = HTFWriter_new(request, fp, NO);
233: me->filename = filename;
234: return me;
2.1 frystyk 235: }
2.26 frystyk 236: HT_FREE(filename);
2.24 frystyk 237: return HTErrorStream();
2.1 frystyk 238: }
239:
240:
2.24 frystyk 241: /* Take action using a system command
242: ** ----------------------------------
243: ** Creates temporary file, writes to it and then executes system
244: ** command (maybe an external viewer) when EOF has been reached. The
245: ** stream finds a suitable name of the temporary file which preserves the
246: ** suffix. This way, the system command can find out the file type from
247: ** the name of the temporary file name.
2.1 frystyk 248: */
2.24 frystyk 249: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
250: void * param,
251: HTFormat input_format,
252: HTFormat output_format,
253: HTStream * output_stream)
2.1 frystyk 254: {
2.24 frystyk 255: FILE * fp = NULL;
256: char * filename = NULL;
2.33 frystyk 257: HTUserProfile * up = HTRequest_userProfile(request);
258: char * tmproot = HTUserProfile_tmp(up);
2.19 frystyk 259: if (HTLib_secure()) {
2.21 frystyk 260: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
261: NULL, 0, "HTSaveLocally");
2.24 frystyk 262: return HTErrorStream();
2.1 frystyk 263: }
2.33 frystyk 264: if (!tmproot) {
2.27 eric 265: if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24 frystyk 266: return HTErrorStream();
2.1 frystyk 267: }
268:
2.24 frystyk 269: /* Let's find a hash name for this file without asking user */
2.4 frystyk 270: {
2.13 frystyk 271: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
272: char *suffix = HTBind_getSuffix(anchor);
2.33 frystyk 273: filename = get_filename(tmproot, HTAnchor_physical(anchor), suffix);
2.26 frystyk 274: HT_FREE(suffix);
2.25 frystyk 275: if (filename) {
276: if ((fp = fopen(filename, "wb")) == NULL) {
277: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
278: filename, strlen(filename),"HTSaveAndExecute");
2.26 frystyk 279: HT_FREE(filename);
2.25 frystyk 280: return HTErrorStream();
281: }
282: } else {
2.27 eric 283: if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24 frystyk 284: return HTErrorStream();
2.4 frystyk 285: }
286: }
287:
2.24 frystyk 288: /* Now we are ready for creating the file writer stream */
289: if (fp) {
290: HTStream * me = HTFWriter_new(request, fp, NO);
291: me->filename = filename;
2.31 frystyk 292: if (param) {
293: if ((me->end_command = (char *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
294: HT_OUTOFMEM("SaveAndExecute");
295: sprintf (me->end_command,
296: (char *)param, filename, filename, filename);
297: }
2.24 frystyk 298: return me;
2.1 frystyk 299: }
2.26 frystyk 300: HT_FREE(filename);
2.24 frystyk 301: return HTErrorStream();
2.1 frystyk 302: }
303:
304:
305: /* Save and Call Back
306: ** ------------------
2.32 frystyk 307: ** This stream works exactly like the HTSaveAndExecute
2.24 frystyk 308: ** stream but in addition when EOF has been reached, it checks whether a
309: ** callback function has been associated with the request object in which
310: ** case, this callback is being called. This can be use by the
311: ** application to do some processing after the system command
312: ** has terminated. The callback function is called with the file name of
313: ** the temporary file as parameter.
2.1 frystyk 314: */
2.16 frystyk 315: PUBLIC HTStream* HTSaveAndCallback (HTRequest * request,
316: void * param,
317: HTFormat input_format,
318: HTFormat output_format,
319: HTStream * output_stream)
2.1 frystyk 320: {
2.24 frystyk 321: HTStream * me = HTSaveAndExecute(request, param, input_format,
322: output_format, output_stream);
323: if (me) {
324: me->callback = HTRequest_callback(request);
325: return me;
326: }
327: return HTErrorStream();
2.1 frystyk 328: }
329:
Webmaster