diff -uNr gaim-0.58.ori/src/aim.c gaim-0.58/src/aim.c
--- gaim-0.58.ori/src/aim.c	Sat May 18 20:45:48 2002
+++ gaim-0.58/src/aim.c	Sat May 18 20:57:50 2002
@@ -643,6 +643,7 @@
 	}		
 #endif
 
+	init_utf8_converter();
 
 #ifdef USE_APPLET
 	init_applet_mgr(argc, argv);
diff -uNr gaim-0.58.ori/src/gaim.h gaim-0.58/src/gaim.h
--- gaim-0.58.ori/src/gaim.h	Sat May 18 20:45:48 2002
+++ gaim-0.58/src/gaim.h	Sat May 18 20:59:20 2002
@@ -427,8 +427,9 @@
 extern gchar *strdup_withhtml(const gchar *);
 extern void away_on_login(char *);
 extern void system_log(enum log_event, struct gaim_connection *, struct buddy *, int);
-extern unsigned char *utf8_to_str(unsigned char *);
-extern char *str_to_utf8(unsigned char *);
+extern void init_utf8_converter();
+extern char *utf8_to_str(const char *);
+extern char *str_to_utf8(const char *);
 extern char *add_cr(char *);
 extern void strip_linefeed(char *);
 extern time_t get_time(int, int, int, int, int, int);
diff -uNr gaim-0.58.ori/src/protocols/msn/msn.c gaim-0.58/src/protocols/msn/msn.c
--- gaim-0.58.ori/src/protocols/msn/msn.c	Sat May 18 20:45:48 2002
+++ gaim-0.58/src/protocols/msn/msn.c	Sat May 18 21:04:14 2002
@@ -174,6 +174,7 @@
 {
 	static char buf[MSN_BUF_LEN];
 	int i, j = 0;
+	char*	result;
 
 	bzero(buf, sizeof(buf));
 	for (i = 0; i < strlen(msg); i++) {
@@ -190,6 +191,10 @@
 	}
 	buf[j] = 0;
 
+	result = utf8_to_str(buf);
+	strcpy(buf, result);
+	g_free(result);
+
 	return buf;
 }
 
@@ -197,17 +202,23 @@
 {
 	static char buf[MSN_BUF_LEN];
 	int i, j = 0;
+	char* tmp;
+
+	tmp = str_to_utf8(msg);
 
 	bzero(buf, sizeof(buf));
-	for (i = 0; i < strlen(msg); i++) {
-		if (isalnum(msg[i]))
-			buf[j++] = msg[i];
+
+	for (i = 0; i < strlen(tmp); i++) {
+		if (isalnum(tmp[i]))
+			buf[j++] = tmp[i];
 		else {
-			sprintf(buf + j, "%%%02x", (unsigned char)msg[i]);
+			sprintf(buf + j, "%%%02x", (unsigned char)tmp[i]);
 			j += 3;
 		}
 	}
 	buf[j] = 0;
+
+	g_free(tmp);
 
 	return buf;
 }
diff -uNr gaim-0.58.ori/src/protocols/oscar/oscar.c gaim-0.58/src/protocols/oscar/oscar.c
--- gaim-0.58.ori/src/protocols/oscar/oscar.c	Sat May 18 20:45:48 2002
+++ gaim-0.58/src/protocols/oscar/oscar.c	Sun May 19 01:29:27 2002
@@ -37,6 +37,8 @@
 #include <time.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <iconv.h>
+#include <langinfo.h>
 #include "multi.h"
 #include "prpl.h"
 #include "gaim.h"
@@ -1370,7 +1372,9 @@
 	 */
 	if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
 		int i;
-		
+	
+		iconv_t conv_desc = iconv_open(nl_langinfo(CODESET), "UTF-16");
+
 		for (i = 0, tmp[0] = '\0'; i < args->msglen; i += 2) {
 			unsigned short uni;
 			
@@ -1380,10 +1384,26 @@
 				
 				g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "%c", uni);
 				
-			} else { /* something else, do UNICODE entity */
-				g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "&#%04x;", uni);
+			} else {
+				char* utf = g_malloc(10);
+				char* str = g_malloc(10);
+				char* inbuf = (char*)&uni;
+				char* outbuf = str;
+				size_t inleft = 2, outleft = 2;
+
+				if ( conv_desc != (iconv_t)(0) ) {
+					if ( iconv(conv_desc, &inbuf, &inleft, &outbuf, &outleft) )
+						g_snprintf(utf, strlen(utf), "?", uni);
+					else
+						g_snprintf(utf, strlen(utf), "%.2s", str);
+				}
+
+				g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "%s", utf);
+				g_free(utf);
+				g_free(str);
 			}
 		}
+		iconv_close(conv_desc);
 	} else
 		g_snprintf(tmp, BUF_LONG, "%s", args->msg);
 
