Index: include/config.h
===================================================================
RCS file: /home/cvs/repository/epic4/include/config.h,v
retrieving revision 1.32
diff -u -3 -p -r1.32 config.h
--- include/config.h	26 Dec 2003 19:14:49 -0000	1.32
+++ include/config.h	4 Mar 2004 21:00:28 -0000
@@ -307,6 +307,11 @@
 #undef ANONYMOUS_COMPILE
 
 /*
+ * Define this to enable support for multi-byte characters.
+ */
+#define MULTIBYTE_SUPPORT
+
+/*
  * The /LOAD path is now generated at runtime, rather than at compile time.
  * This is to allow you to change IRCLIB and have its script library be
  * resepected without having to change IRCPATH as well.  This is a printf
@@ -511,6 +516,7 @@
 #define DEFAULT_TERM_DOES_BRIGHT_BLINK 0
 #define DEFAULT_UNDERLINE_VIDEO 1
 #define DEFAULT_USERINFO "EPIC4 -- Get your laundry brighter, not just whiter!"
+#define DEFAULT_UTF8 0
 #define DEFAULT_VERBOSE_CTCP 1
 #define DEFAULT_WORD_BREAK ".,; \t"
 #define DEFAULT_WSERV_TYPE "screen"
Index: include/irc.h
===================================================================
RCS file: /home/cvs/repository/epic4/include/irc.h,v
retrieving revision 1.25
diff -u -3 -p -r1.25 irc.h
--- include/irc.h	3 Jan 2004 19:57:25 -0000	1.25
+++ include/irc.h	4 Mar 2004 21:00:28 -0000
@@ -80,6 +80,21 @@
 #define REALNAME_LEN 50
 #define PATH_LEN 1024
 
+/* defines to help out with multibyte support */
+#ifdef MULTIBYTE_SUPPORT
+#define WIDE_CHAR wchar_t
+#define WIDE_UCHAR wchar_t
+#define strlen_wc(src)		wcslen(src)
+#define strwidth_wc(src)	my_wcswidth(src, wcslen(src))
+#define NUL_CHAR		L'\0'
+#else
+#define WIDE_CHAR char
+#define WIDE_UCHAR unsigned char
+#define strlen_wc(src)		strlen(src)
+#define strwidth_wc(src)	strlen(src)
+#define NUL_CHAR		'\0'
+#endif
+
 /* irc.c's global variables */
 extern		int	away_set;
 extern		int	background;
@@ -106,7 +121,7 @@ extern		int	waiting_in;
 extern		char *	args_str;
 extern		char *	cannot_open;
 extern const	char *	compile_info;
-extern		char *	cut_buffer;
+extern		WIDE_CHAR *cut_buffer;
 extern		char *	default_channel;
 extern		char	empty_string[];
 extern		char	space[];
Index: include/irc_std.h
===================================================================
RCS file: /home/cvs/repository/epic4/include/irc_std.h,v
retrieving revision 1.17
diff -u -3 -p -r1.17 irc_std.h
--- include/irc_std.h	1 Aug 2003 01:08:54 -0000	1.17
+++ include/irc_std.h	4 Mar 2004 21:00:28 -0000
@@ -113,8 +113,15 @@
 # endif
 #endif
 
-
-
+/* Include headers required for multibyte support */
+#ifdef MULTIBYTE_SUPPORT
+/* broken */
+/* #define _XOPEN_SOURCE 500 */ /* SUSv2 - for wcwidth(), wcswidth() */
+#include <wchar.h>
+#include <wctype.h>
+#include <locale.h>
+#include <iconv.h>
+#endif
 
 /*
  * First try to figure out if we can use GNU CC special features...
Index: include/ircaux.h
===================================================================
RCS file: /home/cvs/repository/epic4/include/ircaux.h,v
retrieving revision 1.60
diff -u -3 -p -r1.60 ircaux.h
--- include/ircaux.h	8 Jan 2004 20:14:57 -0000	1.60
+++ include/ircaux.h	4 Mar 2004 21:00:28 -0000
@@ -183,6 +183,9 @@ char *  strlopencat_c		(char *dest, size
 int     is_string_empty 	(const char *str);
 
 char *	malloc_strcpy_c		(char **, const char *, size_t *);
+#ifdef MULTIBYTE_SUPPORT
+wchar_t *malloc_wcscpy_c	(wchar_t **, const wchar_t *, size_t *);
+#endif
 char *	malloc_strcat_c		(char **, const char *, size_t *);
 char *	malloc_strdup 		(const char *);
 char *	malloc_strdup2 		(const char *, const char *);
@@ -193,6 +196,11 @@ char *	malloc_strcat_word_c    (char **,
 char *	malloc_sprintf 		(char **, const char *, ...) __A(2);
 
 #define malloc_strcpy(x,y) malloc_strcpy_c((x),(y),NULL)
+#ifdef MULTIBYTE_SUPPORT
+#define malloc_wcscpy(d, s)	malloc_wcscpy_c(d, s, NULL)
+#else
+#define malloc_wcscpy(d, s)	malloc_strcpy_c(d, s, NULL)
+#endif
 #define malloc_strcat(x,y) malloc_strcat_c((x),(y),NULL)
 #define malloc_strcat2(x,y,z) malloc_strcat2_c((x),(y),(z),NULL)
 #define malloc_strcat_wordlist(x,y,z) malloc_strcat_wordlist_c((x),(y),(z),NULL)
Index: include/screen.h
===================================================================
RCS file: /home/cvs/repository/epic4/include/screen.h,v
retrieving revision 1.7
diff -u -3 -p -r1.7 screen.h
--- include/screen.h	9 May 2003 04:29:52 -0000	1.7
+++ include/screen.h	4 Mar 2004 21:00:29 -0000
@@ -26,7 +26,7 @@ typedef struct PromptStru
 	struct	PromptStru	*next;
 }	WaitPrompt;
 
-
+#if 0 /* unused */
 typedef struct	PhysicalTTY
 {
 	/* Output stuff */
@@ -71,7 +71,7 @@ typedef struct	PhysicalTTY
 	int	old_co;
 	int	old_li;
 }	Pty;
