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