예제 #1
0
파일: kbd.c 프로젝트: Efreak/elinks
void
dispatch_special(unsigned char *text)
{
	switch (text[0]) {
		case TERM_FN_TITLE:
			if (ditrm) {
				if (ditrm->remote)
					break;

				/* If ditrm->touched_title is 0, then
				 * ditrm->orig_title should be NULL,
				 * but check it to prevent any leak.  */
				if (!ditrm->orig_title && !ditrm->touched_title)
					ditrm->orig_title = get_window_title(
						ditrm->title_codepage);
				ditrm->touched_title = 1;
			}
			/* TODO: Is it really possible to get here with
			 * ditrm == NULL, and which charset would then
			 * be most appropriate?  */
			set_window_title(text + 1,
					 ditrm ? ditrm->title_codepage
					 : get_cp_index("US-ASCII"));
			break;
		case TERM_FN_RESIZE:
			if (ditrm && ditrm->remote)
				break;

			resize_terminal_from_str(text + 1);
			break;
		case TERM_FN_TITLE_CODEPAGE:
			if (ditrm) {
				int cp = get_cp_index(text + 1);

				/* If the master sends the name of an
				 * unrecognized charset, assume only
				 * that it's ASCII compatible.  */
				if (cp == -1)
					cp = get_cp_index("US-ASCII");
				ditrm->title_codepage = cp;
			}
			break;
	}
}
예제 #2
0
파일: osdep.c 프로젝트: rkd77/elinks-tv
/** Convert a STRING XTextProperty to a string in the specified codepage.
 *
 * @return the string that the caller must free with mem_free(),
 * or NULL on error.  */
