Index: fmtext.c
===================================================================
--- fmtext.c	(revision fa3290d0243ae8fb36df1f09bbe9bc943d1efc06)
+++ fmtext.c	(revision 28ee32b3f0b785ed3f83357207feda49cfdb61b4)
@@ -315,43 +315,67 @@
 void owl_fmtext_truncate_cols(owl_fmtext *in, int acol, int bcol, owl_fmtext *out)
 {
-  char *ptr1, *ptr2, *last;
-  int len, offset;
+  char *ptr_s, *ptr_e, *ptr_c, *last;
+  int col, cnt;
 
   last=in->textbuff+in->textlen-1;
-  ptr1=in->textbuff;
-  while (ptr1<=last) {
-    ptr2=strchr(ptr1, '\n');
-    if (!ptr2) {
+  ptr_s=in->textbuff;
+  while (ptr_s<=last) {
+    ptr_e=strchr(ptr_s, '\n');
+    if (!ptr_e) {
       /* but this shouldn't happen if we end in a \n */
       break;
     }
     
-    if (ptr2==ptr1) {
+    if (ptr_e==ptr_s) {
       owl_fmtext_append_normal(out, "\n");
-      ptr1++;
+      ptr_s++;
       continue;
     }
 
+    col = 0;
+    cnt = 0;
+    ptr_c = ptr_s;
+    while(col < bcol && ptr_c < ptr_e) {
+      gunichar c = g_utf8_get_char(ptr_c);
+      if (g_unichar_iswide(c)) {
+	if (col + 2 > bcol) break;
+	else col += 2;
+      }
+      else if (g_unichar_type(c) == G_UNICODE_NON_SPACING_MARK) ; /*do nothing*/
+      /* We may need more special cases here... unicode spacing is hard. */
+      else {
+	if (col + 1 > bcol) break;
+	else ++col;
+      }
+      ptr_c = g_utf8_next_char(ptr_c);
+      if (col >= acol) ++cnt;
+      if (col <= acol) ptr_s = ptr_c;
+    }
+    _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
+    ptr_s=ptr_e+1;
+    
+#if 0
     /* we need to check that we won't run over here */
     len=bcol-acol;
-    if (len > (ptr2-(ptr1+acol))) {
+    if (len > (ptr_e-(ptr_s+acol))) {
       /* the whole line fits with room to spare, don't take a full 'len' */
-      len=ptr2-(ptr1+acol);
-    }
-    if (len>last-ptr1) {
+      len=ptr_e-(ptr_s+acol);
+    }
+    if (len>last-ptr_s) {
       /* the whole rest of the text fits with room to spare, adjust for it */
-      len-=(last-ptr1);
+      len-=(last-ptr_s);
     }
     if (len<=0) {
       /* saftey check */
       owl_fmtext_append_normal(out, "\n");
-      ptr1=ptr2+1;
+      ptr_s=ptr_e+1;
       continue;
     }
 
-    offset=ptr1-in->textbuff;
+    offset = ptr_s - in->textbuff;
     _owl_fmtext_append_fmtext(out, in, offset+acol, offset+acol+len);
 
-    ptr1=ptr2+1;
+    ptr_s=ptr_e+1;
+#endif
   }
 }
Index: functions.c
===================================================================
--- functions.c	(revision 34509d514dfa9ee441febffc6d61e108962d1507)
+++ functions.c	(revision 28ee32b3f0b785ed3f83357207feda49cfdb61b4)
@@ -2598,5 +2598,11 @@
   }
   /* downcase it */
-  downstr(filtname);
+  {
+    char *temp = g_utf8_strdown(filtname, -1);
+    if (temp) {
+      owl_free(filtname);
+      filtname = temp;
+    }
+  }
   /* turn spaces, single quotes, and double quotes into dots */
   owl_text_tr(filtname, ' ', '.');
Index: logging.c
===================================================================
--- logging.c	(revision d0961fe0bc68cec33bc23afbae4928bbd861d718)
+++ logging.c	(revision 28ee32b3f0b785ed3f83357207feda49cfdb61b4)
@@ -155,7 +155,9 @@
     to = owl_sprintf("jabber:%s", owl_message_get_recipient(m));
   } else if (owl_message_is_type_aim(m)) {
+    char *temp2;
     temp = owl_aim_normalize_screenname(owl_message_get_recipient(m));
-    downstr(temp);
-    to = owl_sprintf("aim:%s", temp);
+    temp2 = g_utf8_strdown(temp,-1);
+    to = owl_sprintf("aim:%s", temp2);
+    owl_free(temp2);
     owl_free(temp);
   } else {
@@ -267,9 +269,10 @@
   } else if (owl_message_is_type_aim(m)) {
     /* we do not yet handle chat rooms */
-    char *normalto;
-    normalto=owl_aim_normalize_screenname(owl_message_get_sender(m));
-    downstr(normalto);
+    char *normalto, *temp;
+    temp = owl_aim_normalize_screenname(owl_message_get_sender(m));
+    normalto = g_utf8_strdown(temp, -1);
     from=frombuff=owl_sprintf("aim:%s", normalto);
     owl_free(normalto);
+    owl_free(temp);
   } else if (owl_message_is_type_loopback(m)) {
     from=frombuff=owl_strdup("loopback");
@@ -290,5 +293,5 @@
 
   ch=frombuff[0];
-  if (!isalnum(ch)) from="weird";
+  if (!g_ascii_isalnum(ch)) from="weird";
 
   for (i=0; i<len; i++) {
@@ -299,5 +302,11 @@
 
   if (!personal) {
-    if (strcmp(from, "weird")) downstr(from);
+    if (strcmp(from, "weird")) {
+      char* temp = g_utf8_strdown(frombuff, -1);
+      if (temp) {
+	owl_free(frombuff);
+	from = frombuff = temp;
+      }
+    }
   }
 
Index: text.c
===================================================================
--- text.c	(revision 34509d514dfa9ee441febffc6d61e108962d1507)
+++ text.c	(revision 28ee32b3f0b785ed3f83357207feda49cfdb61b4)
@@ -50,39 +50,63 @@
 void owl_text_truncate_cols(char *out, char *in, int acol, int bcol)
 {
-  char *ptr1, *ptr2, *tmpbuff, *last;
-  int len;
-
+  char *ptr_s, *ptr_e, *ptr_c, *tmpbuff, *last;
+  int col, cnt;
+  
   tmpbuff=owl_malloc(strlen(in)+20);
 
   strcpy(tmpbuff, "");
   last=in+strlen(in)-1;
-  ptr1=in;
-  while (ptr1<last) {
-    ptr2=strchr(ptr1, '\n');
-    if (!ptr2) {
+  ptr_s=in;
+  while (ptr_s<last) {
+    ptr_e=strchr(ptr_s, '\n');
+    if (!ptr_e) {
       /* but this shouldn't happen if we end in a \n */
       break;
     }
     
-    if (ptr2==ptr1) {
+    if (ptr_e==ptr_s) {
       strcat(tmpbuff, "\n");
-      ptr1++;
-      continue;
-    }
-
+      ptr_s++;
+      continue;
+    }
+
+    col = 0;
+    cnt = 0;
+    ptr_c = ptr_s;
+    while(col < bcol && ptr_c < ptr_e) {
+      gunichar c = g_utf8_get_char(ptr_c);
+      if (g_unichar_iswide(c)) {
+	if (col + 2 > bcol) break;
+	else col += 2;
+      }
+      else if (g_unichar_type(c) == G_UNICODE_NON_SPACING_MARK) ; /*do nothing*/
+      /* We may need more special cases here... unicode spacing is hard. */
+      else {
+	if (col + 1 > bcol) break;
+	else ++col;
+      }
+      ptr_c = g_utf8_next_char(ptr_c);
+      if (col >= acol) ++cnt;
+      if (col <= acol) ptr_s = ptr_c;
+    }
+    strncat(tmpbuff, ptr_s, ptr_c - ptr_s - 1);
+    strcat(tmpbuff, "\n");
+    ptr_s = ptr_e + 1;
+#if 0
     /* we need to check that we won't run over here */
-    if ( (ptr2-ptr1) < (bcol-acol) ) {
-      len=ptr2-(ptr1+acol);
+    if ( (ptr_e-ptr_s) < (bcol-acol) ) {
+      len=ptr_e-(ptr_s+acol);
     } else {
       len=bcol-acol;
     }
-    if ((ptr1+len)>=last) {
-      len-=last-(ptr1+len);
-    }
-
-    strncat(tmpbuff, ptr1+acol, len);
+    if ((ptr_s+len)>=last) {
+      len-=last-(ptr_s+len);
+    }
+
+    strncat(tmpbuff, ptr_s+acol, len);
     strcat(tmpbuff, "\n");
 
-    ptr1=ptr2+1;
+    ptr_s=ptr_e+1;
+#endif
   }
   strcpy(out, tmpbuff);
@@ -275,19 +299,16 @@
 char *stristr(char *a, char *b)
 {
-  char *x, *y, *ret;
-
-  if ((x=owl_strdup(a))==NULL) return(NULL);
-  if ((y=owl_strdup(b))==NULL) return(NULL);
-  downstr(x);
-  downstr(y);
-  ret=strstr(x, y);
-  if (ret==NULL) {
-    owl_free(x);
-    owl_free(y);
-    return(NULL);
-  }
-  ret=ret-x+a;
-  owl_free(x);
-  owl_free(y);
+  char *x, *y;
+  char *ret = NULL;
+  if ((x = g_utf8_casefold(a, -1)) != NULL) {
+    if ((y = g_utf8_casefold(b, -1)) != NULL) {
+      ret = strstr(x, y);
+      if (ret != NULL) {
+	ret = ret - x + a;
+      }
+      g_free(y);
+    }
+    g_free(x);
+  }
   return(ret);
 }
@@ -296,7 +317,15 @@
 int only_whitespace(char *s)
 {
-  int i;
-  for (i=0; s[i]; i++) {
-    if (!isspace((int) s[i])) return(0);
+  if (g_utf8_validate(s,-1,NULL)) {
+    char *p;
+    for(p = s; p[0]; p=g_utf8_next_char(p)) {
+      if (!g_unichar_isspace(g_utf8_get_char(p))) return 0;
+    }
+  }
+  else {
+    int i;
+    for (i=0; s[i]; i++) {
+      if (!isspace((int) s[i])) return(0);
+    }
   }
   return(1);
Index: util.c
===================================================================
--- util.c	(revision 89f5338caeb1828d0000cccaf478f1808203a6b1)
+++ util.c	(revision 28ee32b3f0b785ed3f83357207feda49cfdb61b4)
@@ -399,13 +399,4 @@
 }
 
-/* downcase the string 'foo' */
-void downstr(char *foo)
-{
-  int i;
-  for (i=0; foo[i]!='\0'; i++) {
-    foo[i]=tolower(foo[i]);
-  }
-}
-
 /* Caller must free response. 
  * Takes in strings which are space-separated lists of tokens
@@ -466,29 +457,15 @@
 /* allocates memory and returns the string or null.
  * caller must free the string. 
- * from Linux sprintf man page. 
  */
 char *owl_sprintf(const char *fmt, ...)
 {
-  int n, size = 100;
-  char *p;
   va_list ap;
-  if ((p = owl_malloc (size)) == NULL) return (NULL);
-  while (1) {
-    /* Try to print in the allocated space. */
-    va_start(ap, fmt);
-    n = vsnprintf (p, size, fmt, ap);
-    va_end(ap);
-    /* If that worked, return the string. */
-    if (n > -1 && n < size)
-      return p;
-    /* Else try again with more space. */
-    if (n > -1)    /* glibc 2.1 */
-      size = n+1; /* precisely what is needed */
-    else           /* glibc 2.0 */
-      size *= 2;  /* twice the old size */
-    if ((p = owl_realloc (p, size)) == NULL)
-      return NULL;
-  }
-}
+  char *ret = NULL;
+  va_start(ap, fmt);
+  ret = g_strdup_vprintf(fmt, ap);
+  va_end(ap);
+  return ret;
+}
+
 
 /* Return the owl color associated with the named color.  Return -1