-
+#endif
 
 typedef	struct	ScreenStru
 {
@@ -96,12 +96,15 @@ struct	ScreenStru *next;		/* Previous sc
 	int	wserv_version;		/* The version of wserv talking to */
 
 	/* Input line and prompt stuff */
-	char	input_buffer[INPUT_BUFFER_SIZE+1];
+	WIDE_CHAR input_buffer[INPUT_BUFFER_SIZE+1];
 					/* Current user input for us */
 	int	buffer_pos;		/* Where on input line cursor is */
 	int	buffer_min_pos;		/* First position after prompt */
 	int	input_cursor;		/* Where the cursor is on input line */
 	int	input_visible;
+#ifdef MULTIBYTE_SUPPORT
+	int	input_visible_char;	/* Character number for input_visible */
+#endif
 	int	input_zone_len;
 	int	input_start_zone;
 	int	input_end_zone;
@@ -110,7 +113,7 @@ struct	ScreenStru *next;		/* Previous sc
 	int	input_prompt_malloc;
 	int	input_line;
 
-	char	saved_input_buffer[INPUT_BUFFER_SIZE+1];
+	WIDE_CHAR saved_input_buffer[INPUT_BUFFER_SIZE+1];
 	int	saved_buffer_pos;
 	int	saved_min_buffer_pos;
 
Index: include/term.h
===================================================================
RCS file: /home/cvs/repository/epic4/include/term.h,v
retrieving revision 1.4
diff -u -3 -p -r1.4 term.h
--- include/term.h	22 Jul 2003 21:12:53 -0000	1.4
+++ include/term.h	4 Mar 2004 21:00:29 -0000
@@ -28,6 +28,20 @@ extern	int	meta_mode;
 #ifdef __need_putchar_x__
 __inline__ 
 static int putchar_x (int c) { return fputc((int) c, current_ftarget ); }
+#ifdef MULTIBYTE_SUPPORT
+__inline__ 
+static int putwchar_x (wchar_t c) {
+	char buf[MB_LEN_MAX];
+
+	memset(buf, 0, sizeof(buf));
+	/* FIXME: wcrtomb */
+	wctomb(buf, c);
+	return fputs(buf, current_ftarget );
+}
+#define putchar_x_wc(c) putwchar_x(c)
+#else
+#define putchar_x_wc(c) puchar_x(c)
+#endif
 #endif
 
 #ifdef __need_term_flush__
@@ -632,9 +646,9 @@ int	tputs_x(char *);
 	int		term_init 		(void);
 	int		term_resize 		(void);
 	void		term_pause 		(char, char *);
-	void		term_putchar 		(unsigned char);
+	void		term_putchar 		(WIDE_UCHAR);
 	void		term_scroll 		(int, int, int);
-	void		term_insert 		(unsigned char);
+	void		term_insert 		(WIDE_UCHAR);
 	void		term_delete 		(int);
 	void		term_repeat		(unsigned char, int);
 	void		term_right		(int);