static unsigned char *
xprop_to_string(Display *display, const XTextProperty *text_prop, int to_cp)
{
	int from_cp;
	char **list = NULL;
	int count = 0;
	struct conv_table *convert_table;
	unsigned char *ret = NULL;

	/* <X11/Xlib.h> defines X_HAVE_UTF8_STRING if
	 * Xutf8TextPropertyToTextList is available.
	 *
	 * The X...TextPropertyToTextList functions return a negative
	 * error code, or Success=0, or the number of unconvertible
	 * characters.  Use the result even if some characters were
	 * unconvertible, because convert_string() can be lossy too,
	 * and it seems better to restore an approximation of the
	 * original title than to restore a default title that may be
	 * entirely different.  */
#if defined(CONFIG_UTF8) && defined(X_HAVE_UTF8_STRING)

	from_cp = get_cp_index((const unsigned char *)"UTF-8");
	if (Xutf8TextPropertyToTextList(display, text_prop, &list,
					&count) < 0)
		return NULL;

#else  /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */

	from_cp = get_cp_index((const unsigned char *)"System");
	if (XmbTextPropertyToTextList(display, text_prop, &list,
				      &count) < 0)
		return NULL;

#endif /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */

	convert_table = get_translation_table(from_cp, to_cp);
	if (count >= 1 && convert_table)
		ret = convert_string(convert_table, (unsigned char *)list[0], strlen((const char *)list[0]),
				     to_cp, CSM_NONE, NULL, NULL, NULL);

	XFreeStringList(list);
	return ret;
}
예제 #3
0
/* @bookmark_class.setProperty */
static JSBool
bookmark_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
{
	struct bookmark *bookmark;
	jsid tmp;
	unsigned char *title = NULL;
	unsigned char *url = NULL;
	int ok;

	/* This can be called if @obj if not itself an instance of the
	 * appropriate class but has one in its prototype chain.  Fail
	 * such calls.  */
	if (!JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL))
		return JS_FALSE;

	bookmark = JS_GetInstancePrivate(ctx, obj,
					 (JSClass *) &bookmark_class, NULL);

	if (!bookmark) return JS_FALSE;

	if (!JSID_IS_INT(id))
		return JS_FALSE;

	switch (JSID_TO_INT(id)) {
	case BOOKMARK_TITLE:
		if (!JS_ValueToId(ctx, *vp, &tmp))
			return JS_FALSE;
		if (!jsval_to_bookmark_string(ctx, tmp, &title))
			return JS_FALSE;
		break;
	case BOOKMARK_URL:
		if (!JS_ValueToId(ctx, *vp, &tmp))
			return JS_FALSE;
		if (!jsval_to_bookmark_string(ctx, tmp, &url))
			return JS_FALSE;
		break;
	default:
		/* Unrecognized integer property ID; someone is using
		 * the object as an array.  SMJS builtin classes (e.g.
		 * js_RegExpClass) just return JS_TRUE in this case.
		 * Do the same here.  */
		return JS_TRUE;
	}

	ok = update_bookmark(bookmark, get_cp_index("UTF-8"), title, url);
	mem_free_if(title);
	mem_free_if(url);
	return ok ? JS_TRUE : JS_FALSE;
}
예제 #4
0
파일: language.c 프로젝트: engine12/links
void set_language(int l)
{
	int i;
	unsigned char *cp;
	for (i = 0; i < T__N_TEXTS; i++) if (translations[l].t[i].code != i) {
		internal("Bad table for language %s. Run script synclang.", translations[l].t[T__LANGUAGE].name);
		return;
	}
	current_language = l;
	cp = cast_uchar translations[l].t[T__CHAR_SET].name;
	i = get_cp_index(cp);
	if (i == -1) {
		internal("Unknown charset for language %s.", translations[l].t[T__LANGUAGE].name);
		i = 0;
	}
	current_lang_charset = i;
}
예제 #5
0
파일: kbd.c 프로젝트: Efreak/elinks
static void
free_itrm(struct itrm *itrm)
{
	if (!itrm) return;

	if (!itrm->remote) {
		if (itrm->orig_title && *itrm->orig_title) {
			set_window_title(itrm->orig_title, itrm->title_codepage);

		} else if (itrm->touched_title) {
			/* Set the window title to the value of $TERM if X11
			 * wasn't compiled in. Should hopefully make at least
			 * half the users happy. (debian bug #312955) */
			unsigned char title[MAX_TERM_LEN];

			get_terminal_name(title);
			if (*title)
				set_window_title(title,
						 get_cp_index("US-ASCII"));
		}


		unhandle_terminal_resize(itrm->in.ctl);
#ifdef CONFIG_MOUSE
		disable_mouse();
#endif
		send_done_sequence(itrm->out.std, itrm->altscreen);
		tcsetattr(itrm->in.ctl, TCSANOW, &itrm->t);
	}

	mem_free_set(&itrm->orig_title, NULL);

	/* elinks -remote may not have a valid stdin if not run from a tty (bug 938) */
	if (!itrm->remote || itrm->in.std >= 0) clear_handlers(itrm->in.std);
	clear_handlers(itrm->in.sock);
	clear_handlers(itrm->out.std);
	clear_handlers(itrm->out.sock);

	kill_timer(&itrm->timer);

	if (itrm == ditrm) ditrm = NULL;
	mem_free_if(itrm->out.queue.data);
	mem_free_if(itrm->in.queue.data);
	mem_free(itrm);
}
예제 #6
0
파일: x.c 프로젝트: lince/ginga-srpp
/* initiate connection with X server */
static unsigned char * x_init_driver(unsigned char *param, unsigned char *display)
{
	XGCValues gcv;
	XSetWindowAttributes win_attr;
	XVisualInfo vinfo;
	int misordered=-1;

	n_wins=0;

#if defined(HAVE_SETLOCALE) && defined(LC_ALL)
	setlocale(LC_ALL,"");
#endif
#ifdef X_DEBUG
	{
		unsigned char txt[256];
		sprintf(txt,"x_init_driver(%s, %s)\n",param, display);
		MESSAGE(txt);
	}
#endif
	x_input_encoding=-1;
#if defined(HAVE_NL_LANGINFO) && defined(HAVE_LANGINFO_H) && defined(CODESET)
	{
		unsigned char *cp;
		cp=nl_langinfo(CODESET);
		x_input_encoding=get_cp_index(cp);
	}
#endif
	if (x_input_encoding<0)x_driver.flags|=GD_NEED_CODEPAGE;

	if (!display||!(*display))display=0;

/*
	X documentation says on XOpenDisplay(display_name) :

	display_name
		Specifies the hardware display name, which determines the dis-
		play and communications domain to be used.  On a POSIX-confor-
		mant system, if the display_name is NULL, it defaults to the
		value of the DISPLAY environment variable.

	But OS/2 has problems when display_name is NULL ...

*/
	if (!display)display=getenv("DISPLAY");
#ifndef __linux__
	/* on Linux, do not assume XWINDOW present if $DISPLAY is not set
	   --- rather open links on svgalib or framebuffer console */
	if (!display)display=":0.0";	/* needed for MacOS X */
#endif

	x_display=XOpenDisplay(display);
	if (!x_display)
	{
		unsigned char *err=init_str();
		int l=0;

		add_to_str(&err,&l,"Can't open display \"");
		add_to_str(&err,&l,display?display:(unsigned char *)"(null)");
		add_to_str(&err,&l,"\"\n");
		return err;
	}

	x_hash_table_init();

	x_bitmap_bit_order=BitmapBitOrder(x_display);
	x_fd=XConnectionNumber(x_display);
	x_screen=DefaultScreen(x_display);
	x_display_height=DisplayHeight(x_display,x_screen);
	x_display_width=DisplayWidth(x_display,x_screen);
	x_root_window=RootWindow(x_display,x_screen);

	x_default_window_width=x_display_width-50;
	x_default_window_height=x_display_height-50;

	x_driver_param=NULL;

	if (param)
	{
		char *p, *e, *f;
		int w,h;
		
		x_driver_param=stracpy(param);
		
		for (p=x_driver_param;(*p)&&(*p)!='x'&&(*p)!='X';p++);
		if (!(*p))goto done;
		*p=0;
		w=strtoul(x_driver_param,&e,10);
		h=strtoul(p+1,&f,10);
		if (!(*e)&&!(*f)&&w&&h){x_default_window_width=w;x_default_window_height=h;}
		*p='x';
		done:;
	}

	/* find best visual */
	{
#define DEPTHS 5
#define CLASSES 2
		int depths[DEPTHS]={24, 16, 15, 8, 4};
		int classes[CLASSES]={TrueColor, PseudoColor}; /* FIXME: dodelat DirectColor */
		int a,b;
		
		for (a=0;a<DEPTHS;a++)
			for (b=0;b<CLASSES;b++)
			{
				if (XMatchVisualInfo(x_display, x_screen,depths[a],classes[b], &vinfo))
				{
					x_default_visual=vinfo.visual;
					x_depth=vinfo.depth;

					/* determine bytes per pixel */
					{
						XPixmapFormatValues *pfm;
						int n,i;
						
						pfm=XListPixmapFormats(x_display,&n);
						for (i=0;i<n;i++)
							if (pfm[i].depth==x_depth)
							{
								x_bitmap_bpp=pfm[i].bits_per_pixel<8?1:((pfm[i].bits_per_pixel)>>3);
								x_bitmap_scanline_pad=(pfm[i].scanline_pad)>>3;
								XFree(pfm);
								goto bytes_per_pixel_found;
							}
						if(n) XFree(pfm);
						continue;
					}
bytes_per_pixel_found:

					/* test misordered flag */
					switch(x_depth)
					{
						case 4:
						case 8:
						if (x_bitmap_bpp!=1)break;
						if (vinfo.red_mask>=vinfo.green_mask&&vinfo.green_mask>=vinfo.blue_mask)
						{
							misordered=0;
							goto visual_found;
						}
						break;

						case 15:
						case 16:
						if (x_bitmap_bpp!=2)break;
						if (x_bitmap_bit_order==MSBFirst&&vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask)
						{
							misordered=256;
							goto visual_found;
						}
						if (x_bitmap_bit_order==MSBFirst)break;
						if (vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask)
						{
							misordered=0;
							goto visual_found;
						}
						break;

						case 24:
						if (x_bitmap_bpp!=3&&x_bitmap_bpp!=4) break;
						if (vinfo.red_mask<vinfo.green_mask&&vinfo.green_mask<vinfo.blue_mask)
						{
							misordered=256;
							goto visual_found;
						}
						if (x_bitmap_bit_order==MSBFirst&&vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask)
						{
							misordered=512;
							goto visual_found;
						}
						if (vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask)
						{
							misordered=0;
							goto visual_found;
						}
						break;
					}
				}
			}
예제 #7
0
파일: screen.c 프로젝트: rkd77/elinks-tv
/** Set screen_driver.opt according to screen_driver.type and @a term_spec.
 * Other members of @a *driver need not have been initialized.
 *
 * If you modify anything here, check whether option descriptions
 * should be updated.  */
static void
set_screen_driver_opt(struct screen_driver *driver, struct option *term_spec)
{
	const int cp = get_opt_codepage_tree(term_spec, (const unsigned char *)"charset", NULL);
	int utf8_io = get_opt_bool_tree(term_spec, (const unsigned char *)"utf_8_io", NULL);

	/* Copy all the original options from constants, so that this
	 * function need not carefully restore options one by one.  */
	copy_struct(&driver->opt, screen_driver_opts[driver->type]);

#ifdef CONFIG_COMBINE
	driver->opt.combine = get_opt_bool_tree(term_spec, (const unsigned char *)"combine", NULL);
#endif /* CONFIG_COMBINE */
#ifdef CONFIG_UTF8
	/* Force UTF-8 I/O if the UTF-8 charset is selected.  Various
	 * places assume that the terminal's charset is unibyte if
	 * UTF-8 I/O is disabled.  (bug 827) */
	if (is_cp_utf8(cp)) {
		driver->opt.utf8_cp = 1;
		utf8_io = 1;
	} else {
		driver->opt.utf8_cp = 0;
	}
#endif /* CONFIG_UTF8 */

	driver->opt.color_mode = get_opt_int_tree(term_spec, (const unsigned char *)"colors", NULL);
	driver->opt.transparent = get_opt_bool_tree(term_spec, (const unsigned char *)"transparency",
	                                            NULL);

	if (get_opt_bool_tree(term_spec, (const unsigned char *)"italic", NULL)) {
		driver->opt.italic = italic_seqs;
	} else {
		driver->opt.italic = NULL;
	}

	if (get_opt_bool_tree(term_spec, (const unsigned char *)"underline", NULL)) {
		driver->opt.underline = underline_seqs;
	} else {
		driver->opt.underline = NULL;
	}

	if (utf8_io) {
		driver->opt.charsets[0] = cp;

		/* When we're using UTF-8 I/O, we never need to switch
		 * charsets or fonts for drawing frames, because the
		 * characters encoded in UTF-8 are already unambiguous.  */
		driver->opt.frame_seqs = NULL;

		if (driver->type == TERM_LINUX || driver->type == TERM_FBTERM) {
			if (get_opt_bool_tree(term_spec, (const unsigned char *)"restrict_852", NULL))
				driver->opt.frame = frame_restrict;
			driver->opt.charsets[1] = get_cp_index((const unsigned char *)"cp437");

		} else if (driver->type == TERM_FREEBSD) {
			driver->opt.frame = frame_freebsd_u;
			driver->opt.charsets[1] = get_cp_index((const unsigned char *)"cp437");

		} else if (driver->type == TERM_VT100) {
			driver->opt.frame = frame_vt100_u;
			driver->opt.charsets[1] = get_cp_index((const unsigned char *)"cp437");

		} else if (driver->type == TERM_KOI8) {
			driver->opt.charsets[1] = get_cp_index((const unsigned char *)"koi8-r");

		} else {
#ifdef CONFIG_UTF8
			/* Don't let driver->opt.charsets[1] become
			 * UTF-8, because it is passed to cp2u(),
			 * which supports only unibyte characters.  */
			if (driver->opt.utf8_cp)
				driver->opt.charsets[1] = get_cp_index((const unsigned char *)"US-ASCII");
			else
#endif	/* CONFIG_UTF8 */
				driver->opt.charsets[1] = driver->opt.charsets[0];
		}

	} else { /* !utf8_io */
		driver->opt.charsets[0] = -1;

		if (driver->type == TERM_LINUX) {
			if (get_opt_bool_tree(term_spec, (const unsigned char *)"restrict_852", NULL))
				driver->opt.frame = frame_restrict;

			if (get_opt_bool_tree(term_spec, (const unsigned char *)"m11_hack", NULL))
				driver->opt.frame_seqs = m11_hack_frame_seqs;

		} else if (driver->type == TERM_FREEBSD) {
			if (get_opt_bool_tree(term_spec, (const unsigned char *)"m11_hack", NULL))
				driver->opt.frame_seqs = m11_hack_frame_seqs;

		} else if (driver->type == TERM_VT100) {
			driver->opt.frame = frame_vt100;
		}
 	} /* !utf8_io */
}
예제 #8
0
파일: kbd.c 프로젝트: Efreak/elinks
/** Construct the struct itrm of this process, make ::ditrm point to it,
 * set up select() handlers, and send the initial interlink packet.
 *
 * The first five parameters are file descriptors that this function
 * saves in submembers of struct itrm, and for which this function may
 * set select() handlers.  Please see the definitions of struct
 * itrm_in and struct itrm_out for further explanations.
 *
 * @param std_in	itrm_in.std: read tty device (or pipe)
 * @param std_out	itrm_out.std: write tty device (or pipe)
 * @param sock_in	itrm_in.sock
 *			- If master: == @a std_out (masterhood flag)
 *			- If slave: read socket from master
 * @param sock_out	itrm_out.sock
 *			- If master: write pipe to same process
 *			- If slave: write socket to master
 * @param ctl_in	itrm_in.ctl: control tty device
 *
 * The remaining three parameters control the initial interlink packet.
 *
 * @param init_string	A string to be passed to the master process.  Need
 *			not be null-terminated.  If @a remote == 0, this is
 *			a URI.  Otherwise, this is a remote command.
 * @param init_len	The length of init_string, in bytes.
 * @param remote	= 0 if asking the master to start a new session
 *			and display it via this process.  Otherwise,
 *			enum ::remote_session_flags.  */
void
handle_trm(int std_in, int std_out, int sock_in, int sock_out, int ctl_in,
	   void *init_string, int init_len, int remote)
{
	struct itrm *itrm;
	struct terminal_info info;
	struct interlink_event_size *size = &info.event.info.size;
	unsigned char *ts;

	memset(&info, 0, sizeof(info));

	get_terminal_size(ctl_in, &size->width, &size->height);
	info.event.ev = EVENT_INIT;
	info.system_env = get_system_env();
	info.length = init_len;

	if (remote) {
		info.session_info = remote;
		info.magic = INTERLINK_REMOTE_MAGIC;
	} else {
		info.session_info = get_cmd_opt_int("base-session");
		info.magic = INTERLINK_NORMAL_MAGIC;
	}

	itrm = mem_calloc(1, sizeof(*itrm));
	if (!itrm) return;

	itrm->in.queue.data = mem_calloc(1, ITRM_IN_QUEUE_SIZE);
	if (!itrm->in.queue.data) {
		mem_free(itrm);
		return;
	}

	ditrm = itrm;
	itrm->in.std = std_in;
	itrm->out.std = std_out;
	itrm->in.sock = sock_in;
	itrm->out.sock = sock_out;
	itrm->in.ctl = ctl_in;
	itrm->timer = TIMER_ID_UNDEF;
	itrm->remote = !!remote;

	/* If the master does not tell which charset it's using in
	 * this terminal, assume it's some ISO 8859.  Because that's
	 * what older versions of ELinks did.  */
	itrm->title_codepage = get_cp_index("ISO-8859-1");

	/* FIXME: Combination altscreen + xwin does not work as it should,
	 * mouse clicks are reportedly partially ignored. */
	if (info.system_env & (ENV_SCREEN | ENV_XWIN))
		itrm->altscreen = 1;

	if (!remote) {
		if (ctl_in >= 0) setraw(itrm, 1);
		send_init_sequence(std_out, itrm->altscreen);
		handle_terminal_resize(ctl_in, resize_terminal);
#ifdef CONFIG_MOUSE
		enable_mouse();
#endif
		handle_itrm_stdin(itrm);
	} else {
		/* elinks -remote may not have a valid stdin if not run from a tty (bug 938) */
		if (std_in >= 0) handle_itrm_stdin(itrm);
	}

	if (sock_in != std_out)
		set_handlers(sock_in, (select_handler_T) in_sock,
			     NULL, (select_handler_T) free_itrm, itrm);

	get_terminal_name(info.name);

	ts = get_cwd();
	if (ts) {
		memcpy(info.cwd, ts, int_min(strlen(ts), MAX_CWD_LEN));
		mem_free(ts);
	}

	itrm_queue_event(itrm, (char *) &info, TERMINAL_INFO_SIZE);
	itrm_queue_event(itrm, (char *) init_string, init_len);
}
예제 #9
0
파일: file.c 프로젝트: rkd77/elinks-tv
/* To reduce redundant error handling code [calls to abort_connection()]
 * most of the function is build around conditions that will assign the error
 * code to @state if anything goes wrong. The rest of the function will then just
 * do the necessary cleanups. If all works out we end up with @state being S_OK
 * resulting in a cache entry being created with the fragment data generated by
 * either reading the file content or listing a directory. */
void
file_protocol_handler(struct connection *connection)
{
	unsigned char *redirect_location = NULL;
	struct string page, name;
	struct connection_state state;
	int set_dir_content_type = 0;

	if (get_cmd_opt_bool((const unsigned char *)"anonymous")) {
		if (strcmp((const char *)connection->uri->string, "file:///dev/stdin")
		    || isatty(STDIN_FILENO)) {
			abort_connection(connection,
					 connection_state(S_FILE_ANONYMOUS));
			return;
		}
	}

#ifdef CONFIG_CGI
	if (!execute_cgi(connection)) return;
#endif /* CONFIG_CGI */

	/* Treat /dev/stdin in special way */
	if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) {
		int fd = open("/dev/stdin", O_RDONLY);

		if (fd == -1) {
			abort_connection(connection, connection_state(-errno));
			return;
		}
		set_nonblocking_fd(fd);
		if (!init_http_connection_info(connection, 1, 0, 1)) {
			abort_connection(connection, connection_state(S_OUT_OF_MEM));
			close(fd);
			return;
		}
		connection->socket->fd = fd;
		connection->data_socket->fd = -1;
		read_from_stdin(connection);
		return;
	}


	/* This function works on already simplified file-scheme URI pre-chewed
	 * by transform_file_url(). By now, the function contains no hostname
	 * part anymore, possibly relative path is converted to an absolute one
	 * and uri->data is just the final path to file/dir we should try to
	 * show. */

	if (!init_string(&name)
	    || !add_uri_to_string(&name, connection->uri, URI_PATH)) {
		done_string(&name);
		abort_connection(connection, connection_state(S_OUT_OF_MEM));
		return;
	}

	decode_uri_string(&name);

	/* In Win32, file_is_dir seems to always return 0 if the name
	 * ends with a directory separator.  */
	if ((name.length > 0 && dir_sep(name.source[name.length - 1]))
	    || file_is_dir(name.source)) {
		/* In order for global history and directory listing to
		 * function properly the directory url must end with a
		 * directory separator. */
		if (name.source[0] && !dir_sep(name.source[name.length - 1])) {
			redirect_location = (unsigned char *)STRING_DIR_SEP;
			state = connection_state(S_OK);
		} else {
			state = list_directory(connection, name.source, &page);
			set_dir_content_type = 1;
		}

	} else {
		state = read_encoded_file(&name, &page);
		/* FIXME: If state is now S_ENCODE_ERROR we should try loading
		 * the file undecoded. --jonas */
	}

	done_string(&name);

	if (is_in_state(state, S_OK)) {
		struct cache_entry *cached;

		/* Try to add fragment data to the connection cache if either
		 * file reading or directory listing worked out ok. */
		cached = connection->cached = get_cache_entry(connection->uri);
		if (!connection->cached) {
			if (!redirect_location) done_string(&page);
			state = connection_state(S_OUT_OF_MEM);

		} else if (redirect_location) {
			if (!redirect_cache(cached, redirect_location, 1, 0))
				state = connection_state(S_OUT_OF_MEM);

		} else {
			add_fragment(cached, 0, page.source, page.length);
			connection->from += page.length;

			if (!cached->head && set_dir_content_type) {
				unsigned char *head;

				/* If the system charset somehow
				 * changes after the directory listing
				 * has been generated, it should be
				 * parsed with the original charset.  */
				head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=",
						  get_cp_mime_name(get_cp_index((const unsigned char *)"System")),
						  "\r\n", (unsigned char *) NULL);

				/* Not so gracefully handle failed memory
				 * allocation. */
				if (!head)
					state = connection_state(S_OUT_OF_MEM);

				/* Setup directory listing for viewing. */
				mem_free_set(&cached->head, head);
			}

			done_string(&page);
		}
	}

	abort_connection(connection, state);
}