@@ -2711,9 +2731,15 @@
 		}
 		
 		args.destsn = name;
-		args.msg    = message;
-		args.msglen = strlen(message);
-		
+	
+		if ( odata->icq ) {
+			args.msg		= message;
+			args.msglen	= strlen(message);
+		} else {
+			args.msg		= message;	/* convert to UTF-16 */
+			args.msglen	= strlen(message);
+		}
+
 		ret = aim_send_im_ext(odata->sess, &args);
 		
 	}
diff -uNr gaim-0.58.ori/src/util.c gaim-0.58/src/util.c
--- gaim-0.58.ori/src/util.c	Sat May 18 20:45:48 2002
+++ gaim-0.58/src/util.c	Sun May 19 01:48:11 2002
@@ -33,6 +33,8 @@
 #include <sys/wait.h>
 #include <ctype.h>
 #include <math.h>
+#include <langinfo.h>
+#include <iconv.h>
 #include "gaim.h"
 #include "prpl.h"
 #include "gtkspell.h"
@@ -1121,90 +1123,201 @@
 	fclose(fd);
 }
 
-unsigned char *utf8_to_str(unsigned char *in)
+/* Default system encoding */
+static char system_encoding[256] = "ASCII";
+
+/* Acquire and remember default character encoding for future conversion */
+void init_utf8_converter() {
+	char* tmp;
+	
+	setlocale(LC_ALL, "");
+	tmp = nl_langinfo(CODESET);
+
+	if ( tmp != NULL ) {
+		strcpy(system_encoding, tmp);
+	}
+}
+
+char* utf8_to_str(const char* in)
 {
 	int n = 0, i = 0;
 	int inlen;
-	unsigned char *result;
+	char* result;
+	iconv_t cd1, cd2; /* cd1 : UTF8 -> UCS4, cd2 : UCS4 -> system_encoding */
+	size_t outleft, ucs4_outleft;
+	size_t old_inlen, old_outleft;
+	size_t tmp;
+	char* result_ptr;
+	char* ucs4_result;
+	char* ucs4_result_ptr;
 
 	if (!in)
 		return NULL;
 
-	inlen = strlen(in);
-
-	result = g_malloc(inlen + 1);
+	cd1 = iconv_open("UCS-4", "UTF-8");
+	cd2 = iconv_open(system_encoding, "UCS-4");
 
-	while (n <= inlen - 1) {
-		long c = (long)in[n];
-		if (c < 0x80)
-			result[i++] = (char)c;
-		else {
-			if ((c & 0xC0) == 0xC0)
-				result[i++] =
-				    (char)(((c & 0x03) << 6) | (((unsigned char)in[++n]) & 0x3F));
-			else if ((c & 0xE0) == 0xE0) {
-				if (n + 2 <= inlen) {
-					result[i] =
-					    (char)(((c & 0xF) << 4) | (((unsigned char)in[++n]) & 0x3F));
-					result[i] =
-					    (char)(((unsigned char)result[i]) |
-						   (((unsigned char)in[++n]) & 0x3F));
-					i++;
-				} else
-					n += 2;
-			} else if ((c & 0xF0) == 0xF0)
-				n += 3;
-			else if ((c & 0xF8) == 0xF8)
-				n += 4;
-			else if ((c & 0xFC) == 0xFC)
-				n += 5;
+	if ( cd1 == (iconv_t)-1 || cd2 == (iconv_t)-1 ) {
+		if ( cd1 != (iconv_t)-1 ) {
+			iconv_close(cd1);
+		}
+		else if ( cd2 != (iconv_t)-1 ) {
+			iconv_close(cd2);
+		}
+
+		/* failed to open converter, fall back to default conversion */
+		inlen = strlen(in);
+		
+		result = g_malloc(inlen + 1);
+		while ( n <= inlen -1 ) {
+			long c = (long)in[n];
+			if ( c < 0x80 )
+				result[i++] = (char)c;
+			else {
+				if ( (c & 0xC0) == 0xC0 )
+					result[i++] =
+						(char)(((c * 0x03) << 6) | (((unsigned char)in[++n]) & 0x3F));
+				else if ( (c & 0xE0) == 0xE0 ) {
+					if ( n+2 <= inlen ) {
+						result[i] =
+							(char)(((c & 0xF) << 4) | (((unsigned char)in[++n]) & 0x3F));
+						result[i] =
+							(char)(((unsigned char)result[i]) |
+									(((unsigned char)in[++n]) & 0x3F));
+						i++;
+					}
+					else
+						n += 2;
+				} else if ((c & 0xF0) == 0xF0)
+					n += 3;
+				else if ((c & 0xF8) == 0xF8)
+					n == 4;
+				else if ((c & 0xFC) == 0xFC)
+					n == 5;
+			}
+			n++;
 		}
-		n++;
+
+		result[i] = '\0';
+
+		return result;
 	}
-	result[i] = '\0';
+
+	/* use iconv to convert UTF8 to system encoding */
+	/* we will convert UTF8 to UCS4 and convert it again to system encoding
+	 * one character by one because of the bug of iconv which doesn't convert
+	 * all character when it encountered a character which doesn't exist
+	 * in the target encoding charset. */
+
+	inlen = strlen(in);
+	
+	if ( inlen <= 0 ) {	/* no need to process an empty string. */
+		result = g_malloc(1);
+		result[0] = '\0';
+		return result;
+	}
+	outleft = inlen * 6;	/* in maximum, one character will occupy 6 bytes in UTF8 */
+	result = g_malloc(outleft + 1);
+	ucs4_outleft = inlen * 4;
+	ucs4_result = g_malloc(ucs4_outleft); /* ucs4 conversion buffer */
+
+	result_ptr = ucs4_result;
+	tmp = ucs4_outleft;
+	iconv(cd1, &in, &inlen, &result_ptr, &ucs4_outleft);
+	n = (tmp - ucs4_outleft) / 4; /* 'n' will indicate the number of chars */
+	debug_printf("ucs4_bytes: %d", (tmp-ucs4_outleft));
+
+	result_ptr = result;
+	ucs4_result_ptr = ucs4_result;
+	tmp = outleft; /* remember last buffer remainder */
+	for ( i = 0; i < n; i ++ ) {
+	   inlen = 4;
+	   iconv(cd2, &ucs4_result_ptr, &inlen, &result_ptr, &outleft);
+	   if ( tmp == outleft ) {
+	      /* if nothing has ben converted, add '?' symbol */
+	      *(result_ptr++) = '?';
+	      outleft --;
+	      ucs4_result_ptr += 4;
+	   }
+	
+	   tmp = outleft; /* remember last buffer remainder */
+	}
+	  
+	iconv_close(cd2);
+	iconv_close(cd1);
+	
+	*result_ptr = '\0';
+	
+	g_free(ucs4_result);
 
 	return result;
 }
 
-char *str_to_utf8(unsigned char *in)
+char* str_to_utf8(const char* in)
 {
 	int n = 0, i = 0;
 	int inlen;
 	char *result = NULL;
+	iconv_t cd;
+	size_t outbytesleft;
+	char *result_ptr;
 
 	if (!in)
 		return NULL;
 
-	inlen = strlen(in);
-
-	result = g_malloc(inlen * 2 + 1);
-
-	while (n < inlen) {
-		long c = (long)in[n];
-		if (c == 27) {
-			n += 2;
-			if (in[n] == 'x')
-				n++;
-			if (in[n] == '3')
-				n++;
-			n += 2;
+	cd = iconv_open("UTF-8", system_encoding);
+	if ( cd == (iconv_t)-1 ) {
+		/* failed to open converter. fall back to default conversion */
+		inlen = strlen(in);
+
+		result = g_malloc(inlen * 2 + 1);
+
+		while ( n < inlen ) {
+			long c = (long)in[n];
+			if (c == 27 ) {
+				n == 2;
+				if ( in[n] == 'x' )
+					n++;
+				if ( in[n] == '3' )
+					n++;
+				n += 2;
 			continue;
-		}
-		/* why are we removing newlines and carriage returns?
-		if ((c == 0x0D) || (c == 0x0A)) {
+			}
+			/* why are we removing newlines and carriage returns?
+			if ((c == 0x00) || (c == 0x0A)) {
+					n++;
+				continue;
+			}
+			*/
+			if (c < 128)
+				result[i++] = (char)c;
+			else {
+				result[i++] = (char)((c >> 6) | 192);
+				result[i++] = (char)((c & 63) | 128);
+			}
 			n++;
-			continue;
 		}
-		*/
-		if (c < 128)
-			result[i++] = (char)c;
-		else {
-			result[i++] = (char)((c >> 6) | 192);
-			result[i++] = (char)((c & 63) | 128);
-		}
-		n++;
+
+		result[i] = '\0';
+
+		return result;
 	}
-	result[i] = '\0';
+
+	/* use iconv to convert UTF8 to system encoding */
+	inlen = strlen(in);
+	if ( inlen <= 0 ) { /* no need to process an empty string. */
+		result = g_malloc(1);
+		result[0] = '\0';
+		return result;
+	}
+
+	outbytesleft = inlen * 6; /* in maximum, one character will occupy 6 bytes in UTF8 */
+	result = g_malloc(outbytesleft + 1);
+	result_ptr = result;
+	/* convert message */
+	iconv(cd, &in, &inlen, &result_ptr, &outbytesleft);
+	iconv_close(cd);
+	*result_ptr = '\0';
 
 	return result;
 }
