Annotation of libwww/Library/src/HTFWrite.c, revision 2.44
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.44 ! frystyk 6: ** @(#) $Id: HTFWrite.c,v 2.43 1998/07/22 19:24:25 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.42 frystyk 23: #include "wwwsys.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.44 ! frystyk 29: #include "HTInet.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.44 ! frystyk 49: #define DEFAULT_LAST_SEGMENT "index"
! 50:
2.3 frystyk 51: /* ------------------------------------------------------------------------- */
2.1 frystyk 52:
2.16 frystyk 53: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3 frystyk 54: {
55: return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
56: }
57:
2.28 frystyk 58: PRIVATE int HTFWriter_put_string (HTStream * me, const char* s)
2.3 frystyk 59: {
60: if (*s) /* For vms :-( 10/04-94 */
61: return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
62: return HT_OK;
63: }
64:
2.16 frystyk 65: PRIVATE int HTFWriter_flush (HTStream * me)
2.3 frystyk 66: {
2.7 frystyk 67: return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3 frystyk 68: }
69:
2.28 frystyk 70: PRIVATE int HTFWriter_write (HTStream * me, const char* s, int l)
2.3 frystyk 71: {
2.7 frystyk 72: int status ;
73: status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
2.24 frystyk 74: if (l > 1 && status == HT_OK) (void) HTFWriter_flush(me);
2.7 frystyk 75: return status ;
2.3 frystyk 76: }
2.7 frystyk 77:
2.30 frystyk 78: PRIVATE int HTFWriter_free (HTStream * me)
2.3 frystyk 79: {
2.24 frystyk 80: if (me) {
2.41 frystyk 81: if (me->leave_open != YES)
82: fclose(me->fp);
83: else
84: HTFWriter_flush(me);
2.28 frystyk 85: #ifdef HAVE_SYSTEM
2.24 frystyk 86: if (me->end_command) system(me->end_command); /* SECURITY HOLE!!! */
2.17 frystyk 87: #endif
2.37 frystyk 88: if (me->callback) (*me->callback)(me->request, me->filename);
2.24 frystyk 89: if (me->remove_on_close) REMOVE(me->filename);
2.26 frystyk 90: HT_FREE(me->end_command);
91: HT_FREE(me->filename);
92: HT_FREE(me);
2.3 frystyk 93: }
94: return HT_OK;
95: }
96:
2.18 frystyk 97: PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
2.3 frystyk 98: {
2.27 eric 99: if (STREAM_TRACE) HTTrace("FileWriter.. ABORTING...\n");
2.24 frystyk 100: if (me) {
101: if (me->leave_open != YES) fclose(me->fp);
102: if (me->remove_on_close) REMOVE(me->filename);
2.26 frystyk 103: HT_FREE(me->end_command);
104: HT_FREE(me->filename);
105: HT_FREE(me);
2.3 frystyk 106: }
107: return HT_ERROR;
108: }
109:
2.28 frystyk 110: PRIVATE const HTStreamClass HTFWriter = /* As opposed to print etc */
2.3 frystyk 111: {
112: "FileWriter",
113: HTFWriter_flush,
2.30 frystyk 114: HTFWriter_free,
2.3 frystyk 115: HTFWriter_abort,
116: HTFWriter_put_character,
117: HTFWriter_put_string,
118: HTFWriter_write
119: };
120:
2.24 frystyk 121: PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
122: BOOL leave_open)
2.3 frystyk 123: {
2.24 frystyk 124: HTStream * me = NULL;
2.3 frystyk 125: if (!fp) {
2.27 eric 126: if (STREAM_TRACE)HTTrace("FileWriter.. Bad file descriptor\n");
2.24 frystyk 127: return HTErrorStream();
2.3 frystyk 128: }
2.26 frystyk 129: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
130: HT_OUTOFMEM("HTFWriter_new");
2.3 frystyk 131: me->isa = &HTFWriter;
132: me->fp = fp;
2.24 frystyk 133: me->leave_open = leave_open;
134: me->request = request;
2.3 frystyk 135: return me;
136: }
137:
138: /* ------------------------------------------------------------------------- */
139: /* FILE WRITER ROUTINES */
140: /* ------------------------------------------------------------------------- */
141:
2.4 frystyk 142: /*
143: ** This function tries really hard to find a non-existent filename relative
2.31 frystyk 144: ** to the path given. Returns a string that must be freed by the caller or
2.44 ! frystyk 145: ** NULL on error.
2.4 frystyk 146: */
2.44 ! frystyk 147: PRIVATE char * get_filename (char * base, const char * uri,
! 148: const char * suffix, BOOL use_last_segment)
2.4 frystyk 149: {
2.44 ! frystyk 150: char * path = NULL;
! 151: if (use_last_segment) {
! 152: char * uri_path = NULL;
! 153: if (uri && (uri_path = HTParse(uri, "", PARSE_PATH|PARSE_PUNCTUATION))) {
! 154: char * last_segment = strrchr(uri_path, '/');
! 155: BOOL slash = (base && *(base+strlen(base)-1)=='/');
! 156: if (last_segment && *(last_segment+1)) {
! 157: StrAllocMCopy(&path, base ? base : "",
! 158: slash ? "" : "/", ++last_segment, NULL);
! 159: } else {
! 160: StrAllocMCopy(&path, base ? base : "",
! 161: slash ? "" : "/", DEFAULT_LAST_SEGMENT,
! 162: suffix ? suffix : "", NULL);
! 163: }
2.4 frystyk 164: }
2.44 ! frystyk 165: } else {
! 166: path = HTGetTmpFileName(base);
! 167: if (path && suffix) StrAllocCat(path, suffix);
2.4 frystyk 168: }
2.44 ! frystyk 169:
! 170: if (STREAM_TRACE)
! 171: HTTrace("Save file... Temporaray file `%s\'\n", path ? path : "<null>");
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
2.44 ! frystyk 178: ** data objects of unknown media types to local disk. The stream prompts
2.24 frystyk 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.43 frystyk 197: if (STREAM_TRACE) HTTrace("Save File... turned off\n");
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);
2.39 frystyk 205:
206: /*
207: ** If we found an alert handler for prompting the user then call it.
208: ** If not then either we are in non-interactive mode or no handler
209: ** has been registered. For now we then return a blackhole which may
210: ** not be the best thing to do.
211: */
2.24 frystyk 212: if (cbf) {
213: HTAlertPar * reply = HTAlert_newReply();
2.40 frystyk 214: char * suffix = HTBind_getSuffix(anchor);
2.44 ! frystyk 215: char * deflt = get_filename(tmproot, HTAnchor_physical(anchor), suffix, YES);
2.24 frystyk 216: if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
217: filename = HTAlert_replyMessage(reply);
218: HTAlert_deleteReply(reply);
2.40 frystyk 219: HT_FREE(suffix);
220: HT_FREE(deflt);
2.24 frystyk 221: }
222: if (filename) {
223: if ((fp = fopen(filename, "wb")) == NULL) {
224: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
225: filename, strlen(filename),"HTSaveLocally");
2.26 frystyk 226: HT_FREE(filename);
2.24 frystyk 227: return HTErrorStream();
228: }
2.39 frystyk 229: } else if (cbf) {
230: if (STREAM_TRACE) HTTrace("Save File... No file name - error stream\n");
231: return HTErrorStream();
2.24 frystyk 232: } else {
2.39 frystyk 233: if (STREAM_TRACE) HTTrace("Save File... No file name - black hole\n");
234: return HTBlackHole();
2.4 frystyk 235: }
236: }
2.24 frystyk 237:
238: /* Now we are ready for creating the file writer stream */
239: if (fp) {
240: HTStream * me = HTFWriter_new(request, fp, NO);
241: me->filename = filename;
242: return me;
2.1 frystyk 243: }
2.26 frystyk 244: HT_FREE(filename);
2.24 frystyk 245: return HTErrorStream();
2.1 frystyk 246: }
247:
248:
2.24 frystyk 249: /* Take action using a system command
250: ** ----------------------------------
251: ** Creates temporary file, writes to it and then executes system
252: ** command (maybe an external viewer) when EOF has been reached. The
253: ** stream finds a suitable name of the temporary file which preserves the
254: ** suffix. This way, the system command can find out the file type from
255: ** the name of the temporary file name.
2.1 frystyk 256: */
2.24 frystyk 257: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
258: void * param,
259: HTFormat input_format,
260: HTFormat output_format,
261: HTStream * output_stream)
2.1 frystyk 262: {
2.24 frystyk 263: FILE * fp = NULL;
264: char * filename = NULL;
2.33 frystyk 265: HTUserProfile * up = HTRequest_userProfile(request);
266: char * tmproot = HTUserProfile_tmp(up);
2.19 frystyk 267: if (HTLib_secure()) {
2.21 frystyk 268: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
269: NULL, 0, "HTSaveLocally");
2.24 frystyk 270: return HTErrorStream();
2.1 frystyk 271: }
2.33 frystyk 272: if (!tmproot) {
2.27 eric 273: if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24 frystyk 274: return HTErrorStream();
2.1 frystyk 275: }
276:
2.24 frystyk 277: /* Let's find a hash name for this file without asking user */
2.4 frystyk 278: {
2.13 frystyk 279: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
280: char *suffix = HTBind_getSuffix(anchor);
2.44 ! frystyk 281: filename = get_filename(tmproot, HTAnchor_physical(anchor), suffix, NO);
2.26 frystyk 282: HT_FREE(suffix);
2.25 frystyk 283: if (filename) {
284: if ((fp = fopen(filename, "wb")) == NULL) {
285: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
286: filename, strlen(filename),"HTSaveAndExecute");
2.26 frystyk 287: HT_FREE(filename);
2.25 frystyk 288: return HTErrorStream();
289: }
290: } else {
2.27 eric 291: if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24 frystyk 292: return HTErrorStream();
2.4 frystyk 293: }
294: }
295:
2.24 frystyk 296: /* Now we are ready for creating the file writer stream */
297: if (fp) {
298: HTStream * me = HTFWriter_new(request, fp, NO);
299: me->filename = filename;
2.31 frystyk 300: if (param) {
301: if ((me->end_command = (char *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
302: HT_OUTOFMEM("SaveAndExecute");
303: sprintf (me->end_command,
304: (char *)param, filename, filename, filename);
305: }
2.24 frystyk 306: return me;
2.1 frystyk 307: }
2.26 frystyk 308: HT_FREE(filename);
2.24 frystyk 309: return HTErrorStream();
2.1 frystyk 310: }
311:
312:
313: /* Save and Call Back
314: ** ------------------
2.32 frystyk 315: ** This stream works exactly like the HTSaveAndExecute
2.24 frystyk 316: ** stream but in addition when EOF has been reached, it checks whether a
317: ** callback function has been associated with the request object in which
318: ** case, this callback is being called. This can be use by the
319: ** application to do some processing after the system command
320: ** has terminated. The callback function is called with the file name of
321: ** the temporary file as parameter.
2.1 frystyk 322: */
2.16 frystyk 323: PUBLIC HTStream* HTSaveAndCallback (HTRequest * request,
324: void * param,
325: HTFormat input_format,
326: HTFormat output_format,
327: HTStream * output_stream)
2.1 frystyk 328: {
2.24 frystyk 329: HTStream * me = HTSaveAndExecute(request, param, input_format,
330: output_format, output_stream);
331: if (me) {
332: me->callback = HTRequest_callback(request);
333: return me;
334: }
335: return HTErrorStream();
2.1 frystyk 336: }
337:
Webmaster