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