Exemplo n.º 1
0
PUBLIC HTStream * HTRules (HTRequest *	request,
			   void *	param,
			   HTFormat	input_format,
			   HTFormat	output_format,
			   HTStream *	output_stream)
{
    HTAlertCallback *cbf = HTAlert_find(HT_A_CONFIRM);
    
    /*
    **  If the library has been compiled so that we automatically accept
    **  rule files then it's OK not to ask the user.
    */
#ifdef HT_AUTOMATIC_RULES
    if (!cbf || (cbf && (*cbf)(request,HT_A_CONFIRM, HT_MSG_RULES, NULL,NULL,NULL))) {
#else
    if ((cbf && (*cbf)(request,HT_A_CONFIRM, HT_MSG_RULES, NULL,NULL,NULL))) {
#endif
	HTStream * me;
	HTTRACE(APP_TRACE, "Rule file... Parser object created\n");
	if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
	    HT_OUTOFMEM("HTRules");
	me->isa = &HTRuleClass;
	me->request = request;
	me->buffer = HTChunk_new(512);
	me->EOLstate = EOL_BEGIN;
	if (!rules) rules = HTList_new();
	return me;
    } else {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_AUTO_RULES,
			   NULL, 0, "HTRules");
	return HTErrorStream();
    }
}

/*
**  Parse a rule file - don't ask don't tell - be carefull with this one!
*/
PUBLIC HTStream * HTRules_parseAutomatically (HTRequest *	request,
					      void *		param,
					      HTFormat		input_format,
					      HTFormat		output_format,
					      HTStream *	output_stream)
{
    if (request) {
	HTStream * me;
	HTTRACE(APP_TRACE, "Rule file... Automatic parser object created\n");
	if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
	    HT_OUTOFMEM("HTRules");
	me->isa = &HTRuleClass;
	me->request = request;
	me->buffer = HTChunk_new(512);
	me->EOLstate = EOL_BEGIN;
	if (!rules) rules = HTList_new();
	return me;
    } else {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_AUTO_RULES,
			   NULL, 0, "HTRules");
	return HTErrorStream();
    }
}
Exemplo n.º 2
0
/*	Take action using a system command
**	----------------------------------
**	Creates temporary file, writes to it and then executes system
**	command (maybe an external viewer) when EOF has been reached. The
**	stream finds a suitable name of the temporary file which preserves the
**	suffix. This way, the system command can find out the file type from
**	the name of the temporary file name.
*/
PUBLIC HTStream* HTSaveAndExecute (HTRequest *	request,
				   void *	param,
				   HTFormat	input_format,
				   HTFormat	output_format,
				   HTStream *	output_stream)
{
    FILE * fp = NULL;
    char * filename = NULL;
    HTUserProfile * up = HTRequest_userProfile(request);
    char * tmproot = HTUserProfile_tmp(up);
    if (HTLib_secure()) {
	HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
			   NULL, 0, "HTSaveLocally");
	return HTErrorStream();
    }
    if (!tmproot) {
	HTTRACE(STREAM_TRACE, "Save File... turned off");
	return HTErrorStream();
    }
	
    /* Let's find a hash name for this file without asking user */
    {
	HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
	char *suffix = HTBind_getSuffix(anchor);
	filename = get_filename(tmproot, HTAnchor_physical(anchor), suffix, NO);
	HT_FREE(suffix);
	if (filename) {
	    if ((fp = fopen(filename, "wb")) == NULL) {
		HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
				   filename, strlen(filename),"HTSaveAndExecute");
		HT_FREE(filename);
		return HTErrorStream();
	    }
	} else {
	    HTTRACE(STREAM_TRACE, "Save File... No file name\n");
	    return HTErrorStream();
	}
    }
    
    /* Now we are ready for creating the file writer stream */
    if (fp) {
	HTStream * me = HTFileSave_new(request, fp, NO);
	me->filename = filename;
	if (param) {
	    if ((me->end_command = (char  *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
		HT_OUTOFMEM("SaveAndExecute");
	    sprintf (me->end_command,
		     (char *)param, filename, filename, filename);
	}
	return me;
    }
    HT_FREE(filename);
    return HTErrorStream();
}
Exemplo n.º 3
0
PUBLIC HTStream * HTBoundary   (HTRequest *	request,
				void *		param,
				HTFormat	input_format,
				HTFormat	output_format,
				HTStream *	output_stream)
{
    HTResponse * response = HTRequest_response(request);
    HTParentAnchor * anchor = HTRequest_anchor(request);
    HTAssocList * type_param = response ?
	HTResponse_formatParam(response) :
	HTAnchor_formatParam(anchor);
    char * boundary = HTAssocList_findObject(type_param, "boundary");
    if (boundary) {
	HTStream * me;
	if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
	    HT_OUTOFMEM("HTBoundary");
	me->isa = &HTBoundaryClass;
	me->request = request;
	me->format = output_format;
	me->orig_target = output_stream;
	me->debug = HTRequest_debugStream(request);
	me->state = EOL_FLF;
	StrAllocCopy(me->boundary, boundary);		       /* Local copy */
	me->bpos = me->boundary;
	HTTRACE(STREAM_TRACE, "Boundary.... Stream created with boundary '%s\'\n" _ me->boundary);
	return me;
    } else {
	HTTRACE(STREAM_TRACE, "Boundary.... UNKNOWN boundary!\n");
	return HTErrorStream();
    }
}
Exemplo n.º 4
0
PUBLIC HTStream * HTPipeBuffer (HTStream * target, int max_size)
{
    HTStream * me = HTBuffer_new(target, NULL, max_size);
    if (me) {
	me->mode = HT_BM_PIPE;
	return me;
    }
    return HTErrorStream();
}
Exemplo n.º 5
0
/*	Create a new coder and insert it into stream chain
**	--------------------------------------------------
**	Creating the content decoding stack is not based on quality factors as
**	we don't have the freedom as with content types. Specify whether you
**	you want encoding or decoding using the BOOL "encode" flag.
*/
PUBLIC HTStream * HTContentCodingStack (HTEncoding	encoding,
					HTStream *	target,
					HTRequest *	request,
					void *		param,
					BOOL		encode)
{
    HTList * coders[2];
    HTStream * top = target;
    HTCoding * pres = NULL;
    HTCoding * best_match = NULL;
    double best_quality = -1e30;		/* Pretty bad! */
    int cnt;
    if (!encoding || !request) {
	HTTRACE(CORE_TRACE, "Codings... Nothing applied...\n");
	return target ? target : HTErrorStream();
    }
    coders[0] = HTRequest_encoding(request);
    coders[1] = HTContentCoders;
    HTTRACE(CORE_TRACE, "C-E......... Looking for `%s\'\n" _ HTAtom_name(encoding));
    for (cnt=0; cnt < 2; cnt++) {
	HTList * cur = coders[cnt];
	while ((pres = (HTCoding *) HTList_nextObject(cur))) {
	    if ((pres->encoding == encoding || HTMIMEMatch(pres->encoding, encoding)) &&
		pres->quality > best_quality) {
		best_match = pres;
		best_quality = pres->quality;
	    }
	}
    }

    if (best_match) {
	HTTRACE(CORE_TRACE, "C-E......... Found `%s\'\n" _ HTAtom_name(best_match->encoding));
	if (encode) {
	    if (best_match->encoder)
		top = (*best_match->encoder)(request, param, encoding, top);
	} else {
	    if (best_match->decoder)
		top = (*best_match->decoder)(request, param, encoding, top);
	}
    } else if (!HTFormat_isUnityContent(encoding)) {

	/*
	**  If this is not a unity coding and we didn't find any coders
	**  that could handle it then put in a local file save stream
	**  instead of the stream that we got.
	*/
	if (encode) {
	    HTTRACE(CORE_TRACE, "C-E......... NOT FOUND - can't encode stream!\n");
	} else {
	    HTTRACE(CORE_TRACE, "C-E......... NOT FOUND - error!\n");
	    top = HTBlackHole();
	}
    }
    return top;
}
Exemplo n.º 6
0
/*	Create a new transfer coder and insert it into stream chain
**	-----------------------------------------------------------
**	Creating the content decoding stack is not based on quality factors as
**	we don't have the freedom as with content types. Specify whether you
**	you want encoding or decoding using the BOOL "encode" flag.
*/
PUBLIC HTStream * HTContentTransferCodingStack (HTEncoding	encoding,
						HTStream *	target,
						HTRequest *	request,
						void *		param,
						BOOL		encode)
{
    HTList * coders[2];
    HTStream * top = target;
    HTCoding * pres = NULL;
    int cnt;
    if (!encoding || !request) {
	HTTRACE(CORE_TRACE, "C-T-E..... Nothing applied...\n");
	return target ? target : HTErrorStream();
    }

    /*
    **  We use the same encoders/decoders as for Transfer-Encodings
    */
    coders[0] = HTRequest_transfer(request);
    coders[1] = HTTransferCoders;
    HTTRACE(CORE_TRACE, "C-T-E....... Looking for %s\n" _ HTAtom_name(encoding));
    for (cnt=0; cnt < 2; cnt++) {
	HTList * cur = coders[cnt];
	while ((pres = (HTCoding *) HTList_nextObject(cur))) {
	    if (pres->encoding == encoding) {
		HTTRACE(CORE_TRACE, "C-T-E....... Found...\n");
		if (encode) {
		    if (pres->encoder)
			top = (*pres->encoder)(request, param, encoding, top);
		    break;
		} else if (pres->decoder) {
		    top = (*pres->decoder)(request, param, encoding, top);
		    break;
		}
	    }
	}
    }

    /*
    **  If this is not a unity coding and we didn't find any coders
    **  that could handle it then put in a local file save stream
    **  instead of the stream that we got.
    */
    if (!HTFormat_isUnityTransfer(encoding) && target==top) {
	if (encode) {	    
	    HTTRACE(CORE_TRACE, "C-T-E....... NOT FOUND - removing encoding!\n");
	    HTAnchor_setContentTransferEncoding(HTRequest_anchor(request), NULL);
	} else {
	    HTTRACE(CORE_TRACE, "C-T-E....... NOT FOUND - error!\n");
	    top = HTBlackHole();
	}
    }
    return top;
}
Exemplo n.º 7
0
PUBLIC HTStream * HTZLib_inflate (HTRequest *	request,
				  void *	param,
				  HTEncoding	coding,
				  HTStream *	target)
{
    HTStream * me = NULL;
    if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL ||
	(me->zstream = (z_stream *) HT_CALLOC(1, sizeof(z_stream))) == NULL)
	HT_OUTOFMEM("HTZLib_inflate");
    me->isa = &HTInflate;
    me->state = HT_OK;
    me->request = request;
    me->target = target ? target : HTErrorStream();
    if (Zlib_init(me, CompressionLevel) != YES) {
	HT_FREE(me);
	return HTErrorStream();
    }
    HTTRACE(STREAM_TRACE, "Zlib Inflate Stream created\n");
    return me;
}
Exemplo n.º 8
0
PUBLIC HTStream * HTContentCounter (HTStream *	target,
				    HTRequest *	request,
				    int		max_size)
{
    HTStream * me = HTBuffer_new(target, NULL, max_size);
    if (me) {
	me->mode = HT_BM_COUNT;
	return me;
    }
    return HTErrorStream();
}
Exemplo n.º 9
0
/*	Save and Call Back
**	------------------
**	This stream works exactly like the HTSaveAndExecute
**	stream but in addition when EOF has been reached, it checks whether a
**	callback function has been associated with the request object in which
**	case, this callback is being called. This can be use by the
**	application to do some processing after the system command
**	has terminated. The callback function is called with the file name of
**	the temporary file as parameter.
*/
PUBLIC HTStream* HTSaveAndCallback (HTRequest *		request,
				    void *		param,
				    HTFormat		input_format,
				    HTFormat		output_format,
				    HTStream *		output_stream)
{
    HTStream * me = HTSaveAndExecute(request, param, input_format,
				     output_format, output_stream);
    if (me) {
	me->callback = HTRequest_callback(request);
	return me;
    }
    return HTErrorStream();
}
Exemplo n.º 10
0
PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
				 BOOL leave_open)
{
    HTStream * me = NULL;
    if (!fp) {
	HTTRACE(STREAM_TRACE, "FileWriter.. Bad file descriptor\n");
	return HTErrorStream();
    }
    if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
        HT_OUTOFMEM("HTFWriter_new");
    me->isa = &HTFWriter;       
    me->fp = fp;
    me->leave_open = leave_open;
    return me;
}
Exemplo n.º 11
0
/*
**  Here you can provide a complete list instead of a single token.
**  The list has to filled up in the order the _encodings_ are to be applied
*/
PUBLIC HTStream * HTTransferEncodingStack (HTList *	encodings,
					   HTStream *	target,
					   HTRequest *	request,
					   void *	param)
{
    if (encodings) {
	HTList * cur = encodings;
	HTEncoding pres;
	HTStream * top = target;
	while ((pres = (HTEncoding) HTList_nextObject(cur))) {
	    top = HTTransferCodingStack(pres, top, request, param, YES);
	    if (top == HTBlackHole()) break;
	}
	return top;
    }
    return HTErrorStream();
}
Exemplo n.º 12
0
/*	HTConverter for HTML to C code
**	------------------------------
**
**	C code is like plain text but all non-preformatted code
**	is commented out.
**	This will convert from HTML to presentation or plain text.
*/
PUBLIC HTStream * HTMLToC (HTRequest *	request,
			   void *	param,
			   HTFormat	input_format,
			   HTFormat	output_format,
			   HTStream *	output_stream)
{
    if (output_stream) {
	HTStructured * html = NULL;
	(*output_stream->isa->put_string)(output_stream, "/* "); /* Before title */
	html = HTML_new(request, NULL, input_format, output_format, output_stream);
	html->comment_start = "\n/* ";
	html->dtd = HTML_dtd();
	html->comment_end = " */\n";	/* Must start in col 1 for cpp */
	return SGML_new(HTML_dtd(), html);
    } else
	return HTErrorStream();
}
Exemplo n.º 13
0
/*
**  Here you can provide a complete list instead of a single token.
**  The list has to be in the order the _encodings_ were applied - that
**  is, the same way that _encodings_ are to be applied. This is all consistent
**  with the order of the Content-Encoding header.
*/
PUBLIC HTStream * HTTransferDecodingStack (HTList *	encodings,
					   HTStream *	target,
					   HTRequest *	request,
					   void *	param)
{
    if (encodings) {
	HTEncoding pres;
	int cnt = HTList_count(encodings);
	HTStream * top = target;
	while (cnt > 0) {
	    pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
	    top = HTTransferCodingStack(pres, top, request, param, NO);
	    if (top == HTBlackHole()) break;
	}
	return top;
    }
    return HTErrorStream();
}
Exemplo n.º 14
0
PUBLIC HTStream * HTStreamToChunk (HTRequest * 	request,
				   HTChunk **	chunk,
				   int 		max_size)
{
    if (request) {
	HTStream * me;
	*chunk = NULL;
	if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
	    HT_OUTOFMEM("HTStreamToChunk");
	me->isa = &HTStreamToChunkClass;
	me->request = request;
	me->max_size = (!max_size) ? max_size : HT_MAXSIZE;
	me->chunk = *chunk = HTChunk_new(me->max_size > 0 ?
					 HTMIN(me->max_size, HT_MAXGROWSIZE) :
					 HT_MAXGROWSIZE);
	HTTRACE(STREAM_TRACE, "ChunkStream. Chunk %p created with max size %d\n" _ 
		    me->chunk _ me->max_size);
	return me;
    }
    return HTErrorStream();
}
Exemplo n.º 15
0
PRIVATE int HTGuess_flush (HTStream * me)
{
    if (!me->transparent) {
	HTResponse * response = me->response;

	/*
	**  First we look for magic tokens and evaluate the contents of the buffer
	**  that we are investigating. 
	*/
	if (me->cnt) {
	    HTTRACE(STREAM_TRACE, "GUESSING.... Result of content analysis: Text=%d%% Newlines=%d%% Ctrl=%d%% High=%d%%\n" _ 
			(int)(100*me->text_cnt/me->cnt + 0.5) _ 
			(int)(100*me->lf_cnt  /me->cnt + 0.5) _ 
			(int)(100*me->ctrl_cnt/me->cnt + 0.5) _ 
			(int)(100*me->high_cnt/me->cnt + 0.5));
	}
	
	if (!me->ctrl_cnt ||
	    me->text_cnt + me->lf_cnt >= 16 * (me->ctrl_cnt + me->high_cnt)) {
	    char *ptr;
	    /* some kind of text */
	    
	    *me->write_ptr = 0;	/* terminate buffer */
	    
	    if (me->high_cnt > 0)
		HTResponse_setContentTransferEncoding(response, WWW_CODING_8BIT);
	    else
		HTResponse_setContentTransferEncoding(response, WWW_CODING_7BIT);
	    
	    if (is_html(me->buffer))
		HTResponse_setFormat(response, HTAtom_for("text/html"));
	    
	    else if (!strncmp(me->buffer, "%!", 2))
		HTResponse_setFormat(response, HTAtom_for("application/postscript"));
	    
	    else if (strstr(me->buffer, "#define") &&
		     strstr(me->buffer, "_width") &&
		     strstr(me->buffer, "_bits"))
		HTResponse_setFormat(response, HTAtom_for("image/x-xbitmap"));
	    
	    else if ((ptr = strstr(me->buffer, "converted with BinHex"))!=NULL)
		HTResponse_setContentTransferEncoding(response, WWW_CODING_MACBINHEX);

	    else if (!strncmp(me->buffer, "begin ", 6))
		HTResponse_setContentTransferEncoding(response, WWW_CODING_BASE64);

	    else
		HTResponse_setFormat(response, WWW_PLAINTEXT);
	}
	else {
	    if (!strncmp(me->buffer, "GIF", 3))
		HTResponse_setFormat(response, WWW_GIF);

	    else if (!strncmp(me->buffer, "\377\330\377\340", 4))
		HTResponse_setFormat(response, WWW_JPEG);

	    else if (!strcmp(me->buffer, "MM"))	/* MM followed by a zero */
		HTResponse_setFormat(response, WWW_TIFF);

 	    else if (!strncmp(me->buffer, "\211PNG\r\n\032\n", 8))
 		HTResponse_setFormat(response, WWW_PNG);

	    else if (!strncmp(me->buffer, ".snd", 4))
		HTResponse_setFormat(response, WWW_AUDIO);

	    else if (!strncmp(me->buffer, "\037\235", 2))
		HTResponse_addEncoding(response, WWW_CODING_COMPRESS);

	    else if (!strncmp(me->buffer, "\037\213", 2))
		HTResponse_addEncoding(response, WWW_CODING_GZIP);

	    else
		HTResponse_setFormat(response, WWW_BINARY);
	}
	
	/*
	**  If we couldn't find any magic tokens then we try and look at the suffix
	**  of the URL file name and use our own bindings to see if that gives any
	**  results.
	*/
	if (HTResponse_format(response) == WWW_UNKNOWN) {
	    HTParentAnchor * anchor = HTRequest_anchor(me->request);
	    char * addr = HTAnchor_physical(anchor);
	    HTTRACE(STREAM_TRACE, "GUESSING.... Hmm - trying local bindings\n");
	    HTBind_getResponseBindings (response, addr);
	}

	/*
	**  If nothing worked then give up and say binary...
	*/
	if (HTResponse_format(response) == WWW_UNKNOWN) {
	    HTTRACE(STREAM_TRACE, "GUESSING.... That's it - I'm giving up!\n");
	    HTResponse_setFormat(response, WWW_BINARY);
	}
		
	HTTRACE(STREAM_TRACE, "Guessed..... Content-Type `%s\'\n" _ HTAtom_name(HTResponse_format(response)));

	/*
	**  Set up the new stream stack with the type we figured out 
	*/
	if ((me->target = HTStreamStack(HTResponse_format(response),
					me->output_format, me->output_stream,
					me->request, NO)) == NULL) {
	    HTTRACE(STREAM_TRACE, "HTGuess..... Can't convert media type\n");
	    me->target = HTErrorStream();
	}
	me->transparent = YES;
	return PUT_BLOCK(me->buffer, me->cnt);
    }
    return HT_OK;
}
Exemplo n.º 16
0
/*	Save Locally
**	------------
**	Saves a file to local disk. This can for example be used to dump
**	data objects of unknown media types to local disk. The stream prompts
**	for a file name for the temporary file.
*/
PUBLIC HTStream* HTSaveLocally (HTRequest *	request,
				void *		param,
				HTFormat	input_format,
				HTFormat	output_format,
				HTStream *	output_stream)
{
    FILE * fp = NULL;
    char * filename = NULL;
    HTUserProfile * up = HTRequest_userProfile(request);
    char * tmproot = HTUserProfile_tmp(up);
    if (HTLib_secure()) {
	HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
			   NULL, 0, "HTSaveLocally");
	return HTErrorStream();
    }
    if (!tmproot) {
	HTTRACE(STREAM_TRACE, "Save File... turned off\n");
	return HTErrorStream();
    }
	
    /* Let's prompt the user for a file name for this file */
    {
	HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
	HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);

	/*
	**  If we found an alert handler for prompting the user then call it.
	**  If not then either we are in non-interactive mode or no handler
	**  has been registered. For now we then return a blackhole which may
	**  not be the best thing to do.
	*/
	if (cbf) {
	    HTAlertPar * reply = HTAlert_newReply();
	    char * suffix = HTBind_getSuffix(anchor);
	    char * deflt = get_filename(tmproot, HTAnchor_physical(anchor), suffix, YES);
	    if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
		filename = HTAlert_replyMessage(reply);
	    HTAlert_deleteReply(reply);
	    HT_FREE(suffix);
	    HT_FREE(deflt);
	}
	if (filename) {
	    if ((fp = fopen(filename, "wb")) == NULL) {
		HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
				   filename, strlen(filename),"HTSaveLocally");
		HT_FREE(filename);
		return HTErrorStream();
	    }
	} else if (cbf) {
	    HTTRACE(STREAM_TRACE, "Save File... No file name - error stream\n");
	    return HTErrorStream();
	} else {
	    HTTRACE(STREAM_TRACE, "Save File... No file name - black hole\n");
	    return HTBlackHole();
	}
    }
    
    /* Now we are ready for creating the file writer stream */
    if (fp) {
	HTStream * me = HTFileSave_new(request, fp, NO);
	me->filename = filename;
	return me;
    }
    HT_FREE(filename);
    return HTErrorStream();
}
Exemplo n.º 17
0
/*	Create a Content Type filter stack
**	----------------------------------
**	If a wildcard match is made, a temporary HTPresentation
**	structure is made to hold the destination format while the
**	new stack is generated. This is just to pass the out format to
**	MIME so far.  Storing the format of a stream in the stream might
**	be a lot neater.
**
**	The star/star format is special, in that if you can take
**	that you can take anything.
*/
PUBLIC HTStream * HTStreamStack (HTFormat	rep_in,
				 HTFormat	rep_out,
				 HTStream *	output_stream,
				 HTRequest *	request,
				 BOOL		guess)
{
    HTList * conversion[2];
    int which_list;
    double best_quality = -1e30;		/* Pretty bad! */
    HTPresentation *pres, *best_match=NULL;
    if (rep_out == WWW_RAW) {
	HTTRACE(CORE_TRACE, "StreamStack. Raw output...\n");
	return output_stream ? output_stream : HTErrorStream();
    }

    if (rep_out == rep_in) {
	HTTRACE(CORE_TRACE, "StreamStack. Identical input/output format (%s)\n" _ 
		     HTAtom_name(rep_out));
	return output_stream ? output_stream : HTErrorStream();
    }

#ifdef HTDEBUG
    if (CORE_TRACE) {
	const char *p = HTAtom_name(rep_in);
	const char *q = HTAtom_name(rep_out); 
	HTTRACE(CORE_TRACE, "StreamStack. Constructing stream stack for %s to %s\n" _
		p ? p : "<NULL>" _ q ? q : "<NULL>");
    }
#endif /* HTDEBUG */

    conversion[0] = HTRequest_conversion(request);
    conversion[1] = HTConversions;

    for(which_list = 0; which_list<2; which_list++) {
	HTList * cur = conversion[which_list];
	while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
	    if ((pres->rep==rep_in || HTMIMEMatch(pres->rep, rep_in)) &&
		(pres->rep_out==rep_out || HTMIMEMatch(pres->rep_out,rep_out))){
		if (!best_match || better_match(pres->rep, best_match->rep) ||
		    (!better_match(best_match->rep, pres->rep) &&
		     pres->quality > best_quality)) {
#ifdef HAVE_SYSTEM
		    int result=0;
		    if (pres->test_command) {
			result = system(pres->test_command);
			HTTRACE(CORE_TRACE, "StreamStack. system(%s) returns %d\n" _ pres->test_command _ result);
		    }
		    if (!result) {
			best_match = pres;
			best_quality = pres->quality;
		    }
#else
		    best_match = pres;
		    best_quality = pres->quality;
#endif /* HAVE_SYSTEM */
		}
	    }
	}
    }

    if (best_match) {
 	if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
	    HTTRACE(CORE_TRACE, "StreamStack. Source output\n");
	    return output_stream ? output_stream : HTErrorStream();
	}
	return (*best_match->converter)(request, best_match->command,
					rep_in, rep_out, output_stream);
    }
    if (rep_out == WWW_SOURCE) {
	HTTRACE(CORE_TRACE, "StreamStack. Source output\n");
	return output_stream ? output_stream : HTErrorStream();
    }

    HTTRACE(CORE_TRACE, "StreamStack. NOT FOUND - error!\n");
    return HTBlackHole();
}