/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "if.h" #include "dummy_nc.h" extern PRBool il_load_image(MWContext *cx, char *image_url, NET_ReloadMethod cache_reload_policy); #include "merrors.h" #ifdef STANDALONE_IMAGE_LIB #include "xpcompat.h" #else /* for XP_GetString() */ #include "xpgetstr.h" #endif #include "il_strm.h" /* Stream converters. */ static unsigned int il_view_write_ready(NET_StreamClass *stream) { ilINetReader *reader = (ilINetReader *)stream->data_object; /* For some reason, the imagelib can't deliver the image. Trigger il_view_write(), which will abort the stream. */ /* This originally returned (ic!=0) to trigger il_view_write() which would set the read_size to something reasonable. But in mkmailbox.c ReadMessageSock() uses the return value of one as the read_size and does not call il_view_write() until it has filled up the buffer one byte at a time. This should be addressed correctly in later versions. */ return (reader != 0) * MAX_WRITE_READY; } /* Abort the stream if we get this far */ static int il_view_write(NET_StreamClass *stream, const unsigned char *str, int32 len) { void *dobj=stream->data_object; /* If this assert fires, chances are that the provided URL was malformed.*/ PR_ASSERT(dobj == (void*)1); /* Should be MK_DATA_LOADED, but netlib ignores that. */ return MK_INTERRUPTED; } static void il_view_complete(NET_StreamClass *stream) { } static void il_view_abort(NET_StreamClass *stream, int status) { } void il_stream_complete(NET_StreamClass *stream) { ilINetReader *reader = (ilINetReader *)stream->data_object; reader->StreamComplete((PRBool)stream->is_multipart); } void il_abort(NET_StreamClass *stream, int status) { ilINetReader *reader = (ilINetReader *)stream->data_object; reader->StreamAbort(status); stream->data_object = 0; } /* Only for internal-external-reconnect. */ void il_stream_reconnect_complete(NET_StreamClass *stream) { /* Get reader before calling il_stream_complete because it may set stream->data_object to NULL. */ ilINetReader *reader = (ilINetReader *)stream->data_object; PR_ASSERT(reader); il_stream_complete(stream); NS_RELEASE(reader); stream->data_object = NULL; } /* Only for internal-external-reconnect. */ void il_reconnect_abort(NET_StreamClass *stream, int status) { /* Get reader before calling il_abort because it may set stream->data_object to NULL. */ ilINetReader *reader = (ilINetReader *)stream->data_object; PR_ASSERT(reader); il_abort(stream,status); NS_RELEASE(reader); stream->data_object = NULL; } unsigned int il_write_ready(NET_StreamClass *stream) { ilINetReader *reader = (ilINetReader *)stream->data_object; return reader->WriteReady(); } int il_write(NET_StreamClass *stream, const unsigned char *str, int32 len) { ilINetReader *reader = (ilINetReader *)stream->data_object; return reader->Write(str, len); } int il_first_write(NET_StreamClass *stream, const unsigned char *str, int32 len) { ilINetReader *reader = (ilINetReader *)stream->data_object; int ret_val; ret_val = reader->FirstWrite(str, len); if (ret_val != 0) { return ret_val; } stream->put_block = (MKStreamWriteFunc)il_write; /* do first write */ return stream->put_block(stream, (const char*) str, len); } /* there can be only one, highlander */ static NET_StreamClass *unconnected_stream = 0; static URL_Struct *unconnected_urls = 0; void il_reconnect(il_container *ic) { if (unconnected_stream) { /* Will be freed in il_stream_reconnect_complete or il_reconnect_abort */ ilINetReader *reader = IL_NewNetReader(ic); if (reader != NULL) { unconnected_stream->complete = il_stream_reconnect_complete; unconnected_stream->abort = il_reconnect_abort; unconnected_stream->is_write_ready = il_write_ready; unconnected_stream->data_object = (void *)reader; unconnected_stream->put_block = (MKStreamWriteFunc)il_first_write; ic->type = IL_UNKNOWN; ic->state = IC_STREAM; /* unconnected_urls->fe_data no longer has a ponter to an ilIURL, it wasn't used anyway. */ ic->content_length = unconnected_urls->content_length; } unconnected_stream = 0; unconnected_urls = 0; } } /* We aren't going to reconnect after all. Cause the stream to abort */ void il_abort_reconnect() { if (unconnected_stream) { unconnected_stream->data_object = (void *)1; unconnected_stream = 0; unconnected_urls = 0; } } static char fakehtml[] = ""; NET_StreamClass * IL_ViewStream(FO_Present_Types format_out, void *newshack, URL_Struct *urls, OPAQUE_CONTEXT *cx) { NET_StreamClass *stream = nil, *viewstream = nil; il_container *ic = nil; ilINetReader *reader = nil; ilIURL *iurl; char *org_content_type; char *image_url; /* multi-part reconnect hack */ iurl = (ilIURL *)urls->fe_data; if (iurl) { reader = iurl->GetReader(); if(reader) { /* Extreme editor hack! This value is used when loading images so we use the converter we did in 4.06 code. If we don't, this code triggers parsing of the image URL, which has very bad effects in the editor! */ if( reader->IsMulti() ) { NS_RELEASE(reader); return IL_NewStream(format_out, IL_UNKNOWN, urls, cx); } NS_RELEASE(reader); } } /* Create stream object */ if (!(stream = PR_NEWZAP(NET_StreamClass))) { ILTRACE(1,("il: IL_ViewStream memory lossage")); return 0; } stream->name = "image view"; stream->complete = il_view_complete; stream->abort = il_view_abort; stream->is_write_ready = il_view_write_ready; stream->data_object = NULL; stream->window_id = (MWContext *)cx; stream->put_block = (MKStreamWriteFunc)il_view_write; ILTRACE(0,("il: new view stream, %s", urls->address)); PR_ASSERT(!unconnected_stream); /* Note that this URL_Struct does not have a iURL wrapper around it anymore. It doesn't need it and we wouldn't have any good place to free it anyway. */ unconnected_stream = stream; unconnected_urls = urls; if(!newshack) { char *buffer; org_content_type = urls->content_type; urls->content_type = 0; StrAllocCopy(urls->content_type, TEXT_HTML); urls->is_binary = 1; /* secret flag for mail-to save as */ /* Force layout to discard the old document and start a new one. We do this so that the pre-fetched image request won't be destroyed by a layout call to IL_DestroyImageGroup. */ viewstream = NET_StreamBuilder(format_out, urls, (MWContext *)cx); if (!viewstream) { PR_FREEIF(stream); return NULL; } buffer = PL_strdup(""); if (!buffer) { PR_FREEIF(stream); PR_FREEIF(viewstream); return NULL; } (*viewstream->put_block)(viewstream, buffer, PL_strlen(buffer)+1); PR_FREEIF(buffer); } /* !newshack */ /* Prefetch the image. We do this so that the image library can process image data even if the parser is blocked on the fake IMG tag that we send. Note that this image request will persist until the document is destroyed (when IL_DestroyImageGroup will be called.) */ image_url = (char*) PR_MALLOC(PL_strlen(urls->address) + 29); if (!image_url) { PR_FREEIF(stream); PR_FREEIF(viewstream); return NULL; } XP_SPRINTF(image_url, "internal-external-reconnect:%s", urls->address); if (!il_load_image((MWContext *)cx, image_url, urls->force_reload)) { PR_FREEIF(stream); PR_FREEIF(viewstream); return NULL; } PR_FREEIF(image_url); if (!newshack) { if (viewstream) { char *buffer = (char*) PR_MALLOC(PL_strlen(fakehtml) + PL_strlen(urls->address) + 1); if (buffer) { XP_SPRINTF(buffer, fakehtml, urls->address); (*viewstream->put_block)(viewstream, buffer, PL_strlen(buffer)); PR_FREEIF(buffer); } (*viewstream->complete)(viewstream); } /* this has to be set back for abort to work correctly */ PR_FREEIF(urls->content_type); urls->content_type = org_content_type; } /* !newshack */ return stream; } NET_StreamClass * IL_NewStream (FO_Present_Types format_out, void *type, URL_Struct *urls, OPAQUE_CONTEXT *cx) { NET_StreamClass *stream = nil; il_container *ic = nil; ilINetReader *reader = nil; ilIURL *iurl = nil; /* recover the container */ iurl = (ilIURL *)urls->fe_data; reader = iurl->GetReader(); PR_ASSERT(reader); if (reader->StreamCreated(iurl, (int)type) == PR_FALSE) { NS_RELEASE(reader); return NULL; } /* Create stream object */ if (!(stream = PR_NEWZAP(NET_StreamClass))) { ILTRACE(0,("il: MEM il_newstream")); NS_RELEASE(reader); return 0; } stream->name = "image decode"; stream->complete = il_stream_complete; stream->abort = il_abort; stream->is_write_ready = il_write_ready; stream->data_object = (void *)reader; stream->window_id = (MWContext *)cx; stream->put_block = (MKStreamWriteFunc) il_first_write; // Careful not to call NS_RELEASE until the end, because it sets reader=NULL. NS_RELEASE(reader); return stream; } IL_IMPLEMENT(PRBool) IL_PreferredStream(URL_Struct *urls) { il_container *ic = 0; IL_ImageReq *image_req; ilIURL *iurl; ilINetReader *reader; PR_ASSERT(urls); if (urls) { /* xxx this MUST be an image stream */ iurl = (ilIURL *)urls->fe_data; reader = iurl->GetReader(); ic = IL_GetNetReaderContainer(reader); NS_RELEASE(reader); PR_ASSERT(ic); if (ic) { /* * It could be that layout aborted image loading by * calling IL_FreeImage before the netlib finished * transferring data. Don't do anything. */ if (ic->state == IC_ABORT_PENDING) return PR_FALSE; /* discover if layout is blocked on this image */ for (image_req = ic->clients; image_req; image_req = image_req->next) { #ifdef MOZ_NGLAYOUT XP_ASSERT(0); #else #ifndef M12N /* XXXM12N Fixme. Observer for layout? Query mechanism for FE? */ if ((LO_BlockedOnImage(c->cx, (LO_ImageStruct*)c->client) == TRUE) || FE_ImageOnScreen(c->cx, (LO_ImageStruct*)c->client) ) #endif /* M12N */ #endif /* MOZ_NGLAYOUT */ return PR_TRUE; } } } return PR_FALSE; }