Index: include/vars.h
===================================================================
RCS file: /home/cvs/repository/epic4/include/vars.h,v
retrieving revision 1.26
diff -u -3 -p -r1.26 vars.h
--- include/vars.h	26 Dec 2003 19:14:49 -0000	1.26
+++ include/vars.h	4 Mar 2004 21:00:29 -0000
@@ -215,6 +215,7 @@ enum VAR_TYPES {
 	UNDERLINE_VIDEO_VAR,
 	USER_INFO_VAR,
 #define	USERINFO_VAR USER_INFO_VAR
+	UTF8_VAR,
 	VERBOSE_CTCP_VAR,
 	WORD_BREAK_VAR,
 	WSERV_PATH_VAR,
Index: source/functions.c
===================================================================
RCS file: /home/cvs/repository/epic4/source/functions.c,v
retrieving revision 1.153
diff -u -3 -p -r1.153 functions.c
--- source/functions.c	20 Feb 2004 23:40:22 -0000	1.153
+++ source/functions.c	4 Mar 2004 21:00:37 -0000
@@ -852,7 +852,21 @@ static int	func_exist (char *name)
 
 /* built in expando functions */
 static	char	*alias_line 		(void) { return malloc_strdup(get_input()); }
-static	char	*alias_buffer 		(void) { return malloc_strdup(cut_buffer); }
+static	char	*alias_buffer 		(void)
+{
+#ifdef MULTIBYTE_SUPPORT
+	char *buf;
+	int len = wcstombs(NULL, cut_buffer, 0);
+	
+	buf = new_malloc(len + 1);
+	/* FIXME: use wcsrtombs, check error, and skip unconvertable chars */
+	wcstombs(buf, cut_buffer, len);
+	
+	return buf;
+#else
+	return malloc_strdup(cut_buffer);
+#endif
+}
 static	char	*alias_time 		(void) { return malloc_strdup(get_clock()); }
 static	char	*alias_dollar 		(void) { return malloc_strdup("$"); }
 static	char	*alias_detected 	(void) { return malloc_strdup(last_notify_nick); }
Index: source/input.c
===================================================================
RCS file: /home/cvs/repository/epic4/source/input.c,v
retrieving revision 1.19
diff -u -3 -p -r1.19 input.c
--- source/input.c	3 Feb 2004 19:36:52 -0000	1.19
+++ source/input.c	4 Mar 2004 21:00:37 -0000
@@ -64,6 +64,19 @@
 #include <sys/ioctl.h>		/* XXX ugh */
 
 /*
+ * Defines to use wide-character alternatives if requested (done this way
+ * to disturb the code as little as possible)
+ */
+#ifdef MULTIBYTE_SUPPORT
+#define strlcat(dest, src, len)	strlcat_wide(dest, src, len)
+#define strlcpy(dest, src, len)	strlcpy_wide(dest, src, len)
+#define ov_strcpy(dest, src)	wmemmove(dest, src, wcslen(src) + 1)
+#define LOCAL_WCOPY(x)		wcscpy(alloca((wcslen(x) + 1) * sizeof(wchar_t)), x)
+#else
+#define LOCAL_WCOPY(x)		LOCAL_COPY(x)
+#endif
+
+/*
  * This is how close you have to be to the edge of the screen before the
  * input line scrolls to the adjacent zone.  A detailed discussion of zones
  * can be found below.
@@ -89,9 +102,14 @@
 #define MIN_CHAR 		INPUT_BUFFER[MIN_POS]
 #define PREV_CHAR 		INPUT_BUFFER[THIS_POS-1]
 #define NEXT_CHAR 		INPUT_BUFFER[THIS_POS+1]
-#define ADD_TO_INPUT(x) 	strlcat(INPUT_BUFFER, (x), sizeof INPUT_BUFFER);
+#define ADD_TO_INPUT(x) 	strlcat(INPUT_BUFFER, (x), INPUT_BUFFER_SIZE);
 #define INPUT_ONSCREEN 		current_screen->input_visible
-#define INPUT_VISIBLE 		INPUT_BUFFER[INPUT_ONSCREEN]
+#ifdef MULTIBYTE_SUPPORT
+#define INPUT_CHAR_ONSCREEN	current_screen->input_visible_char
+#else
+#define INPUT_CHAR_ONSCREEN	INPUT_ONSCREEN
+#endif
+#define INPUT_VISIBLE 		INPUT_BUFFER[INPUT_CHAR_ONSCREEN]
 #define ZONE			current_screen->input_zone_len
 #define START_ZONE 		current_screen->input_start_zone
 #define END_ZONE 		current_screen->input_end_zone
@@ -101,15 +119,86 @@
 #define CUT_BUFFER		cut_buffer
 #define SET_CUT_BUFFER(x)	malloc_strcpy(&CUT_BUFFER, x);
 
+#ifdef MULTIBYTE_SUPPORT
+/*
+ * These are wrappers around wcwidth() that properly handle control
+ * characters (i.e. they know we'll be escaping them, and how long the
+ * escaped versions will be.)
+ */
+static __inline__ int my_wcwidth(wchar_t in)
+{
+	if (!iswprint(in)) {
+		char buf[MB_LEN_MAX];
+
+		/* delete is always an inverted ? */
+		if (in == L'\x7f')
+			return 1;
+
+		/* figure out how long the escape will be */
+		return wctomb(buf, in);
+	}
+	return wcwidth(in);
+}
+
+static int my_wcswidth(const wchar_t *in, size_t len)
+{
+	int x;
+	int ret = 0;
+	
+	for (x = 0; x < len; x++) {
+		ret += my_wcwidth(in[x]);
+	}
+	return ret;
+}
+
+static size_t strlcat_wide(wchar_t *dest, const wchar_t *src, size_t len)
+{
+	size_t ret;
+	
+	ret = wcslen(dest) + wcslen(src);
+	len -= wcslen(dest);
+	
+	if (len > 0) {
+		wcsncat(dest, src, len - 1);
+		dest[len - 1] = L'\0';
+	}
+	
+	return ret;
+}
+
+static size_t strlcpy_wide(wchar_t *dest, const wchar_t *src, size_t len)
+{
+	if (len > 0) {
+		wcsncpy(dest, src, len - 1);
+		dest[len - 1] = L'\0';
+	}
+	return wcslen(src);
+}
+#endif
+
 /* XXXX Only used here anyhow XXXX */
-static int 	safe_puts (char *str, int len, int echo) 
+static int 	safe_puts (WIDE_CHAR *str, int len, int echo) 
 {
 	int i = 0;
+#ifdef MULTIBYTE_SUPPORT
+	int width;
+#endif
 
-	while (*str && i < len)
+	while (*str != NUL_CHAR && i < len)
 	{
+#ifdef MULTIBYTE_SUPPORT
+		/* rain - use len as the number of char cells to use */
+		width = my_wcwidth(*str);
+		if (i + width > len)
+			break;
+#endif
 		term_putchar(*str);
-		str++, i++;
+		str++;
+#ifdef MULTIBYTE_SUPPORT
+		i += width;
+#else
+		i++;
+#endif
 	}
 	return i;
 }
@@ -360,7 +449,37 @@ void	update_input (int update)
 	 * If we have moved to an different "zone" since last time, we want to
 	 * 	completely redraw the input line.
 	 */
+#ifdef MULTIBYTE_SUPPORT
+	START_ZONE = ((INPUT_PROMPT_LEN + my_wcswidth(INPUT_BUFFER, THIS_POS) - WIDTH) / ZONE) * ZONE + WIDTH;
+	/*
+	 * START_ZONE is in char cells, so we need to calculate the number
+	 * of actual characters as well (for the buffer offset.)  We take
+	 * the number of char cells and subtract off the width of each
+	 * character until we've found how many chars there are.  I hate
+	 * this method. 
+	 */
+	len = START_ZONE - INPUT_PROMPT_LEN;
+	INPUT_CHAR_ONSCREEN = 0;
+	
+	while (len > 0 && len > my_wcwidth(INPUT_VISIBLE) && INPUT_CHAR_ONSCREEN < THIS_POS) {
+		len -= my_wcwidth(INPUT_VISIBLE);
+		INPUT_CHAR_ONSCREEN++;
+	}
+	
+	if (START_ZONE == WIDTH)
+		INPUT_CHAR_ONSCREEN = 0;
+	else {
+		/*
+		 * we're putting WIDTH starting chars at the left--use WIDTH
+		 * character cells instead of characters
+		 */
+		
+		for (len = WIDTH; len > 0; INPUT_CHAR_ONSCREEN--)
+			len -= my_wcwidth(INPUT_VISIBLE);
+	}
+#else
 	START_ZONE = ((INPUT_PROMPT_LEN + THIS_POS - WIDTH) / ZONE) * ZONE + WIDTH;
+#endif
 	END_ZONE = START_ZONE + ZONE;
 
 	if (old_zone != START_ZONE)
@@ -385,10 +504,17 @@ void	update_input (int update)
 	 * And the cursor is simply how many characters away THIS_POS is
 	 * from the first column on the screen.
 	 */
+#ifdef MULTIBYTE_SUPPORT
+	if (INPUT_ONSCREEN == 0)
+		INPUT_CURSOR = INPUT_PROMPT_LEN + my_wcswidth(INPUT_BUFFER, THIS_POS);
+	else
+		INPUT_CURSOR = my_wcswidth(&(INPUT_VISIBLE), THIS_POS - INPUT_CHAR_ONSCREEN);
+#else
 	if (INPUT_ONSCREEN == 0)
 		INPUT_CURSOR = INPUT_PROMPT_LEN + THIS_POS;
 	else
 		INPUT_CURSOR = THIS_POS - INPUT_ONSCREEN;
+#endif
 
 	/*
 	 * If the cursor moved, or if we're supposed to do a full update,
@@ -460,11 +586,15 @@ void	update_input (int update)
 		 * and then output it.
 		 */
 		term_move_cursor(INPUT_CURSOR, INPUT_LINE);
+#ifdef MULTIBYTE_SUPPORT
+		max = last_input_screen->co - (my_wcswidth(INPUT_BUFFER, THIS_POS) - INPUT_ONSCREEN);
+#else
 		max = last_input_screen->co - (THIS_POS - INPUT_ONSCREEN);
+#endif
 		if (INPUT_ONSCREEN == 0 && INPUT_PROMPT && *INPUT_PROMPT)
 			max -= INPUT_PROMPT_LEN;
 
-		if ((len = strlen(&(THIS_CHAR))) > max)
+		if ((len = strwidth_wc(&(THIS_CHAR))) > max)
 			len = max;
 		safe_puts(&(THIS_CHAR), len, do_echo);
 		term_clear_to_eol();
@@ -499,7 +629,7 @@ void 	change_input_prompt (int direction
 	/* XXXXXX THIS is totaly wrong. XXXXXX */
 	if (!last_input_screen->promptlist)
 	{
-		strlcpy(INPUT_BUFFER, last_input_screen->saved_input_buffer, sizeof INPUT_BUFFER);
+		strlcpy(INPUT_BUFFER, last_input_screen->saved_input_buffer, INPUT_BUFFER_SIZE);
 		THIS_POS = last_input_screen->saved_buffer_pos;
 		MIN_POS = last_input_screen->saved_min_buffer_pos;
 		*last_input_screen->saved_input_buffer = 0;
@@ -512,10 +642,10 @@ void 	change_input_prompt (int direction
 
 	else if (!last_input_screen->promptlist->next)
 	{
-		strlcpy(last_input_screen->saved_input_buffer, INPUT_BUFFER, sizeof INPUT_BUFFER);
+		strlcpy(last_input_screen->saved_input_buffer, INPUT_BUFFER, INPUT_BUFFER_SIZE);
 		last_input_screen->saved_buffer_pos = THIS_POS;
 		last_input_screen->saved_min_buffer_pos = MIN_POS;
-		*INPUT_BUFFER = 0;
+		*INPUT_BUFFER = NUL_CHAR;
 		THIS_POS = MIN_POS = 0;
 	}
 
@@ -525,21 +655,56 @@ void 	change_input_prompt (int direction
 /* input_move_cursor: moves the cursor left or right... got it? */
 void	input_move_cursor (int dir)
 {
+#ifdef MULTIBYTE_SUPPORT
+	int width;
+#endif
+
 	cursor_to_input();
 	if (dir)
 	{
+#ifdef MULTIBYTE_SUPPORT
+		again_right:
+#endif
 		if (THIS_CHAR)
 		{
+#ifdef MULTIBYTE_SUPPORT
+			width = my_wcwidth(THIS_CHAR);
+
+			THIS_POS++;
+
+			/* skip over any 0-length chars */
+			if (width == 0)
+				goto again_right;
+			/* move the correct number of char cells */
+			while (width-- > 0)
+				term_cursor_right();
+#else
 			THIS_POS++;
 			term_cursor_right();
+#endif
 		}
 	}
 	else
 	{
+#ifdef MULTIBYTE_SUPPORT
+		again_left:
+#endif
 		if (THIS_POS > MIN_POS)
 		{
 			THIS_POS--;
+#ifdef MULTIBYTE_SUPPORT
+			width = my_wcwidth(THIS_CHAR);
+			
+			/* skip over any zero-width chars */
+			if (width == 0)
+				goto again_left;
+
+			/* move the correct number of char cells */
+			while (width-- > 0)
+				term_cursor_left();
+#else
 			term_cursor_left();
+#endif
 		}
 	}
 	update_input(NO_UPDATE);
@@ -551,10 +716,24 @@ void	input_move_cursor (int dir)
  */
 void	set_input (char *str)
 {
+#ifdef MULTIBYTE_SUPPORT
+	/* convert from the locale charset */
+	mbstowcs(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
+#else
+	strlcpy(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
+#endif
+	THIS_POS = strlen_wc(INPUT_BUFFER);
+	update_input(UPDATE_ALL);
+}
+
+#ifdef MULTIBYTE_SUPPORT
+static void	set_input_wc (wchar_t *str)
+{
 	strlcpy(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
-	THIS_POS = strlen(INPUT_BUFFER);
+	THIS_POS = strlen_wc(INPUT_BUFFER);
 	update_input(UPDATE_ALL);
 }
+#endif
 
 /*
  * get_input: returns a pointer to the input buffer.  Changing this will
@@ -563,13 +742,27 @@ void	set_input (char *str)
  */
 char *	get_input (void)
 {
+#ifdef MULTIBYTE_SUPPORT
+	/* when we're doing multibyte, we convert into a static buffer */
+	static char buf[INPUT_BUFFER_SIZE + 1];
+	wchar_t *min = &MIN_CHAR;
+	mbstate_t ps;
+	
+	memset(&ps, 0, sizeof(ps));
+	/* FIXME: check result and mangle past unprintable chars */
+	wcsrtombs(buf, (const wchar_t **)&min, sizeof(buf) - 1, &ps);
+	buf[INPUT_BUFFER_SIZE] = '\0';
+	
+	return buf;
+#else
 	return &MIN_CHAR;
+#endif
 }
 
 /* init_input: initialized the input buffer by clearing it out */
 void	init_input (void)
 {
-	*INPUT_BUFFER = 0;
+	*INPUT_BUFFER = NUL_CHAR;
 	THIS_POS = MIN_POS;
 }
 
@@ -599,7 +792,11 @@ void	set_input_prompt (const void *stuff
 }
 
 
+#ifdef MULTIBYTE_SUPPORT
+#define WHITESPACE(x) (iswspace(x) || iswpunct(x))
+#else
 #define WHITESPACE(x) (my_isspace(x) || ispunct(x))
+#endif
 
 /* 
  * Why did i put these in this file?  I dunno.  But i do know that the ones 
@@ -672,8 +869,14 @@ static void	input_delete_char_from_scree
 		/*
 		 * Delete the character.  This is the simple part.
 		 */
+#ifdef MULTIBYTE_SUPPORT
+		/* delete the appropriate number of char cells */
+		pos = my_wcwidth(THIS_CHAR);
+		if (pos > 0)
+			term_delete(pos);
+#else
 		term_delete(1);
-
+#endif
 		/*
 		 * So right now we have a blank space at the right of the
 		 * screen.  If there is a character in the input buffer that
@@ -684,7 +887,7 @@ static void	input_delete_char_from_scree
 		else
 			pos = INPUT_ONSCREEN + last_input_screen->co - 1;
 
-		if (pos < (int)strlen(INPUT_BUFFER))
+		if (pos < (int)strlen_wc(INPUT_BUFFER))
 		{
 			term_move_cursor(last_input_screen->co - 1, INPUT_LINE);
 			term_putchar(INPUT_BUFFER[pos]);
@@ -703,6 +906,9 @@ static void	input_delete_char_from_scree
  */
 BUILT_IN_BINDING(input_delete_character)
 {
+#ifdef MULTIBYTE_SUPPORT
+	wchar_t *p;
+#endif
 	cursor_to_input();
 
 	/*
@@ -716,8 +922,19 @@ BUILT_IN_BINDING(input_delete_character)
 	 * Remove the current character from the logical buffer
 	 * and also from the screen.
 	 */
+#ifdef MULTIBYTE_SUPPORT
+	/* delete from the screen first (because we need the width) */
+	input_delete_char_from_screen();
+
+	/* skip over any zero-width chars */
+	p = &NEXT_CHAR;
+	while (*p != L'\0' && my_wcwidth(*p) == 0)
+		p++;
+	ov_strcpy(&THIS_CHAR, p);
+#else
 	ov_strcpy(&THIS_CHAR, &NEXT_CHAR);
 	input_delete_char_from_screen();
+#endif
 }
 
 
@@ -760,7 +977,7 @@ BUILT_IN_BINDING(input_beginning_of_line
 BUILT_IN_BINDING(input_end_of_line)
 {
 	cursor_to_input();
-	THIS_POS = strlen(INPUT_BUFFER);
+	THIS_POS = strlen_wc(INPUT_BUFFER);
 	update_input(UPDATE_JUST_CURSOR);
 }
 
@@ -771,30 +988,30 @@ BUILT_IN_BINDING(input_end_of_line)
  */
 static void	cut_input (int anchor)
 {
-	char *	buffer;
-	size_t	size;
+	WIDE_CHAR *	buffer;
+	size_t		size;
 
 	if (anchor < THIS_POS)
 	{
 		size = THIS_POS - anchor;
-		buffer = alloca(size + 1);
+		buffer = alloca((size + 1) * sizeof(WIDE_CHAR));
 		strlcpy(buffer, &INPUT_BUFFER[anchor], size + 1);
-		malloc_strcpy(&cut_buffer, buffer);
+		malloc_wcscpy(&cut_buffer, buffer);
 
-		buffer = LOCAL_COPY(&THIS_CHAR);
-		INPUT_BUFFER[anchor] = 0;
+		buffer = LOCAL_WCOPY(&THIS_CHAR);
+		INPUT_BUFFER[anchor] = NUL_CHAR;
 		ADD_TO_INPUT(buffer);
 		THIS_POS = anchor;
 	}
 	else
 	{
 		size = anchor - THIS_POS;
-		buffer = alloca(size + 1);
+		buffer = alloca((size + 1) * sizeof(WIDE_CHAR));
 		strlcpy(buffer, &THIS_CHAR, size + 1);
-		malloc_strcpy(&cut_buffer, buffer);
+		malloc_wcscpy(&cut_buffer, buffer);
 
-		buffer = LOCAL_COPY(&INPUT_BUFFER[anchor]);
-		THIS_CHAR = 0;
+		buffer = LOCAL_WCOPY(&INPUT_BUFFER[anchor]);
+		THIS_CHAR = NUL_CHAR;
 		ADD_TO_INPUT(buffer);
 	}
 
@@ -824,7 +1041,11 @@ BUILT_IN_BINDING(input_delete_to_previou
 		return;
 
 	anchor = THIS_POS;
+#ifdef MULTIBYTE_SUPPORT
+	while (THIS_POS > MIN_POS && !iswspace(PREV_CHAR))
+#else
 	while (THIS_POS > MIN_POS && !my_isspace(PREV_CHAR))
+#endif
 		backward_character(0, NULL);
 	cut_input(anchor);
 }
@@ -873,14 +1094,49 @@ BUILT_IN_BINDING(input_delete_next_word)
 BUILT_IN_BINDING(input_add_character)
 {
 	int	display_flag = NO_UPDATE;
+	WIDE_CHAR realkey;
+#ifdef MULTIBYTE_SUPPORT
+	size_t res;
+	static mbstate_t ps; /* FIXME */
+#endif
 
 	cursor_to_input();
 
+#ifdef MULTIBYTE_SUPPORT
+	if ((res = mbrtowc(&realkey, &key, 1, &ps)) == (size_t)-2)
+		return; /* incomplete multibyte sequence */
+
+	/* complete or invalid, clear state */
+	memset(&ps, 0, sizeof(ps));
+
+	if (res == (size_t)-1) {
+		/* invalid multibyte sequence - FIXME? */
+		return;
+	}
+#else
+	realkey = key;
+#endif
+
 	if (last_input_screen->promptlist)
 		term_echo(last_input_screen->promptlist->echo);
 
 	/* Don't permit the input buffer to get too big. */
+#ifdef MULTIBYTE_SUPPORT
+	/*
+	 * We calculate with the byte length, since we're checking against
+	 * the ircd buffer length here
+	 */
+	/* FIXME: use wcsrtombs, skip and mangle unprintable chars */
+	/*
+	 * FIXME: behavior isn't quite the same -- vanilla lets you
+	 * insert (and kill the end of the buffer) if you're not at
+	 * the end when you type.  That behavior may be a bug, though.
+	 */
+	
+	if (wcstombs(NULL, INPUT_BUFFER, THIS_POS) >= INPUT_BUFFER_SIZE)
+#else
 	if (THIS_POS >= INPUT_BUFFER_SIZE)
+#endif
 	{
 		term_echo(1);
 		return;
@@ -894,24 +1150,25 @@ BUILT_IN_BINDING(input_add_character)
 		 */
 		if (THIS_CHAR)
 		{
-			char	*ptr;
+			WIDE_CHAR	*ptr;
 
 			/*
 			 * Add to logical buffer
 			 */
-			ptr = LOCAL_COPY(&(THIS_CHAR));
-			THIS_CHAR = key;
-			NEXT_CHAR = 0;
+			ptr = LOCAL_WCOPY(&(THIS_CHAR));
+			THIS_CHAR = realkey;
+
+			NEXT_CHAR = NUL_CHAR;
 			ADD_TO_INPUT(ptr);
 
 			/*
 			 * Add to display screen
 			 */
 			if (termfeatures & TERM_CAN_INSERT)
-				term_insert(key);
+				term_insert(realkey);
 			else
 			{
-				term_putchar(key);
+				term_putchar(realkey);
 				if (NEXT_CHAR)
 					display_flag = UPDATE_FROM_CURSOR;
 				else
@@ -923,21 +1180,83 @@ BUILT_IN_BINDING(input_add_character)
 			/*
 			 * Add to logical buffer
 			 */
-			THIS_CHAR = key;
-			NEXT_CHAR = 0;
+			THIS_CHAR = realkey;
+			NEXT_CHAR = NUL_CHAR;
 
 			/* Add to display screen */
-			term_putchar(key);
+			term_putchar(realkey);
 		}
 	}
 
 	/* Overstrike mode.  Much simpler. */
+	/* unless we need to deal with different character widths. */
 	else
 	{
+#ifdef MULTIBYTE_SUPPORT
+		wchar_t *p;
+#endif
 		if (THIS_CHAR == 0)
-			NEXT_CHAR = 0;
-		THIS_CHAR = key;
-		term_putchar(key);
+			NEXT_CHAR = NUL_CHAR;
+
+#ifdef MULTIBYTE_SUPPORT
+		/* replacing a multibyte char, redraw the rest of the line */
+		if (my_wcwidth(THIS_CHAR) > 1)
+			display_flag = UPDATE_FROM_CURSOR;
+		/*
+		 * if we're inserting a wide char and our term supports insert
+		 * and delete, delete the char we're removing so that we can
+		 * use insert mode (more efficient.)  we have to do it here
+		 * so that input_delete_char_from_screen() knows the width
+		 * of the char we're deleting.
+		 */
+		if (my_wcwidth(realkey) > 1 &&
+			(termfeatures & TERM_CAN_INSERT) &&
+			(termfeatures & TERM_CAN_DELETE)) {
+
+			input_delete_char_from_screen();
+		}
+#endif
+		THIS_CHAR = realkey;
+#ifndef MULTIBYTE_SUPPORT
+		term_putchar(realkey);
+#else
+		/*
+		 * if we're adding a zero-width char, it might be combining
+		 * (combines with the previous char), so we have to redraw
+		 * the whole line to ensure we combing with the correct one.
+		 * if we're adding a wide char, we need to insert some
+		 * char cells to make sure the rest of the input line
+		 * is in the right place.
+		 */
+		if (my_wcwidth(realkey) == 0)
+			display_flag = UPDATE_ALL;
+		else if (my_wcwidth(realkey) > 1) {
+			/* copied from insert mode above */
+			if ((termfeatures & TERM_CAN_INSERT) && (termfeatures & TERM_CAN_DELETE)) {
+				term_insert(realkey);
+			} else {
+				term_putchar(realkey);
+				if (NEXT_CHAR)
+					display_flag = UPDATE_FROM_CURSOR;
+				else
+					display_flag = NO_UPDATE;
+			}
+		} else
+			term_putchar(realkey);
+		
+		/*
+		 * clobber any zero-width chars after this point, effectively
+		 * treating <char><zerowidth> as a single character.  we do
+		 * this so that combined characters are treated as one.
+		 */
+		p = &NEXT_CHAR;
+		while (*p != L'\0' && my_wcwidth(*p) == 0)
+			p++;
+
+		/* there were chars, delete them */
+		if (p != &NEXT_CHAR)
+			ov_strcpy(&NEXT_CHAR, p);
+#endif
 	}
 
 	THIS_POS++;
@@ -950,8 +1269,8 @@ BUILT_IN_BINDING(input_clear_to_eol)
 {
 	/* This doesnt really speak to the implementation, but it works.  */
 	cursor_to_input();
-	malloc_strcpy(&cut_buffer, &THIS_CHAR);
-	THIS_CHAR = 0;
+	malloc_wcscpy(&cut_buffer, &THIS_CHAR);
+	THIS_CHAR = NUL_CHAR;
 	term_clear_to_eol();
 	update_input(NO_UPDATE);
 }
@@ -966,11 +1285,15 @@ BUILT_IN_BINDING(input_clear_to_bol)
 
 	cursor_to_input();
 
-	THIS_CHAR = 0;
-	malloc_strcpy(&cut_buffer, &MIN_CHAR);
+	THIS_CHAR = NUL_CHAR;
+	malloc_wcscpy(&cut_buffer, &MIN_CHAR);
 	THIS_CHAR = c;
 
-	set_input(LOCAL_COPY(&THIS_CHAR));
+#ifdef MULTIBYTE_SUPPORT
+	set_input_wc(LOCAL_WCOPY(&THIS_CHAR));
+#else
+	set_input(LOCAL_WCOPY(&THIS_CHAR));
+#endif
 	THIS_POS = MIN_POS;
 	term_move_cursor(INPUT_PROMPT_LEN, INPUT_LINE);
 	term_clear_to_eol();
@@ -985,10 +1308,10 @@ BUILT_IN_BINDING(input_clear_line)
 {
 	cursor_to_input();
 
-	if (MIN_CHAR != '\0')
+	if (MIN_CHAR != NUL_CHAR)
 		/* only copy if there is input. -wd */
-		malloc_strcpy(&cut_buffer, INPUT_BUFFER + MIN_POS);
-	MIN_CHAR = 0;
+		malloc_wcscpy(&cut_buffer, INPUT_BUFFER + MIN_POS);
+	MIN_CHAR = NUL_CHAR;
 	THIS_POS = MIN_POS;
 	term_move_cursor(INPUT_PROMPT_LEN, INPUT_LINE);
 	term_clear_to_eol();
@@ -1022,9 +1345,9 @@ BUILT_IN_BINDING(input_transpose_charact
 		 * Else if the input buffer has at least two
 		 * characters in it (and implicity we're at the end)
 		 * then swap the two characters before the cursor
-		 * XXX This strlen() is probably unnecesary.
+		 * XXX This strlen_wc() is probably unnecesary.
 		 */
-		else if ((int) strlen(INPUT_BUFFER) > MIN_POS + 2)
+		else if ((int) strlen_wc(INPUT_BUFFER) > MIN_POS + 2)
 		{
 			pos = THIS_POS - 1;
 			end_of_line = 1;
@@ -1079,19 +1402,27 @@ BUILT_IN_BINDING(refresh_inputline)
  */
 BUILT_IN_BINDING(input_yank_cut_buffer)
 {
-	char	*ptr = NULL;
+	WIDE_CHAR	*ptr = NULL;
+#ifdef MULTIBYTE_SUPPORT
+	size_t len;
+#endif
 
 	if (!cut_buffer)
 		return;
 
-	ptr = LOCAL_COPY(&THIS_CHAR);
-	THIS_CHAR = 0;
+	ptr = LOCAL_WCOPY(&THIS_CHAR);
+	THIS_CHAR = NUL_CHAR;
 	ADD_TO_INPUT(cut_buffer);
 	ADD_TO_INPUT(ptr);
 	update_input(UPDATE_FROM_CURSOR);
 
-	THIS_POS += strlen(cut_buffer);
+	THIS_POS += strlen_wc(cut_buffer);
+#ifdef MULTIBYTE_SUPPORT
+	if ((len = wcstombs(NULL, INPUT_BUFFER, THIS_POS)) >= INPUT_BUFFER_SIZE)
+
+#else
 	if (THIS_POS > INPUT_BUFFER_SIZE)
+#endif
 		THIS_POS = INPUT_BUFFER_SIZE;
 	update_input(UPDATE_JUST_CURSOR);
 }
@@ -1136,7 +1467,7 @@ BUILT_IN_BINDING(send_line)
 	int	do_unhold;
 
 	from_server = get_window_server(0);
-	MIN_CHAR = 0;
+	MIN_CHAR = NUL_CHAR;
 	THIS_POS = MIN_POS;
 
 	/*
@@ -1283,6 +1614,11 @@ void	edit_char (u_char key)
 #endif
 		return;
 	}
+	
+	/*
+	 * FIXME: multibyte chars should probably be handled here, not in
+	 * input_add_character.
+	 */
 
 	/* were we waiting for a keypress? */
 	if (last_input_screen->promptlist && 
Index: source/irc.c
===================================================================
RCS file: /home/cvs/repository/epic4/source/irc.c,v
retrieving revision 1.705
diff -u -3 -p -r1.705 irc.c
--- source/irc.c	21 Feb 2004 17:12:18 -0000	1.705
+++ source/irc.c	4 Mar 2004 21:00:37 -0000
@@ -90,6 +90,7 @@ const char ridiculous_version_name[] = "
 #include "parse.h"
 #include "notice.h"
 #include <pwd.h>
+#include <locale.h>
 
 
 /*
@@ -228,8 +229,8 @@ char		*startup_file = NULL,		/* full pat
 		one[] = "1",
 		star[] = "*",
 		dot[] = ".",
-		comma[] = ",",
-		*cut_buffer = (char *) 0;	/* global cut_buffer */
+		comma[] = ",";
+		WIDE_CHAR *cut_buffer = NULL;	/* global cut_buffer */
 
 fd_set		readables, held_readables;
 fd_set		writables, held_writables;
@@ -1111,6 +1112,8 @@ int 	main (int argc, char *argv[])
 #ifdef SOCKS
 	SOCKSinit(argv[0]);
 #endif
+	setlocale(LC_ALL, "");
+
         get_time(&start_time);
 	check_password();
 	check_valid_user();
Index: source/ircaux.c
===================================================================
RCS file: /home/cvs/repository/epic4/source/ircaux.c,v
retrieving revision 1.106
diff -u -3 -p -r1.106 ircaux.c
--- source/ircaux.c	8 Jan 2004 20:14:58 -0000	1.106
+++ source/ircaux.c	4 Mar 2004 21:00:39 -0000
@@ -3811,6 +3811,51 @@ char *	malloc_strcpy_c (char **ptr, cons
 	return *ptr;
 }
 
+#ifdef MULTIBYTE_SUPPORT
+wchar_t *	malloc_wcscpy_c (wchar_t **ptr, const wchar_t *src, size_t *clue)
+{
+	size_t	size, size_src;
+
+	if (!src)
+	{
+		if (clue)
+			*clue = 0;
+		return new_free(ptr);	/* shrug */
+	}
+
+	if (*ptr)
+	{
+		size = alloc_size(*ptr);
+		if (size == (size_t) FREED_VAL)
+			panic("free()d pointer passed to malloc_strcpy");
+
+		size /= sizeof(wchar_t);
+
+		/* No copy neccesary! */
+		if (*ptr == src)
+			return *ptr;
+
+		size_src = wcslen(src);
+		if (size > size_src)
+		{
+			wcsncpy(*ptr, src, size);
+			if (clue)
+				*clue = size_src;
+			return *ptr;
+		}
+
+		new_free(ptr);
+	}
+
+	size = wcslen(src);
+	*ptr = new_malloc((size + 1) * sizeof(wchar_t));
+	wcsncpy(*ptr, src, size + 1);
+	if (clue)
+		*clue = size;
+	return *ptr;
+}
+#endif
+
 /*
  * malloc_strcat_c: Append a copy of 'src' to the end of '*ptr', with an 
  *	optional "clue" (length of (*ptr))
Index: source/screen.c
===================================================================
RCS file: /home/cvs/repository/epic4/source/screen.c,v
retrieving revision 1.65
diff -u -3 -p -r1.65 screen.c
--- source/screen.c	7 Dec 2003 20:16:52 -0000	1.65
+++ source/screen.c	4 Mar 2004 21:00:41 -0000
@@ -55,6 +55,7 @@
 #include "commands.h"
 #include "parse.h"
 #include "newio.h"
+#include <wchar.h>
 
 #define CURRENT_WSERV_VERSION	4
 
@@ -1574,6 +1575,8 @@ const 	u_char	*ptr;
 	Attribute	a;
 	Attribute	saved_a;
 	u_char	*cont_free = NULL;
+	int	do_utf8;
+	mbstate_t	mbs;
 
 	if (recursion)
 		panic("prepare_display() called recursively");
@@ -1593,6 +1596,10 @@ const 	u_char	*ptr;
 	if (!(cont_ptr = get_string_var(CONTINUED_LINE_VAR)))
 		cont_ptr = empty_string;
 
+	do_utf8 = get_int_var(UTF8_VAR);
+	if (do_utf8)
+		memset(&mbs, 0, sizeof(mbs));
+
 	buffer[0] = 0;
 
 	if (!output_size)
@@ -1657,6 +1664,37 @@ const 	u_char	*ptr;
 
 			default:
 			{
+				int mbcount;
+				wchar_t wch;
+
+				if (do_utf8 && 1 < (mbcount = mbrtowc(&wch, ptr, BIG_BUFFER_SIZE, &mbs)))
+				{
+					int width = wcwidth(wch);
+
+					/* MASSIVE EVIL HACKERY AT WORK */
+					if ((col + width) > max_cols) {
+						col = max_cols + 1;
+						ptr--;
+						break;
+					}
+
+					/* multi-byte character */
+					if ((pos + mbcount) >= (BIG_BUFFER_SIZE - 8))
+					{
+						pos = (BIG_BUFFER_SIZE - 8);
+						ptr += mbcount - 1;
+						break;
+					}
+
+					memcpy(&buffer[pos], ptr, mbcount);
+					pos += mbcount;
+					ptr += mbcount - 1;
+
+					col += width;
+
+					break;
+				}
+
 				if (!strchr(words, *ptr))
 				{
 					if (indent == -1)
@@ -1991,11 +2029,17 @@ int 	output_with_count (const unsigned c
 			out = 0;
 	Attribute	a;
 	const unsigned char *str;
+	int		do_utf8;
+	mbstate_t	mbs;
 
         /* Reset all attributes to zero */
         a.bold = a.underline = a.reverse = a.blink = a.altchar = 0;
         a.color_fg = a.color_bg = a.fg_color = a.bg_color = 0;
 
+	do_utf8 = get_int_var(UTF8_VAR);
+	if (do_utf8)
+		memset(&mbs, 0, sizeof(mbs));
+
 	for (str = str1; str && *str; str++)
 	{
 		switch (*str)
@@ -2053,9 +2097,24 @@ int 	output_with_count (const unsigned c
 				 * that are nasty that get here, its probably
 				 * because the user specifically asked for it.
 				 */
-				if (output)
-					putchar_x(*str);
-				out++;
+				int mbcount;
+				wchar_t wch;
+
+				if (do_utf8 && 1 < (mbcount = mbrtowc(&wch, str, BIG_BUFFER_SIZE, &mbs))) {
+					if (output)
+					{
+						int i;
+						for (i = 0; i < mbcount; i++)
+							putchar_x(str[i]);
+					}
+
+					out += wcwidth(wch);
+					str += mbcount - 1;
+				} else {
+					if (output)
+						putchar_x(*str);
+					out++;
+				}
 				break;
 			}
 		}
Index: source/term.c
===================================================================
RCS file: /home/cvs/repository/epic4/source/term.c,v
retrieving revision 1.12
diff -u -3 -p -r1.12 term.c
--- source/term.c	3 Dec 2003 22:17:40 -0000	1.12
+++ source/term.c	4 Mar 2004 21:00:42 -0000
@@ -651,7 +651,7 @@ int	term_echo (int flag)
  * we need to worry about here is making sure nothing suspcious, like an
  * escape, makes its way to the output stream.
  */
-void	term_putchar (unsigned char c)
+void	term_putchar (WIDE_UCHAR c)
 {
 	if (!term_echo_flag)
 	{
@@ -663,8 +663,10 @@ void	term_putchar (unsigned char c)
 	 * If the user has /set eight_bit_characters off, then we lop off
 	 * any 8 bit characters we might stumble across.
 	 */
+#ifndef MULTIBYTE_SUPPORT
 	if (!(newb.c_cflag & CS8) && (c & 0x80))
 		c &= ~0x80;
+#endif
 
 	/*
 	 * Any nonprintable characters we lop off.  In addition to this,
@@ -673,17 +675,36 @@ void	term_putchar (unsigned char c)
 	 * with only 7 bit capabilities wont be reflected in /set eight_bit.
 	 * It is therefore our job to head that possibility off at the pass.
 	 */
-	if (c < 0x20 || c == 0x9b)
+#ifdef MULTIBYTE_SUPPORT
+	if (!iswprint(c)) {
+		char buf[MB_LEN_MAX];
+		int len, x;
+
+		term_standout_on();
+
+		len = wctomb(buf, c);
+		for (x = 0; x < len; x++) 
+			putchar_x((buf[x] | 0x40) & 0x7f);
+		
+		term_standout_off();
+	}
+#else
+	if (c < 0x20 || (c == 0x9b && !get_int_var(ALLOW_C1_CHARS_VAR)))
 	{
 		term_standout_on();
-		putchar_x((c | 0x40) & 0x7f);
+		putchar_x_wc((c | 0x40) & 0x7f);
 		term_standout_off();
 	}
+#endif
 
 	/*
 	 * The delete character is handled especially as well
 	 */
+#ifdef MULTIBYTE_SUPPORT
+	else if (c == L'\x7f')	/* delete char */
+#else
 	else if (c == 0x7f) 	/* delete char */
+#endif
 	{
 		term_standout_on();
 		putchar_x('?');
@@ -694,7 +715,7 @@ void	term_putchar (unsigned char c)
 	 * Everything else is passed through.
 	 */
 	else
-		putchar_x(c);
+		putchar_x_wc(c);
 }
 
 
@@ -1322,7 +1343,7 @@ void	term_delete (int num)
 /*
  * Insert character C at the curent cursor position.
  */
-void	term_insert (unsigned char c)
+void	term_insert (WIDE_UCHAR c)
 {
 	if (current_term->TI_smir)
 		tputs_x (current_term->TI_smir);
Index: source/vars.c
===================================================================
RCS file: /home/cvs/repository/epic4/source/vars.c,v
retrieving revision 1.45
diff -u -3 -p -r1.45 vars.c
--- source/vars.c	26 Dec 2003 19:14:49 -0000	1.45
+++ source/vars.c	4 Mar 2004 21:00:42 -0000
@@ -315,6 +315,7 @@ static	IrcVariable irc_variable[] =
 	{ "TRANSLATION_PATH",		STR_TYPE_VAR,	0, 0, NULL, NULL, 0, 0 },
 	{ "UNDERLINE_VIDEO",		BOOL_TYPE_VAR,	DEFAULT_UNDERLINE_VIDEO, 0, NULL, NULL, 0, 0 },
 	{ "USER_INFORMATION", 		STR_TYPE_VAR,	0, 0, NULL, NULL, 0, 0 },
+	{ "UTF8",			BOOL_TYPE_VAR,	DEFAULT_UTF8, 0, NULL, NULL, 0, 0 },
 	{ "VERBOSE_CTCP",		BOOL_TYPE_VAR,	DEFAULT_VERBOSE_CTCP, 0, NULL, NULL, 0, 0 },
 	{ "WORD_BREAK",			STR_TYPE_VAR,	0, 0, NULL, NULL, 0, 0 },
 	{ "WSERV_PATH",			STR_TYPE_VAR,	0, 0, NULL, NULL, 0, 0 },
