[1058] in BarnOwl Developers

home help back first fref pref prev next nref lref last post

[D-O-H] r1040 - in trunk: . owl owl/perl/modules/Jabber/lib/BarnOwl/Module owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber owl/perl/modules/Jabber/lib/Net/XMPP owl/perl/modules/Jabber/lib/XML

daemon@ATHENA.MIT.EDU (nelhage@MIT.EDU)
Thu Oct 29 18:12:35 2009

Resent-From: nelhage@mit.edu
Resent-To: barnowl-dev-mtg@charon.mit.edu
X-Original-To: nelhage@nelhage.com
To: dirty-owl-hackers@mit.edu
From: nelhage@MIT.EDU
Reply-to: dirty-owl-hackers@MIT.EDU
Date: Sun, 11 May 2008 22:57:44 -0400 (EDT)

Author: nelhage
Date: 2008-05-11 22:57:44 -0400 (Sun, 11 May 2008)
New Revision: 1040

Added:
   trunk/owl/configure.ac
   trunk/owl/glib_compat.c
   trunk/owl/wcwidth.c
Removed:
   trunk/owl/configure.in
Modified:
   trunk/
   trunk/owl/Makefile.in
   trunk/owl/aim.c
   trunk/owl/cmd.c
   trunk/owl/config.h.in
   trunk/owl/editwin.c
   trunk/owl/fmtext.c
   trunk/owl/functions.c
   trunk/owl/global.c
   trunk/owl/keymap.c
   trunk/owl/keypress.c
   trunk/owl/keys.c
   trunk/owl/logging.c
   trunk/owl/message.c
   trunk/owl/owl.c
   trunk/owl/owl.h
   trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm
   trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber/Connection.pm
   trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Debug.pm
   trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Message.pm
   trunk/owl/perl/modules/Jabber/lib/XML/Stream.pm
   trunk/owl/perlconfig.c
   trunk/owl/text.c
   trunk/owl/util.c
   trunk/owl/viewwin.c
   trunk/owl/zcrypt.c
   trunk/owl/zephyr.c
   trunk/owl/zwrite.c
Log:
Merge the unicode branch to trunk

........
  r776 | asedeno | 2007-12-23 19:48:01 -0500 (Sun, 23 Dec 2007) | 10 lines
  
  GLib/Unicode branch - adding glib dependency.
  
  Linking BarnOwl to GLib. 
  
  Cleaning up some malloc/realloc/strdup/free code, moving to owl_*
  functions for each.
  
  Changing to GLib memory allocation functions.
........
  r780 | asedeno | 2007-12-24 02:53:11 -0500 (Mon, 24 Dec 2007) | 21 lines
  
  UTF-8 - first pass
  
  unicode changes:
  * remove downstr() from text.c, replace on site with calls to g_utf8_strdown.
    In place downcasing is not a good idea, so the downstr() contract is unfulfillable.
  
  * make owl_text_truncate_cols() and owl_fmtext_truncate_cols() understand character width.
    This may need more work. Some code duplication - see if we can refactor.
  
  * stristr() rewritten to yse g_utf_casefold() instead of downstr(), and restructured to have a single return.
  
  * only_whitespace() rewritten for unicode.
  
  glib changes:
  * rewrite owl_sprintf() in terms of g_strdup_vprintf()
  
  WARNING: THIS IS NOT SAFE YET. Network data is not yet sanitized. Non
  UTF-8 inputs may do horrible things to you. This phase is just
  working on rendering.
........
  r781 | asedeno | 2007-12-24 03:10:38 -0500 (Mon, 24 Dec 2007) | 1 line
  
  full path to pkg.m4 in autoconf.in
........
  r782 | asedeno | 2007-12-24 10:14:09 -0500 (Mon, 24 Dec 2007) | 9 lines
  
  Unicode / Glib branch:
  
  * include wchar.h
  * replace hand-rolled width detection with wcswidth.
  * pad with space if we end up halfway into a character at the start of a line.
  
  WARNING: Still not safe.
........
  r784 | asedeno | 2007-12-27 11:01:03 -0500 (Thu, 27 Dec 2007) | 20 lines
  
  Unicode / glib branch
  
  Reworked the fmtext format to use in-line formatting.  Characters used
  for formatting are part of Unicode Supplemental Private Area-B, or
  Plane 16.
  
  fmtext no longer need 5x the text space to store formatting
  information, though they are harder to change at arbitrary
  points. This was something we hardly ever did anyhow, and we can still
  do everything we need to do.
  
  fmtext keeps a pair of colors and a char for default attributes to be
  applied when necessary.
  
  Searching is now done inline at owl_fmtext_waddstr() rather than
  specifying a section of the string to be reversed.
  
  This probably still needs some cleanup and more comments, but it
  works.
........
  r786 | asedeno | 2007-12-28 17:04:34 -0500 (Fri, 28 Dec 2007) | 6 lines
  
  unicode/glib branch.
  First pass at incoming zephyr -> UTF-8 sanitizing.
  This only operates on incoming data so far.
  We still need to clean outgoing data -- the plan is to attempt conversion
  to ISO-8859-1, and use that if it works.
........
  r787 | asedeno | 2007-12-28 17:21:57 -0500 (Fri, 28 Dec 2007) | 3 lines
  
  unicode/glib branch
  Fixing bug encountered when last field was not null-terminated.
........
  r788 | asedeno | 2007-12-29 02:55:43 -0500 (Sat, 29 Dec 2007) | 7 lines
  
  unicode/glib branch
  first pass at outbound zephyr -> iso-8859-1 sanitizing.
  Not that we can input anything other than ascii yet...
  
  The plan is that for a given field, we'll try to convert to iso-8859-1.
  If that doesn't work, use utf-8.
........
  r792 | asedeno | 2008-01-02 02:42:05 -0500 (Wed, 02 Jan 2008) | 21 lines
  
  unicode / glib branch
  
  text entry:
  * first pass at utf-8 text entry. This is not yet complete, and it certainly has bugs.
    The following is an incomplete list of functions that will probably misbehave if you use them.
    - owl_editwin_move_to_nextword()
    - owl_editwin_move_to_previousword()
    - owl_editwin_delete_nextword()
    - owl_editwin_delete_previousword()
    - owl_editwin_delete_to_endofline()
    - owl_editwin_fill_paragraph()
  
  format text:
  * owl_fmtext_curs_waddstr() contract restored to match trunk.
  * owl_fmtext_curs_waddstr_without_search() added.
  
  misc:
  * Importing Markus Kuhn's wcwidth.c from
    http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
  * Change wcwidth() calls to mk_wcwidth()
........
  r793 | asedeno | 2008-01-02 13:56:33 -0500 (Wed, 02 Jan 2008) | 8 lines
  
  unicode / glib branch
  * set min glib version to 2.12.0
   - first to support Unicode 5.0
  
  * added glib_compat.c with our own implementation of
    g_unicode_ismark() for glib < 2.14
........
  r794 | asedeno | 2008-01-02 16:53:19 -0500 (Wed, 02 Jan 2008) | 4 lines
  
  Remove options for libcurses and libncurses. This really only works
  with libncursesw.
........
  r795 | asedeno | 2008-01-02 21:35:44 -0500 (Wed, 02 Jan 2008) | 3 lines
  
  unicode/glib branch
  * Fix search code so higlighting actually works.
........
  r796 | asedeno | 2008-01-02 22:51:28 -0500 (Wed, 02 Jan 2008) | 3 lines
  
  unicode/glib branch
  fixing bugs in editwin bufflen calculations.
........
  r797 | asedeno | 2008-01-04 14:31:55 -0500 (Fri, 04 Jan 2008) | 5 lines
  
  unicode/glib branch
  * Rework some logic in fmtext's column truncating code.
  * fix what appears to be an off-by-one error, though I can't explain why
    it never manifested in trunk.
........
  r798 | asedeno | 2008-01-04 14:32:59 -0500 (Fri, 04 Jan 2008) | 2 lines
  
  unicode/glib branch
  * removing some debugging code I left in accidentally.
........
  r800 | asedeno | 2008-01-07 23:11:57 -0500 (Mon, 07 Jan 2008) | 2 lines
  
  unicode/glib branch
  Strip formmating characters when dumping to file.
........
  r802 | asedeno | 2008-01-08 00:11:55 -0500 (Tue, 08 Jan 2008) | 4 lines
  
  unicode/glib branch
  * more strict utf-8 byte fetching.
  This probably still needs more work.
........
  r804 | asedeno | 2008-01-08 00:31:31 -0500 (Tue, 08 Jan 2008) | 4 lines
  
  unicode/glib branch
  * ignore KEY_RESIZE if we know what that is. We don't need an
  unhandled keypress every time we resize the terminal.
........
  r808 | nelhage | 2008-01-09 00:26:15 -0500 (Wed, 09 Jan 2008) | 3 lines
  
   r27173@lunatique:  nelhage | 2008-01-09 00:25:13 -0500
   Implement smartnarrow on channels
........
  r811 | asedeno | 2008-01-09 14:17:57 -0500 (Wed, 09 Jan 2008) | 1 line
  
  take two for input processing
........
  r813 | asedeno | 2008-01-09 14:32:01 -0500 (Wed, 09 Jan 2008) | 1 line
  
  Preserve colors when highlighting search terms.
........
  r832 | asedeno | 2008-01-11 14:46:52 -0500 (Fri, 11 Jan 2008) | 1 line
  
  fixing post-processing in the editwin.
........
  r833 | asedeno | 2008-01-11 15:32:14 -0500 (Fri, 11 Jan 2008) | 5 lines
  
  
  * drop unused struct member
  * char * != char
  
  This fixes unicode input, which was broken as of r811.
........
  r844 | asedeno | 2008-01-11 23:59:42 -0500 (Fri, 11 Jan 2008) | 3 lines
  
  unicode/glib
  * Do not use bit 0x80 to indicate meta. We have other uses for that bit.
  * shift it above ncurses's KEY_MAX instead.
........
  r846 | asedeno | 2008-01-12 01:18:20 -0500 (Sat, 12 Jan 2008) | 2 lines
  
  unicode/glib branch
  Eliminating a warning by un-internalizing a new fmtext function.
........
  r849 | asedeno | 2008-01-12 02:26:49 -0500 (Sat, 12 Jan 2008) | 4 lines
  
  unicode/glib branch
  * fix a typo that was causing background problems
  * pass defaults attributes through in the truncate functions
........
  r883 | asedeno | 2008-01-16 14:34:55 -0500 (Wed, 16 Jan 2008) | 3 lines
  
  Unicode/glib branch
  Patches to jabber libraries for better UTF-8 handling.
........
  r884 | asedeno | 2008-01-16 14:39:12 -0500 (Wed, 16 Jan 2008) | 2 lines
  
  Unicode/glib branch
  Shuffling a line of code to where it actually should be.
........
  r885 | asedeno | 2008-01-16 14:40:36 -0500 (Wed, 16 Jan 2008) | 2 lines
  
  Unicode/glib branch
  Pet peeve - tabs. That should be the end of it for now.
........
  r886 | asedeno | 2008-01-16 20:18:25 -0500 (Wed, 16 Jan 2008) | 8 lines
  
  unicode/glib branch
  
  editwin.c: make locktext deal with UTF-8
  
  Jabber - 
  More utf-8 sanitizing.
  New helper function to validate strings from C and set the utf8 flag if needed.
........
  r887 | asedeno | 2008-01-16 21:54:55 -0500 (Wed, 16 Jan 2008) | 5 lines
  
  unicode/glib branch
  Remove a debug message I accidentally left in.
  Remove the hours old check_utf8 hackery in favor of actually
  marking strings as UTF-8 from the C side.
........
  r888 | asedeno | 2008-01-16 21:58:09 -0500 (Wed, 16 Jan 2008) | 2 lines
  
  unicode/glib branch
  Remove more bad hacks.
........
  r892 | asedeno | 2008-01-17 01:23:53 -0500 (Thu, 17 Jan 2008) | 4 lines
  
  unicode/glib branch
  editwin.c - lots of utf-8 cleanup that I had been putting off.
  util.c - a can we break here'' function based on perl's Text::WrapI18N
........
  r893 | asedeno | 2008-01-17 02:03:11 -0500 (Thu, 17 Jan 2008) | 3 lines
  
  unicode/glib branch
  editwin.c - fix a wrapping bug I introduced in the last revision.
  It could leave us with a buffer that was not valid UTF-8
........
  r895 | asedeno | 2008-01-17 09:51:48 -0500 (Thu, 17 Jan 2008) | 2 lines
  
  unicode/glib branch
  removing more hackery I left behind after doing things the right way.
........
  r896 | asedeno | 2008-01-17 14:55:22 -0500 (Thu, 17 Jan 2008) | 3 lines
  
  unicode/glib branch
  better compliance with UTF-8 processing. Stop trying to pull in a UTF-8
  character as soon as we know something has gone wrong.
........
  r929 | asedeno | 2008-02-04 20:17:18 -0500 (Mon, 04 Feb 2008) | 4 lines
  
  unicode/glib branch
  * fix a typo in OWL_FMTEXT_UTF8_BGDEFAULT
  * fix a parsing issue for attributes
........
  r930 | asedeno | 2008-02-04 20:33:04 -0500 (Mon, 04 Feb 2008) | 3 lines
  
  unicode/glib branch
  * Fix nelhage's key_left bug. Don't spin at the locktext boundary.
........
  r931 | asedeno | 2008-02-04 21:23:16 -0500 (Mon, 04 Feb 2008) | 2 lines
  
  unicode/glib branch
  I think I like this better.
........
  r932 | asedeno | 2008-02-07 14:01:23 -0500 (Thu, 07 Feb 2008) | 6 lines
  
  unicode/glib branch
  
  Fix a bug in owl_editwin_move_to_previousword() which would skip over
  single letter words.
........
  r938 | nelhage | 2008-02-13 23:39:41 -0500 (Wed, 13 Feb 2008) | 2 lines
  
  Rename configure.in to configure.ac so Debian autoconf DTRT.
........
  r961 | asedeno | 2008-02-19 21:52:10 -0500 (Tue, 19 Feb 2008) | 1 line
  
  Fixing an obscure wrapping bug that nelhage and I tracked down.
........
  r979 | asedeno | 2008-03-02 18:30:35 -0500 (Sun, 02 Mar 2008) | 1 line
  
  Fix a unicode branch wordwrap problem.
........
  r1021 | asedeno | 2008-04-15 12:09:13 -0400 (Tue, 15 Apr 2008) | 1 line
  
  Unicode branch: Fix building without zephyr.
........
  r1032 | nelhage | 2008-05-02 16:17:10 -0400 (Fri, 02 May 2008) | 3 lines
  
  Put glib's CFLAGS and LDFLAGS at the beginning of the corresponding
  variables.
........



Property changes on: trunk
___________________________________________________________________
Name: svnmerge-integrated
   - /branches/barnowl_sqlite:1-735 /branches/barnowl_unicode:1-734
   + /branches/barnowl_sqlite:1-735 /branches/barnowl_unicode:1-1039

Modified: trunk/owl/Makefile.in
===================================================================
--- trunk/owl/Makefile.in	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/Makefile.in	2008-05-12 02:57:44 UTC (rev 1040)
@@ -25,7 +25,8 @@
      regex.c history.c view.c dict.c variable.c filterelement.c pair.c \
      keypress.c keymap.c keybinding.c cmd.c context.c zcrypt.c \
      aim.c buddy.c buddylist.c timer.c style.c errqueue.c \
-     zbuddylist.c muxevents.c popexec.c obarray.c select.c
+     zbuddylist.c muxevents.c popexec.c obarray.c select.c wcwidth.c \
+     glib_compat.c
 OWL_SRC = owl.c
 TESTER_SRC = tester.c
 

Modified: trunk/owl/aim.c
===================================================================
--- trunk/owl/aim.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/aim.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -947,13 +947,13 @@
     return -1;
   
   if (modname) {
-    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
+    if (!(filename = owl_malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
       /* perror("memrequest: malloc"); */
       return -1;
     }
     sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
   } else {
-    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
+    if (!(filename = owl_malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
       /* perror("memrequest: malloc"); */
       return -1;
     }
@@ -963,7 +963,7 @@
   if (stat(filename, &st) == -1) {
     if (!modname) {
       /* perror("memrequest: stat"); */
-      free(filename);
+      owl_free(filename);
       return -1;
     }
     invalid = 1;
@@ -985,14 +985,14 @@
   if (invalid) {
     int i;
     
-    free(filename); /* not needed */
+    owl_free(filename); /* not needed */
     owl_function_error("getaimdata memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
     i = 8;
     if (modname) {
       i+=strlen(modname);
     }
     
-    if (!(buf = malloc(i))) {
+    if (!(buf = owl_malloc(i))) {
       return -1;
     }
     
@@ -1016,31 +1016,31 @@
     *bufret = buf;
     *buflenret = i;
   } else {
-    if (!(buf = malloc(len))) {
-      free(filename);
+    if (!(buf = owl_malloc(len))) {
+      owl_free(filename);
       return -1;
     }
     /* printf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); */
     if (!(f = fopen(filename, "r"))) {
       /* perror("memrequest: fopen"); */
-      free(filename);
-      free(buf);
+      owl_free(filename);
+      owl_free(buf);
       return -1;
     }
     
-    free(filename);
+    owl_free(filename);
     
     if (fseek(f, offset, SEEK_SET) == -1) {
       /* perror("memrequest: fseek"); */
       fclose(f);
-      free(buf);
+      owl_free(buf);
       return -1;
     }
     
     if (fread(buf, len, 1, f) != 1) {
       /* perror("memrequest: fread"); */
       fclose(f);
-      free(buf);
+      owl_free(buf);
       return -1;
     }
     
@@ -1075,7 +1075,7 @@
   
   if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
     aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
-    free(buf);
+    owl_free(buf);
   } else {
     owl_function_debugmsg("faimtest_memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname);
     aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
@@ -1341,12 +1341,12 @@
       char *newbuf;
       int z;
       
-      newbuf = malloc(i+1);
+      newbuf = owl_malloc(i+1);
       for (z = 0; z < i; z++)
 	newbuf[z] = (z % 10)+0x30;
       newbuf[i] = '\0';
       /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK | AIM_IMFLAGS_AWAY, newbuf); */
-      free(newbuf);
+      owl_free(newbuf);
     }
   } else if (strstr(tmpstr, "seticqstatus")) {
     aim_setextstatus(sess, AIM_ICQ_STATE_DND);

Modified: trunk/owl/cmd.c
===================================================================
--- trunk/owl/cmd.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/cmd.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -73,7 +73,7 @@
   char *retval = NULL;
   owl_cmd *cmd;
 
-  tmpbuff=strdup(cmdbuff);
+  tmpbuff=owl_strdup(cmdbuff);
   argv=owl_parseline(tmpbuff, &argc);
   if (argc < 0) {
     owl_free(tmpbuff);

Modified: trunk/owl/config.h.in
===================================================================
--- trunk/owl/config.h.in	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/config.h.in	2008-05-12 02:57:44 UTC (rev 1040)
@@ -21,9 +21,6 @@
 /* Define to 1 if you have the `com_err' library (-lcom_err). */
 #undef HAVE_LIBCOM_ERR
 
-/* Define to 1 if you have the `curses' library (-lcurses). */
-#undef HAVE_LIBCURSES
-
 /* Define to 1 if you have the `des425' library (-ldes425). */
 #undef HAVE_LIBDES425
 
@@ -39,9 +36,6 @@
 /* Define to 1 if you have the `krb5' library (-lkrb5). */
 #undef HAVE_LIBKRB5
 
-/* Define to 1 if you have the `ncurses' library (-lncurses). */
-#undef HAVE_LIBNCURSES
-
 /* Define to 1 if you have the `ncursesw' library (-lncursesw). */
 #undef HAVE_LIBNCURSESW
 

Copied: trunk/owl/configure.ac (from rev 938, branches/barnowl_unicode/owl/configure.ac)
===================================================================
--- trunk/owl/configure.ac	                        (rev 0)
+++ trunk/owl/configure.ac	2008-05-12 02:57:44 UTC (rev 1040)
@@ -0,0 +1,130 @@
+dnl $Id$
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(owl.c)
+
+AC_CONFIG_HEADER(config.h)
+
+AC_PROG_CC
+
+dnl If we're using GCC, enable all warnings
+if test "$GCC" = yes; then
+     CFLAGS="$CFLAGS -Wall -g";
+fi
+
+m4_include(/usr/share/aclocal/pkg.m4)
+dnl m4_include(pkg.m4)
+
+dnl Check for Athena
+AC_MSG_CHECKING(for /usr/athena/include)
+if test -d /usr/athena/include; then
+	CFLAGS=${CFLAGS}\ -I/usr/athena/include
+	CPPFLAGS=${CPPFLAGS}\ -I/usr/athena/include
+	AC_MSG_RESULT(yes)
+else
+	AC_MSG_RESULT(no)
+fi
+AC_MSG_CHECKING(for /usr/athena/lib)
+if test -d /usr/athena/lib; then
+	LDFLAGS=${LDFLAGS}\ -L/usr/athena/lib
+	AC_MSG_RESULT(yes)
+else
+	AC_MSG_RESULT(no)
+fi
+
+dnl Check for kerberosIV include
+AC_MSG_CHECKING(for kerberosIV)
+if test -d /usr/include/kerberosIV; then
+        CFLAGS=${CFLAGS}\ -I/usr/include/kerberosIV
+        CPPFLAGS=${CPPFLAGS}\ -I/usr/include/kerberosIV
+        AC_MSG_RESULT(yes)
+elif test -d /usr/local/include/kerberosIV; then
+        CFLAGS=${CFLAGS}\ -I/usr/local/include/kerberosIV
+        CPPFLAGS=${CPPFLAGS}\ -I/usr/local/include/kerberosIV
+        AC_MSG_RESULT(yes)
+else
+        AC_MSG_RESULT(no)
+fi
+
+AC_CHECK_LIB(ncursesw, initscr,, AC_MSG_ERROR(No curses library found.))
+AC_CHECK_LIB(com_err, com_err)
+AC_CHECK_LIB(nsl, gethostbyname)
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(k5crypto, krb5_derive_key)
+dnl AC_CHECK_LIB(des425, req_act_vno)
+AC_CHECK_LIB(des425, des_cbc_encrypt)
+AC_CHECK_LIB(resolv, res_search)
+AC_CHECK_LIB(krb5, krb5_get_credentials)
+AC_CHECK_LIB(krb4, krb_sendauth,,
+   AC_CHECK_LIB(krb, krb_sendauth))
+dnl AC_CHECK_LIB(zephyr, ZGetSender,, AC_MSG_ERROR(No zephyr library found.))
+AC_CHECK_LIB(zephyr, ZGetSender)
+AC_CHECK_LIB(zephyr, ZInitLocationInfo, AC_DEFINE([HAVE_LIBZEPHYR_ZINITLOCATIONINFO], [], [Have ZInitLocationInfo]),)
+
+AC_ARG_ENABLE([athstatic], AS_HELP_STRING([--enable-athstatic],
+                                          [Statically link libraries in /usr/athena/lib]),
+                                          [ATHSTATIC=./athstatic],
+                                          [ATHSTATIC=])
+
+AC_CHECK_FUNCS(use_default_colors resizeterm des_string_to_key des_key_sched des_ecb_encrypt)
+
+AC_MSG_CHECKING(for des_ecb_encrypt prototype)
+AC_TRY_COMPILE([#include <des.h>
+int des_ecb_encrypt(char foo[], char bar[], des_key_schedule baz, int qux);],
+[int foo = des_ecb_encrypt(0,0,0,0);],
+ac_cv_des_ecb_encrypt_proto=no,
+ac_cv_des_ecb_encrypt_proto=yes)
+AC_MSG_RESULT($ac_cv_des_ecb_encrypt_proto)
+if test "$ac_cv_des_ecb_encrypt_proto" = yes; then
+	AC_DEFINE([HAVE_DES_ECB_ENCRYPT_PROTO], [], [have proto for des_ecb_encrypt])
+fi
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(strings.h sys/ioctl.h sys/filio.h unistd.h com_err.h)
+
+dnl Add CFLAGS for embeded perl
+FOO=`perl -MExtUtils::Embed -e ccopts`
+echo Adding perl CFLAGS ${FOO}
+CFLAGS=${CFLAGS}\ ${FOO}
+
+dnl Find the location of perl XSUBPP
+AC_MSG_CHECKING(for the perl xsubpp precompiler)
+XSUBPPDIR="`(perl -MExtUtils::MakeMaker -e 'print ExtUtils::MakeMaker->new({NAME => qw(owl)})->tool_xsubpp;') | grep \^XSUBPPDIR | sed -e 's/XSUBPPDIR = //g;'`"
+if test -n "${XSUBPPDIR}"; then
+   AC_MSG_RESULT(${XSUBPPDIR})
+else
+   AC_MSG_ERROR(not found)
+fi
+
+if test -f "${XSUBPPDIR}/typemap"; then
+   XSUBPPFLAGS="-typemap ${XSUBPPDIR}/typemap"
+else
+   XSUBPPFLAGS=""
+fi
+
+dnl Add LDFLAGS for embedded perl
+FOO=`perl -MExtUtils::Embed -e ldopts`
+echo Adding perl LDFLAGS ${FOO}
+LDFLAGS=${LDFLAGS}\ ${FOO}
+
+dnl Add CFLAGS and LDFLAGS for glib-2.0
+PKG_CHECK_MODULES(GLIB,glib-2.0)
+
+echo Adding glib-2.0 CFLAGS ${GLIB_CFLAGS}
+CFLAGS="${GLIB_CFLAGS} ${CFLAGS}"
+echo Adding glib-2.0 LDFLAGS ${GLIB_LIBS}
+LDFLAGS="${GLIB_LIBS} ${LDFLAGS}"
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+
+AC_SUBST(XSUBPPDIR)
+AC_SUBST(XSUBPPFLAGS)
+AC_SUBST(ATHSTATIC)
+
+AC_PROG_INSTALL
+
+AC_CONFIG_SUBDIRS(libfaim)
+
+AC_OUTPUT(Makefile)

Deleted: trunk/owl/configure.in
===================================================================
--- trunk/owl/configure.in	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/configure.in	2008-05-12 02:57:44 UTC (rev 1040)
@@ -1,121 +0,0 @@
-dnl $Id$
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT(owl.c)
-
-AC_CONFIG_HEADER(config.h)
-
-AC_PROG_CC
-
-dnl If we're using GCC, enable all warnings
-if test "$GCC" = yes; then
-     CFLAGS="$CFLAGS -Wall -g";
-fi
-
-
-dnl Check for Athena
-AC_MSG_CHECKING(for /usr/athena/include)
-if test -d /usr/athena/include; then
-	CFLAGS=${CFLAGS}\ -I/usr/athena/include
-	CPPFLAGS=${CPPFLAGS}\ -I/usr/athena/include
-	AC_MSG_RESULT(yes)
-else
-	AC_MSG_RESULT(no)
-fi
-AC_MSG_CHECKING(for /usr/athena/lib)
-if test -d /usr/athena/lib; then
-	LDFLAGS=${LDFLAGS}\ -L/usr/athena/lib
-	AC_MSG_RESULT(yes)
-else
-	AC_MSG_RESULT(no)
-fi
-
-dnl Check for kerberosIV include
-AC_MSG_CHECKING(for kerberosIV)
-if test -d /usr/include/kerberosIV; then
-        CFLAGS=${CFLAGS}\ -I/usr/include/kerberosIV
-        CPPFLAGS=${CPPFLAGS}\ -I/usr/include/kerberosIV
-        AC_MSG_RESULT(yes)
-elif test -d /usr/local/include/kerberosIV; then
-        CFLAGS=${CFLAGS}\ -I/usr/local/include/kerberosIV
-        CPPFLAGS=${CPPFLAGS}\ -I/usr/local/include/kerberosIV
-        AC_MSG_RESULT(yes)
-else
-        AC_MSG_RESULT(no)
-fi
-
-AC_CHECK_LIB(ncursesw, initscr,,
-  AC_CHECK_LIB(ncurses, initscr,,
-    AC_CHECK_LIB(curses, initscr,, AC_MSG_ERROR(No curses library found.))))
-AC_CHECK_LIB(com_err, com_err)
-AC_CHECK_LIB(nsl, gethostbyname)
-AC_CHECK_LIB(socket, socket)
-AC_CHECK_LIB(k5crypto, krb5_derive_key)
-dnl AC_CHECK_LIB(des425, req_act_vno)
-AC_CHECK_LIB(des425, des_cbc_encrypt)
-AC_CHECK_LIB(resolv, res_search)
-AC_CHECK_LIB(krb5, krb5_get_credentials)
-AC_CHECK_LIB(krb4, krb_sendauth,,
-   AC_CHECK_LIB(krb, krb_sendauth))
-dnl AC_CHECK_LIB(zephyr, ZGetSender,, AC_MSG_ERROR(No zephyr library found.))
-AC_CHECK_LIB(zephyr, ZGetSender)
-AC_CHECK_LIB(zephyr, ZInitLocationInfo, AC_DEFINE([HAVE_LIBZEPHYR_ZINITLOCATIONINFO], [], [Have ZInitLocationInfo]),)
-
-AC_ARG_ENABLE([athstatic], AS_HELP_STRING([--enable-athstatic],
-                                          [Statically link libraries in /usr/athena/lib]),
-                                          [ATHSTATIC=./athstatic],
-                                          [ATHSTATIC=])
-
-AC_CHECK_FUNCS(use_default_colors resizeterm des_string_to_key des_key_sched des_ecb_encrypt)
-
-AC_MSG_CHECKING(for des_ecb_encrypt prototype)
-AC_TRY_COMPILE([#include <des.h>
-int des_ecb_encrypt(char foo[], char bar[], des_key_schedule baz, int qux);],
-[int foo = des_ecb_encrypt(0,0,0,0);],
-ac_cv_des_ecb_encrypt_proto=no,
-ac_cv_des_ecb_encrypt_proto=yes)
-AC_MSG_RESULT($ac_cv_des_ecb_encrypt_proto)
-if test "$ac_cv_des_ecb_encrypt_proto" = yes; then
-	AC_DEFINE([HAVE_DES_ECB_ENCRYPT_PROTO], [], [have proto for des_ecb_encrypt])
-fi
-
-dnl Checks for header files.
-AC_HEADER_STDC
-AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS(strings.h sys/ioctl.h sys/filio.h unistd.h com_err.h)
-
-dnl Add CFLAGS for embeded perl
-FOO=`perl -MExtUtils::Embed -e ccopts`
-echo Adding perl CFLAGS ${FOO}
-CFLAGS=${CFLAGS}\ ${FOO}
-
-dnl Find the location of perl XSUBPP
-AC_MSG_CHECKING(for the perl xsubpp precompiler)
-XSUBPPDIR="`(perl -MExtUtils::MakeMaker -e 'print ExtUtils::MakeMaker->new({NAME => qw(owl)})->tool_xsubpp;') | grep \^XSUBPPDIR | sed -e 's/XSUBPPDIR = //g;'`"
-if test -n "${XSUBPPDIR}"; then
-   AC_MSG_RESULT(${XSUBPPDIR})
-else
-   AC_MSG_ERROR(not found)
-fi
-
-if test -f "${XSUBPPDIR}/typemap"; then
-   XSUBPPFLAGS="-typemap ${XSUBPPDIR}/typemap"
-else
-   XSUBPPFLAGS=""
-fi
-
-dnl Add LDFLAGS for embedded perl
-FOO=`perl -MExtUtils::Embed -e ldopts`
-echo Adding perl LDFLAGS ${FOO}
-LDFLAGS=${LDFLAGS}\ ${FOO}
-
-dnl Checks for typedefs, structures, and compiler characteristics.
-
-AC_SUBST(XSUBPPDIR)
-AC_SUBST(XSUBPPFLAGS)
-AC_SUBST(ATHSTATIC)
-
-AC_PROG_INSTALL
-
-AC_CONFIG_SUBDIRS(libfaim)
-
-AC_OUTPUT(Makefile)

Modified: trunk/owl/editwin.c
===================================================================
--- trunk/owl/editwin.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/editwin.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -142,11 +142,12 @@
   e->buffx=0;
   e->buffy=0;
   owl_editwin_overwrite_string(e, text);
+  owl_editwin_overwrite_char(e, '\0');
   e->lock=strlen(text);
   /* if (text[e->lock-1]=='\n') e->lock--; */
-  e->buffx=x;
-  e->buffy=y;
-  owl_editwin_adjust_for_locktext(e);
+  /*  e->buffx=x; */
+  /*  e->buffy=y; */
+  _owl_editwin_set_xy_by_index(e, e->lock);
   owl_editwin_redisplay(e, 0);
 }
 
@@ -254,187 +255,248 @@
   wmove(e->curswin, 0, 0);
 
   /* start at topline */
-  ptr1=e->buff;
-  for (i=0; i<e->topline; i++) {
-    ptr2=strchr(ptr1, '\n');
+  ptr1 = e->buff;
+  for (i = 0; i < e->topline; i++) {
+    ptr2 = strchr(ptr1, '\n');
     if (!ptr2) {
       /* we're already on the last line */
       break;
     }
-    ptr1=ptr2+1;
+    ptr1 = ptr2 + 1;
   }
   /* ptr1 now stores the starting point */
 
   /* find the ending point and store it in ptr3 */
-  ptr2=ptr1;
-  ptr3=ptr1;
-  for (i=0; i<e->winlines; i++) {
-    ptr3=strchr(ptr2, '\n');
+  ptr2 = ptr1;
+  ptr3 = ptr1;
+  for (i = 0; i < e->winlines; i++) {
+    ptr3 = strchr(ptr2, '\n');
     if (!ptr3) {
       /* we've hit the last line */
       /* print everything to the end */
-      ptr3=e->buff+e->bufflen-1;
+      ptr3 = e->buff + e->bufflen - 1;
       ptr3--;
       break;
     }
-    ptr2=ptr3+1;
+    ptr2 = ptr3 + 1;
   }
-  ptr3+=2;
+  ptr3 += 2;
 
-  buff=owl_malloc(ptr3-ptr1+50);
-  strncpy(buff, ptr1, ptr3-ptr1);
-  buff[ptr3-ptr1]='\0';
-  if (e->echochar=='\0') {
+  buff = owl_malloc(ptr3 - ptr1 + 50);
+  strncpy(buff, ptr1, ptr3 - ptr1);
+  buff[ptr3 - ptr1] = '\0';
+  if (e->echochar == '\0') {
     waddstr(e->curswin, buff);
   } else {
     /* translate to echochar, *except* for the locktext */
     int len;
-    int dolocklen=e->lock-(ptr1-e->buff);
+    int dolocklen = e->lock - (ptr1 - e->buff);
+    char *locktext;
+    char tmp = e->buff[dolocklen];
 
-    for (i=0; i<dolocklen; i++) {
-      waddch(e->curswin, buff[i]);
-    }
-    len=strlen(buff);
-    for (i=0; i<len-dolocklen; i++) {
+    e->buff[dolocklen] = '\0';
+    locktext = owl_strdup(e->buff);
+    e->buff[dolocklen] = tmp;
+
+    waddstr(e->curswin, locktext);
+    
+    len = strlen(buff);
+    for (i = 0; i < len-dolocklen; i++) {
       waddch(e->curswin, e->echochar);
     }
   }
-  wmove(e->curswin, e->buffy-e->topline, e->buffx);
+  wmove(e->curswin, e->buffy-e->topline, e->buffx + _owl_editwin_cursor_adjustment(e));
   wnoutrefresh(e->curswin);
-  if (update==1) {
+  if (update == 1) {
     doupdate();
   }
   owl_free(buff);
 }
 
+/* Remove n bytes at cursor. */
+void _owl_editwin_remove_bytes(owl_editwin *e, int n) /*noproto*/
+{
+  int i = _owl_editwin_get_index_from_xy(e) + n;
+  for (; i < e->bufflen; i++) {
+    e->buff[i-n] = e->buff[i];
+  }
+  
+  e->bufflen -= n;
+  e->buff[e->bufflen] = '\0';
+}
 
+/* Insert n bytes at cursor.*/
+void _owl_editwin_insert_bytes(owl_editwin *e, int n) /*noproto*/
+{
+  int i, z;
+  
+  if ((e->bufflen + n) > (e->allocated - 5)) {
+    _owl_editwin_addspace(e);
+  }
+
+  e->bufflen += n;
+  e->buff[e->bufflen] = '\0';
+  
+  z = _owl_editwin_get_index_from_xy(e);
+  for (i = e->bufflen - 1; i > z; i--) {
+    e->buff[i] = e->buff[i - n];
+  }
+}
+
+
 /* linewrap the word just before the cursor.
  * returns 0 on success
  * returns -1 if we could not wrap.
  */
 int _owl_editwin_linewrap_word(owl_editwin *e)
 {
-  int i, z;
+  int x, y;
+  int i;
+  char *ptr1, *start;
+  gunichar c;
 
-  z=_owl_editwin_get_index_from_xy(e);
-  /* move back and line wrap the previous word */
-  for (i=z-1; ; i--) {
-    /* move back until you find a space or hit the beginning of the line */
-    if (e->buff[i]==' ') {
-      /* replace the space with a newline */
-      e->buff[i]='\n';
-      e->buffy++;
-      e->buffx=z-i-1;
-      /* were we on the last line */
-      return(0);
-    } else if (e->buff[i]=='\n' || i<=e->lock) {
-      /* we hit the begginning of the line or the buffer, we cannot
-       * wrap.
-       */
-      return(-1);
+  /* saving values */
+  x = e->buffx;
+  y = e->buffy;
+  start = e->buff + e->lock;
+
+  ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
+  ptr1 = g_utf8_find_prev_char(start, ptr1);
+
+  while (ptr1) {
+    c = g_utf8_get_char(ptr1);
+    if (owl_util_can_break_after(c)) {
+      if (c != ' ') {
+        i = ptr1 - e->buff;
+        _owl_editwin_set_xy_by_index(e, i);
+        _owl_editwin_insert_bytes(e, 1);
+        /* _owl_editwin_insert_bytes may move e->buff. */
+        ptr1 = e->buff + i;
+      }
+      *ptr1 = '\n';
+      return 0;
     }
+    else if (c == '\n') {
+      return 0;
+    }
+    ptr1 = g_utf8_find_prev_char(start, ptr1);
   }
+  return -1;
 }
 
 /* insert a character at the current point (shift later
  * characters over)
  */
-void owl_editwin_insert_char(owl_editwin *e, char c)
+void owl_editwin_insert_char(owl_editwin *e, gunichar c)
 {
-  
-  int z, i, ret;
+  int z, i, ret, len;
+  char tmp[6];
+  memset(tmp, '\0', 6);
 
   /* \r is \n */
-  if (c=='\r') {
-    c='\n';
+  if (c == '\r') {
+    c = '\n';
   }
 
-  if (c=='\n' && e->style==OWL_EDITWIN_STYLE_ONELINE) {
+  if (c == '\n' && e->style == OWL_EDITWIN_STYLE_ONELINE) {
     /* perhaps later this will change some state that allows the string
        to be read */
     return;
   }
 
+  g_unichar_to_utf8(c, tmp);
+  len = strlen(tmp);
+
   /* make sure there is enough memory for the new text */
-  if ((e->bufflen+1) > (e->allocated-5)) {
+  if ((e->bufflen + len) > (e->allocated - 5)) {
     _owl_editwin_addspace(e);
   }
 
   /* get the insertion point */
-  z=_owl_editwin_get_index_from_xy(e);
+  z = _owl_editwin_get_index_from_xy(e);
 
   /* If we're going to insert at the last column do word wrapping, unless it's a \n */
-  if ((e->buffx+1==e->wrapcol) && (c!='\n')) {
-    ret=_owl_editwin_linewrap_word(e);
-    if (ret==-1) {
+  if ((e->buffx + 1 == e->wrapcol) && (c != '\n')) {
+    ret = _owl_editwin_linewrap_word(e);
+    if (ret == -1) {
       /* we couldn't wrap, insert a hard newline instead */
       owl_editwin_insert_char(e, '\n');
     }
   }
 
-  z=_owl_editwin_get_index_from_xy(e);
   /* shift all the other characters right */
-  for (i=e->bufflen; i>z; i--) {
-    e->buff[i]=e->buff[i-1];
+  if (z != e->bufflen) {
+    _owl_editwin_insert_bytes(e, len);
   }
 
-  /* insert the new one */
-  e->buff[z]=c;
+  /* insert the new character */
+  for(i = 0; i < len; i++) {
+    e->buff[z + i] = tmp[i];
+  }
 
   /* housekeeping */
-  e->bufflen++;
-  e->buff[e->bufflen]='\0';
-
+  e->bufflen += len;
+  e->buff[e->bufflen] = '\0';
+  
   /* advance the cursor */
-  if (c=='\n') {
-    e->buffx=0;
-    e->buffy++;
-  } else {
-    e->buffx++;
-  }
+  z += len;
+  _owl_editwin_set_xy_by_index(e, z);
 }
 
 /* overwrite the character at the current point with 'c' */
-void owl_editwin_overwrite_char(owl_editwin *e, char c)
+void owl_editwin_overwrite_char(owl_editwin *e, gunichar c)
 {
-  int z;
-  
+  int z, oldlen, newlen, i;
+  char tmp[6];
+  memset(tmp, '\0', 6);
+
   /* \r is \n */
-  if (c=='\r') {
-    c='\n';
+  if (c == '\r') {
+    c = '\n';
   }
-
-  if (c=='\n' && e->style==OWL_EDITWIN_STYLE_ONELINE) {
+  
+  if (c == '\n' && e->style == OWL_EDITWIN_STYLE_ONELINE) {
     /* perhaps later this will change some state that allows the string
        to be read */
     return;
   }
 
-  z=_owl_editwin_get_index_from_xy(e);
+  g_unichar_to_utf8(c, tmp);
+  newlen = strlen(tmp);
 
-  /* only if we are at the end of the buffer do we create new space */
-  if (z==e->bufflen) {
-    if ((e->bufflen+1) > (e->allocated-5)) {
+  z = _owl_editwin_get_index_from_xy(e);
+  {
+    char *t = g_utf8_find_next_char(e->buff + z, NULL);
+    oldlen = (t ? (t - (e->buff + z)) : 0);
+  }
+
+  /* only if we are at the end of the buffer do we create new space here */
+  if (z == e->bufflen) {
+    if ((e->bufflen+newlen) > (e->allocated-5)) {
       _owl_editwin_addspace(e);
     }
   }
+  /* if not at the end of the buffer, adjust based in char size difference. */ 
+  else if (oldlen > newlen) {
+    _owl_editwin_remove_bytes(e, oldlen-newlen);
+  }
+  else /* oldlen < newlen */ {
+    _owl_editwin_insert_bytes(e, newlen-oldlen);
+  }
+  /* Overwrite the old char*/
+  for (i = 0; i < newlen; i++) {
+    e->buff[z+i] = tmp[i];
+  }
+       
+  /* housekeeping */
+  if (z == e->bufflen) {
+    e->bufflen += newlen;
+    e->buff[e->bufflen] = '\0';
+  }
   
-  e->buff[z]=c;
-
-  /* housekeeping if we are at the end of the buffer */
-  if (z==e->bufflen) {
-    e->bufflen++;
-    e->buff[e->bufflen]='\0';
-  }
-
   /* advance the cursor */
-  if (c=='\n') {
-    e->buffx=0;
-    e->buffy++;
-  } else {
-    e->buffx++;
-  }
-
+  z += newlen;
+  _owl_editwin_set_xy_by_index(e, z);
 }
 
 /* delete the character at the current point, following chars
@@ -442,20 +504,25 @@
  */ 
 void owl_editwin_delete_char(owl_editwin *e)
 {
-  int z, i;
+  int z;
+  char *p1, *p2;
+  gunichar c;
 
-  if (e->bufflen==0) return;
+  if (e->bufflen == 0) return;
   
   /* get the deletion point */
-  z=_owl_editwin_get_index_from_xy(e);
+  z = _owl_editwin_get_index_from_xy(e);
 
-  if (z==e->bufflen) return;
+  if (z == e->bufflen) return;
 
-  for (i=z; i<e->bufflen; i++) {
-    e->buff[i]=e->buff[i+1];
+  p1 = e->buff + z;
+  p2 = g_utf8_next_char(p1);
+  c = g_utf8_get_char(p2);
+  while (g_unichar_ismark(c)) {
+    p2 = g_utf8_next_char(p2);
+    c = g_utf8_get_char(p2);
   }
-  e->bufflen--;
-  e->buff[e->bufflen]='\0';
+  _owl_editwin_remove_bytes(e, p2-p1);
 }
 
 /* Swap the character at point with the character at point-1 and
@@ -466,27 +533,45 @@
 void owl_editwin_transpose_chars(owl_editwin *e)
 {
   int z;
-  char tmp;
+  char *p1, *p2, *p3, *tmp;
 
-  if (e->bufflen==0) return;
+  if (e->bufflen == 0) return;
   
   /* get the cursor point */
-  z=_owl_editwin_get_index_from_xy(e);
+  z = _owl_editwin_get_index_from_xy(e);
 
-  if (z==e->bufflen) {
+  if (z == e->bufflen) {
     /* point is after last character */
     z--;
   }  
 
-  if (z-1 < e->lock) {
+  if (z - 1 < e->lock) {
     /* point is at beginning of buffer, do nothing */
     return;
   }
 
-  tmp=e->buff[z];
-  e->buff[z]=e->buff[z-1];
-  e->buff[z-1]=tmp;
-  owl_editwin_key_right(e);
+  /* Transpose two utf-8 unicode glyphs. */
+  p1 = e->buff + z;
+
+  p2 = g_utf8_find_next_char(p1, NULL);
+  while (p2 != NULL && g_unichar_ismark(g_utf8_get_char(p2))) {
+    p2 = g_utf8_find_next_char(p2, NULL);
+  }
+  if (p2 == NULL) return;
+
+  p3 = g_utf8_find_prev_char(e->buff, p1);
+  while (p3 != NULL && g_unichar_ismark(g_utf8_get_char(p3))) {
+    p3 = g_utf8_find_prev_char(p3, NULL);
+  }
+  if (p3 == NULL) return;
+
+  tmp = owl_malloc(p2 - p3 + 5);
+  *tmp = '\0';
+  strncat(tmp, p1, p2 - p1);
+  strncat(tmp, p3, p1 - p3);
+  strncpy(p3, tmp, p2 - p3);
+  owl_free(tmp);
+  _owl_editwin_set_xy_by_index(e, p3 - e->buff);
 }
 
 /* insert 'string' at the current point, later text is shifted
@@ -494,12 +579,19 @@
  */
 void owl_editwin_insert_string(owl_editwin *e, char *string)
 {
-  int i, j;
-
-  j=strlen(string);
-  for (i=0; i<j; i++) {
-    owl_editwin_insert_char(e, string[i]);
+  char *p;
+  gunichar c;
+  if (!g_utf8_validate(string, -1, NULL)) {
+    owl_function_debugmsg("owl_editwin_insert_string: received non-utf-8 string.");
+    return;
   }
+  p = string;
+  c = g_utf8_get_char(p);
+  while (c) {
+    _owl_editwin_process_char(e, c);
+    p = g_utf8_next_char(p);
+    c = g_utf8_get_char(p);
+  }
 }
 
 /* write 'string' at the current point, overwriting text that is
@@ -508,12 +600,20 @@
 
 void owl_editwin_overwrite_string(owl_editwin *e, char *string)
 {
-  int i, j;
+  char *p;
+  gunichar c;
 
-  j=strlen(string);
-  for (i=0; i<j; i++) {
-    owl_editwin_overwrite_char(e, string[i]);
+  if (!g_utf8_validate(string, -1, NULL)) {
+    owl_function_debugmsg("owl_editwin_overwrite_string: received non-utf-8 string.");
+    return;
   }
+  p = string;
+  c = g_utf8_get_char(p);
+  while (c) {
+    owl_editwin_overwrite_char(e, c);
+    p = g_utf8_next_char(p);
+    c = g_utf8_get_char(p);
+  }
 }
 
 /* get the index into e->buff for the current cursor
@@ -523,57 +623,115 @@
 {
   int i;
   char *ptr1, *ptr2;
+  gunichar c;
 
-  if (e->bufflen==0) return(0);
+  if (e->bufflen == 0) return(0);
   
   /* first go to the yth line */
-  ptr1=e->buff;
-  for (i=0; i<e->buffy; i++) {
-    ptr2=strchr(ptr1, '\n');
+  ptr1 = e->buff;
+  for (i = 0; i < e->buffy; i++) {
+    ptr2= strchr(ptr1, '\n');
     if (!ptr2) {
       /* we're already on the last line */
       break;
     }
-    ptr1=ptr2+1;
+    ptr1 = ptr2 + 1;
   }
 
-  /* now go to the xth character */
-  ptr2=strchr(ptr1, '\n');
-  if (!ptr2) {
-    ptr2=e->buff+e->bufflen;
+  /* now go to the xth cell */
+  ptr2 = ptr1;
+  i = 0;
+  while (ptr2 != NULL && i < e->buffx && (ptr2 - e->buff) < e->bufflen) {
+    c = g_utf8_get_char(ptr2);
+    i += (c == '\n' ? 1 : mk_wcwidth(c));
+    ptr2 = g_utf8_next_char(ptr2);
   }
-
-  if ((ptr2-ptr1) < e->buffx) {
-    ptr1=ptr2-1;
-  } else {
-    ptr1+=e->buffx;
+  while(ptr2 != NULL && g_unichar_ismark(g_utf8_get_char(ptr2))) {
+    ptr2 = g_utf8_next_char(ptr2);
   }
+  if (ptr2 == NULL) return e->bufflen;
+  return(ptr2 - e->buff);
+}
 
-  /* printf("DEBUG: index is %i\r\n", ptr1-e->buff); */
-  return(ptr1-e->buff);
+/* We assume x,y are not set to point to a mid-char */
+gunichar _owl_editwin_get_char_at_xy(owl_editwin *e)
+{
+  return g_utf8_get_char(e->buff + _owl_editwin_get_index_from_xy(e));
 }
 
+
 void _owl_editwin_set_xy_by_index(owl_editwin *e, int index)
 {
-  int z, i;
+  char *ptr1, *ptr2, *target;
+  gunichar c;
 
-  z=_owl_editwin_get_index_from_xy(e);
-  if (index>z) {
-    for (i=0; i<index-z; i++) {
-      owl_editwin_key_right(e);
-    }
-  } else if (index<z) {
-    for (i=0; i<z-index; i++) {
-      owl_editwin_key_left(e);
-    }
+  e->buffx = 0;
+  e->buffy = 0;
+
+  ptr1 = e->buff;
+  target = ptr1 + index;
+  /* target sanitizing */
+  if ((target[0] & 0x80) && (~target[0] & 0x40)) {
+    /* middle of a utf-8 character, back up to previous character. */
+    target = g_utf8_find_prev_char(e->buff, target);
   }
+  c = g_utf8_get_char(target);
+  while (g_unichar_ismark(c) && target > e->buff) {
+    /* Adjust the target off of combining characters and the like. */
+    target = g_utf8_find_prev_char(e->buff, target);
+    c = g_utf8_get_char(target);
+  }
+  /* If we start with a mark, something is wrong.*/
+  if (g_unichar_ismark(c)) return;
+
+  /* Now our target should be acceptable. */
+  ptr2 = strchr(ptr1, '\n');
+  while (ptr2 != NULL && ptr2 < target) {
+    e->buffy++;
+    ptr1 = ptr2 + 1;
+    ptr2 = strchr(ptr1, '\n');
+  }
+  ptr2 = ptr1;
+  while (ptr2 != NULL && ptr2 < target) {
+    c = g_utf8_get_char(ptr2);
+    e->buffx += mk_wcwidth(c);
+    ptr2 = g_utf8_next_char(ptr2);
+  }
 }
 
+int _owl_editwin_cursor_adjustment(owl_editwin *e)
+{
+  char *ptr1, *ptr2;
+  gunichar c;
+  int x, i;
+
+  /* Find line */
+  ptr1 = e->buff;
+  ptr2 = strchr(ptr1, '\n');
+  for (i = 0; ptr2 != NULL && i < e->buffy; i++) {
+    ptr1 = ptr2 + 1;
+    ptr2 = strchr(ptr1, '\n');
+  }
+  ptr2 = ptr1;
+
+  /* Find char */
+  x = 0;
+  while (ptr2 != NULL && x < e->buffx) {
+    if (*ptr2 == '\n') return 0;
+    c = g_utf8_get_char(ptr2);
+    x += mk_wcwidth(c);
+    ptr2 = g_utf8_next_char(ptr2);
+  }
+  
+  /* calculate x offset */
+  return x - e->buffx;
+}
+
 void owl_editwin_adjust_for_locktext(owl_editwin *e)
 {
   /* if we happen to have the cursor over locked text
    * move it to be out of the locktext region */
-  if (_owl_editwin_get_index_from_xy(e)<e->lock) {
+  if (_owl_editwin_get_index_from_xy(e) < e->lock) {
     _owl_editwin_set_xy_by_index(e, e->lock);
   }
 }
@@ -593,8 +751,8 @@
 void owl_editwin_key_up(owl_editwin *e)
 {
   if (e->buffy > 0) e->buffy--;
-  if (e->buffx >= owl_editwin_get_numchars_on_line(e, e->buffy)) {
-    e->buffx=owl_editwin_get_numchars_on_line(e, e->buffy);
+  if (e->buffx >= owl_editwin_get_numcells_on_line(e, e->buffy)) {
+    e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
   }
 
   /* do we need to scroll? */
@@ -611,8 +769,8 @@
   if (e->buffy+1 < owl_editwin_get_numlines(e)) e->buffy++;
 
   /* if we're past the last character move back */
-  if (e->buffx >= owl_editwin_get_numchars_on_line(e, e->buffy)) {
-    e->buffx=owl_editwin_get_numchars_on_line(e, e->buffy);
+  if (e->buffx >= owl_editwin_get_numcells_on_line(e, e->buffy)) {
+    e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
   }
 
   /* do we need to scroll? */
@@ -626,17 +784,19 @@
 
 void owl_editwin_key_left(owl_editwin *e)
 {
-  /* move left if we can, and maybe up a line */
-  if (e->buffx>0) {
-    e->buffx--;
-  } else if (e->buffy>0) {
-    e->buffy--;
-    e->buffx=owl_editwin_get_numchars_on_line(e, e->buffy);
+  int i;
+  char * p;
+  i = _owl_editwin_get_index_from_xy(e);
+  p = e->buff + i;
+  p = g_utf8_find_prev_char(e->buff, p);
+  while (p && g_unichar_ismark(g_utf8_get_char(p))) {
+    p = g_utf8_find_prev_char(e->buff, p);
   }
+  if (p == NULL) p = e->buff;
+  _owl_editwin_set_xy_by_index(e, p - e->buff);
 
-  /* do we need to scroll up? */
-  if (e->buffy-e->topline < 0) {
-    e->topline-=e->winlines/2;
+  if (e->buffy - e->topline < 0) {
+    e->topline -= e->winlines / 2;
   }
 
   /* make sure to avoid locktext */
@@ -646,28 +806,30 @@
 void owl_editwin_key_right(owl_editwin *e)
 {
   int i;
-
-  /* move right if we can, and skip down a line if needed */
-  i=owl_editwin_get_numchars_on_line(e, e->buffy);
-  if (e->buffx < i) {
-    e->buffx++;
-    /*  } else if (e->buffy+1 < owl_editwin_get_numlines(e)) { */
-  } else if (_owl_editwin_get_index_from_xy(e) < e->bufflen) {
-    if (e->style==OWL_EDITWIN_STYLE_MULTILINE) {
-      e->buffx=0;
-      e->buffy++;
-    }
+  char * p;
+  i = _owl_editwin_get_index_from_xy(e);
+  p = e->buff + i;
+  p = g_utf8_find_next_char(p, NULL);
+  while (p && g_unichar_ismark(g_utf8_get_char(p))) {
+    p = g_utf8_find_next_char(p, NULL);
   }
+  if (p == NULL) {
+    _owl_editwin_set_xy_by_index(e, e->bufflen);
+  }
+  else {
+    _owl_editwin_set_xy_by_index(e, p - e->buff);
+  }
 
   /* do we need to scroll down? */
-  if (e->buffy-e->topline >= e->winlines) {
-    e->topline+=e->winlines/2;
+  if (e->buffy - e->topline >= e->winlines) {
+    e->topline += e->winlines / 2;
   }
 }
 
 void owl_editwin_move_to_nextword(owl_editwin *e)
 {
   int i, x;
+  gunichar c = '\0';
 
   /* if we're starting on a space, find the first non-space */
   i=_owl_editwin_get_index_from_xy(e);
@@ -680,20 +842,22 @@
     }
   }
 
-  /* find the next space, newline or end of line and go there, if
-     already at the end of the line, continue on to the next */
-  i=owl_editwin_get_numchars_on_line(e, e->buffy);
+  /* find the next space, newline or end of line and go
+     there, if already at the end of the line, continue on to the next */
+  i=owl_editwin_get_numcells_on_line(e, e->buffy);
+  c = _owl_editwin_get_char_at_xy(e);
   if (e->buffx < i) {
     /* move right till end of line */
     while (e->buffx < i) {
-      e->buffx++;
-      if (e->buff[_owl_editwin_get_index_from_xy(e)]==' ') return;
+      owl_editwin_key_right(e);
+      c = _owl_editwin_get_char_at_xy(e);
+      if (c == ' ') return;
       if (e->buffx == i) return;
     }
   } else if (e->buffx == i) {
     /* try to move down */
     if (e->style==OWL_EDITWIN_STYLE_MULTILINE) {
-      if (e->buffy+1 <  owl_editwin_get_numlines(e)) {
+      if (e->buffy+1 < owl_editwin_get_numlines(e)) {
 	e->buffx=0;
 	e->buffy++;
 	owl_editwin_move_to_nextword(e);
@@ -706,87 +870,98 @@
  */
 void owl_editwin_move_to_previousword(owl_editwin *e)
 {
-  int i, x;
+  int i;
+  gunichar c;
+  char *ptr1, *ptr2;
 
   /* are we already at the beginning of the word? */
-  i=_owl_editwin_get_index_from_xy(e);
-  if ( (e->buff[i]!=' ' && e->buff[i]!='\n' && e->buff[i]!='\0') &&
-       (e->buff[i-1]==' ' || e->buff[i-1]=='\n') ) {
-    owl_editwin_key_left(e);
+  c = _owl_editwin_get_char_at_xy(e);
+  i = _owl_editwin_get_index_from_xy(e);
+  ptr1 = e->buff + i;
+  if (*ptr1 != ' ' && *ptr1 != '\n' && *ptr1 != '\0' ) {
+    ptr1 = g_utf8_find_prev_char(e->buff, ptr1);
+    c = g_utf8_get_char(ptr1);
+    if (c == ' ' || c == '\n') {
+      owl_editwin_key_left(e);      
+    }
   }
-    
+
   /* are we starting on a space character? */
-  i=_owl_editwin_get_index_from_xy(e);
-  if (e->buff[i]==' ' || e->buff[i]=='\n' || e->buff[i]=='\0') {
+  i = _owl_editwin_get_index_from_xy(e);
+  while (i > e->lock && (e->buff[i] == ' ' || e->buff[i] == '\n' || e->buff[i] == '\0')) {
     /* find the first non-space */
-    for (x=i; x>=e->lock; x--) {
-      if (e->buff[x]!=' ' && e->buff[x]!='\n' && e->buff[x]!='\0') {
-	_owl_editwin_set_xy_by_index(e, x);
-	break;
-      }
-    }
+    owl_editwin_key_left(e);      
+    i = _owl_editwin_get_index_from_xy(e);
   }
 
   /* find the last non-space */
-  i=_owl_editwin_get_index_from_xy(e);
-  for (x=i; x>=e->lock; x--) {
-    if (e->buff[x-1]==' ' || e->buff[x-1]=='\n') {
-      _owl_editwin_set_xy_by_index(e, x);
+  ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
+  while (ptr1 >= e->buff + e->lock) {
+    ptr2 = g_utf8_find_prev_char(e->buff, ptr1);
+    if (!ptr2) break;
+    
+    c = g_utf8_get_char(ptr2);
+    if (c == ' ' || c == '\n'){
       break;
     }
+    owl_editwin_key_left(e);
+    ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
   }
-  _owl_editwin_set_xy_by_index(e, x);
 }
 
 
 void owl_editwin_delete_nextword(owl_editwin *e)
 {
-  int z;
+  char *ptr1, *start;
+  gunichar c;
 
   if (e->bufflen==0) return;
 
-  /* if we start out on a space character then gobble all the spaces
-     up first */
-  while (1) {
-    z=_owl_editwin_get_index_from_xy(e);
-    if (e->buff[z]==' ' || e->buff[z]=='\n') {
-      owl_editwin_delete_char(e);
-    } else {
-      break;
-    }
+  start = ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
+  /* if we start out on a space character then jump past all the
+     spaces up first */
+  while (*ptr1 == ' ' || *ptr1 == '\n') {
+    ++ptr1;
   }
 
-  /* then nuke the next word */
-  while (1) {
-    z=_owl_editwin_get_index_from_xy(e);
-    /* z == e->bufflen check added to prevent a hang I (nelhage) have
-       seen repeatedly while using owl. I'm not sure precisely what
-       conditions lead to it. */
-    if (z == e->bufflen
-        || e->buff[z+1]==' ' || e->buff[z+1]=='\n' || e->buff[z+1]=='\0') break;
-    owl_editwin_delete_char(e);
+  /* then jump past the next word */
+  
+  while (ptr1 && ptr1 - e->buff < e->bufflen) {
+    c = g_utf8_get_char(ptr1);
+    if (c == ' ' || c == '\n' || c == '\0') break;
+    ptr1 = g_utf8_find_next_char(ptr1, NULL);
   }
-  owl_editwin_delete_char(e);
+
+  if (ptr1) { /* We broke on a space, */
+    ptr1 = g_utf8_find_next_char(ptr1, NULL);
+    if (ptr1) { /* and there's a character after it, */
+      /* nuke everything back to our starting point. */
+      _owl_editwin_remove_bytes(e, ptr1 - start);
+      return;
+    }
+  }
+  
+  /* If we get here, we ran out of string, drop what's left. */
+  *start = '\0';
+  e->bufflen = start - e->buff;
 }
 
 void owl_editwin_delete_previousword(owl_editwin *e)
 {
   /* go backwards to the last non-space character, then delete chars */
-  int i, startpos, endpos;
+  int startpos, endpos;
 
   startpos = _owl_editwin_get_index_from_xy(e);
   owl_editwin_move_to_previousword(e);
   endpos = _owl_editwin_get_index_from_xy(e);
-  for (i=0; i<startpos-endpos; i++) {
-    owl_editwin_delete_char(e);
-  }
+  _owl_editwin_remove_bytes(e, startpos-endpos);
 }
 
 void owl_editwin_delete_to_endofline(owl_editwin *e)
 {
   int i;
 
-  if (owl_editwin_get_numchars_on_line(e, e->buffy)>e->buffx) {
+  if (owl_editwin_get_numchars_on_line(e, e->buffy) > e->buffx) {
     /* normal line */
     i=_owl_editwin_get_index_from_xy(e);
     while(i < e->bufflen) {
@@ -807,7 +982,7 @@
 
 void owl_editwin_move_to_line_end(owl_editwin *e)
 {
-  e->buffx=owl_editwin_get_numchars_on_line(e, e->buffy);
+  e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
 }
 
 void owl_editwin_move_to_line_start(owl_editwin *e)
@@ -820,7 +995,7 @@
 {
   /* go to last char */
   e->buffy=owl_editwin_get_numlines(e)-1;
-  e->buffx=owl_editwin_get_numchars_on_line(e, e->buffy);
+  e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
   owl_editwin_key_right(e);
 
   /* do we need to scroll? */
@@ -860,40 +1035,48 @@
 
   /* main loop */
   while (1) {
-    i=_owl_editwin_get_index_from_xy(e);
+    i = _owl_editwin_get_index_from_xy(e);
 
     /* bail if we hit the end of the buffer */
-    if (i>=e->bufflen) break;
+    if (i >= e->bufflen || e->buff[i] == '\0') break;
 
     /* bail if we hit the end of the paragraph */
-    if (e->buff[i]=='\n' && e->buff[i+1]=='\n') break;
+    if (e->buff[i] == '\n' && e->buff[i+1] == '\n') break;
 
     /* if we've travelled too far, linewrap */
     if ((e->buffx) >= e->fillcol) {
+      int len = e->bufflen;
       _owl_editwin_linewrap_word(e);
+      /* we may have added a character. */
+      if (i < save) save += e->bufflen - len;
+      _owl_editwin_set_xy_by_index(e, i);
     }
 
     /* did we hit the end of a line too soon? */
-    i=_owl_editwin_get_index_from_xy(e);
-    if (e->buff[i]=='\n' && e->buffx<e->fillcol-1) {
+    /* asedeno: Here we replace a newline with a space. We may want to
+       consider removing the space if the characters to either side
+       are CJK ideograms.*/
+    i = _owl_editwin_get_index_from_xy(e);
+    if (e->buff[i] == '\n' && e->buffx < e->fillcol - 1) {
       /* ********* we need to make sure we don't pull in a word that's too long ***********/
       e->buff[i]=' ';
     }
-    
+
     /* fix spacing */
-    i=_owl_editwin_get_index_from_xy(e);
-    if (e->buff[i]==' ' && e->buff[i+1]==' ') {
-      if (e->buff[i-1]=='.' || e->buff[i-1]=='!' || e->buff[i-1]=='?') {
+    i = _owl_editwin_get_index_from_xy(e);
+    if (e->buff[i] == ' ' && e->buff[i+1] == ' ') {
+      if (e->buff[i-1] == '.' || e->buff[i-1] == '!' || e->buff[i-1] == '?') {
 	owl_editwin_key_right(e);
       } else {
 	owl_editwin_delete_char(e);
-	/* if we did this ahead of the save point, adjust it */
-	if (i<save) save--;
+	/* if we did this ahead of the save point, adjust it. Changing
+           by one is fine here because we're only removing an ASCII
+           space. */
+	if (i < save) save--;
       }
     } else {
       owl_editwin_key_right(e);
     }
-
   }
 
   /* put cursor back at starting point */
@@ -914,47 +1097,62 @@
 
 int owl_editwin_check_dotsend(owl_editwin *e)
 {
-  int i;
+  char *p, *p_n, *p_p;
+  gunichar c;
 
   if (!e->dotsend) return(0);
-  for (i=e->bufflen-1; i>0; i--) {
-    if (e->buff[i] == '.' 
-	&& (e->buff[i-1] == '\n' || e->buff[i-1] == '\r')
-	&& (e->buff[i+1] == '\n' || e->buff[i+1] == '\r')) {
-      e->bufflen = i;
-      e->buff[i] = '\0';
+
+  p = g_utf8_find_prev_char(e->buff, e->buff + e->bufflen);
+  p_n = g_utf8_find_next_char(p, NULL);
+  p_p = g_utf8_find_prev_char(e->buff, p);
+  c = g_utf8_get_char(p);
+  while (p != NULL) {
+    if (*p == '.'
+	&& p_p != NULL && (*p_p == '\n' || *p_p == '\r')
+	&& p_n != NULL && (*p_n == '\n' || *p_n == '\r')) {
+      e->bufflen = p - e->buff;
+      e->buff[e->bufflen] = '\0';
       return(1);
     }
-    if (!isspace((int) e->buff[i])) {
-      return(0);
-    }
+    if (c != '\0' && !g_unichar_isspace(c)) return(0);
+    p_n = p;
+    p = p_p;
+    c = g_utf8_get_char(p);
+    p_p = g_utf8_find_prev_char(e->buff, p);
   }
   return(0);
 }
 
-void owl_editwin_post_process_char(owl_editwin *e, int j)
+void owl_editwin_post_process_char(owl_editwin *e, owl_input j)
 {
   /* check if we need to scroll down */
   if (e->buffy-e->topline >= e->winlines) {
     e->topline+=e->winlines/2;
   }
-  if ((j==13 || j==10) && owl_editwin_check_dotsend(e)) {
+  if ((j.ch==13 || j.ch==10) && owl_editwin_check_dotsend(e)) {
     owl_command_editmulti_done(e);
     return;
   }
   owl_editwin_redisplay(e, 0);  
 }
 
-void owl_editwin_process_char(owl_editwin *e, int j)
+void _owl_editwin_process_char(owl_editwin *e, gunichar j)
 {
-  if (j == ERR) return;
-  if (j>127 || ((j<32) && (j!=10) && (j!=13))) {
-    return;
-  } else {
+  if (!(g_unichar_iscntrl(j) && (j != 10) && (j != 13))) {
     owl_editwin_insert_char(e, j);
   }
 }
 
+
+void owl_editwin_process_char(owl_editwin *e, owl_input j)
+{
+  if (j.ch == ERR) return;
+  /* Ignore ncurses control characters. */
+  if (j.ch < 0x100) { 
+    _owl_editwin_process_char(e, j.uch);
+  }
+}
+
 char *owl_editwin_get_text(owl_editwin *e)
 {
   return(e->buff+e->lock);
@@ -978,14 +1176,48 @@
     ptr1=ptr2+1;
   }
 
-  /* now go to the xth character */
-  ptr2=strchr(ptr1, '\n');
-  if (!ptr2) {
-    return(e->buff + e->bufflen - ptr1);
+  /* now count characters */
+  i = 0;
+  ptr2 = ptr1;
+  while (ptr2 - e->buff < e->bufflen
+	 && *ptr2 != '\n') {
+    ++i;
+    ptr2 = g_utf8_next_char(ptr2);
   }
-  return(ptr2-ptr1); /* don't count the newline for now */
+  return i;
 }
 
+int owl_editwin_get_numcells_on_line(owl_editwin *e, int line)
+{
+  int i;
+  char *ptr1, *ptr2;
+  gunichar c;
+
+  if (e->bufflen==0) return(0);
+  
+  /* first go to the yth line */
+  ptr1=e->buff;
+  for (i=0; i<line; i++) {
+    ptr2=strchr(ptr1, '\n');
+    if (!ptr2) {
+      /* we're already on the last line */
+      return(0);
+    }
+    ptr1=ptr2+1;
+  }
+
+  /* now count cells */
+  i = 0;
+  ptr2 = ptr1;
+  while (ptr2 - e->buff < e->bufflen
+	 && *ptr2 != '\n') {
+    c = g_utf8_get_char(ptr2);
+    i += mk_wcwidth(c);
+    ptr2 = g_utf8_next_char(ptr2);
+  }
+  return i;
+}
+
 int owl_editwin_get_numlines(owl_editwin *e)
 {
   return(owl_text_num_lines(e->buff));

Modified: trunk/owl/fmtext.c
===================================================================
--- trunk/owl/fmtext.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/fmtext.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -7,94 +7,79 @@
 /* initialize an fmtext with no data */
 void owl_fmtext_init_null(owl_fmtext *f)
 {
-  f->textlen=0;
-  f->bufflen=5;
-  f->textbuff=owl_malloc(5);
-  f->fmbuff=owl_malloc(5);
-  f->fgcolorbuff=owl_malloc(5 * sizeof(short));
-  f->bgcolorbuff=owl_malloc(5 * sizeof(short));
-  f->textbuff[0]=0;
-  f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
-  f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
-  f->bgcolorbuff[0]=OWL_COLOR_DEFAULT;
+  f->textlen = 0;
+  f->bufflen = 5;
+  f->textbuff = owl_malloc(5);
+  f->textbuff[0] = 0;
+  f->default_attrs = OWL_FMTEXT_ATTR_NONE;
+  f->default_fgcolor = OWL_COLOR_DEFAULT;
+  f->default_bgcolor = OWL_COLOR_DEFAULT;
 }
 
 /* Clear the data from an fmtext, but don't deallocate memory. This
    fmtext can then be appended to again. */
 void owl_fmtext_clear(owl_fmtext *f)
 {
-    f->textlen = 0;
-    f->textbuff[0] = 0;
-    f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
-    f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
-    f->bgcolorbuff[0]=OWL_COLOR_DEFAULT;
+  f->textlen = 0;
+  f->textbuff[0] = 0;
+  f->default_attrs = OWL_FMTEXT_ATTR_NONE;
+  f->default_fgcolor = OWL_COLOR_DEFAULT;
+  f->default_bgcolor = OWL_COLOR_DEFAULT;
 }
 
-/* Internal function.  Set the attribute 'attr' from index 'first' to
- * index 'last'
- */
-void _owl_fmtext_set_attr(owl_fmtext *f, int attr, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->fmbuff[i]=(unsigned char) attr;
-  }
-}
-
-/* Internal function.  Add the attribute 'attr' to the existing
- * attributes from index 'first' to index 'last'
- */
-void _owl_fmtext_add_attr(owl_fmtext *f, int attr, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->fmbuff[i]|=(unsigned char) attr;
-  }
-}
-
-/* Internal function.  Set the color to be 'color' from index 'first'
- * to index 'last
- */
-void _owl_fmtext_set_fgcolor(owl_fmtext *f, int color, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->fgcolorbuff[i]=(short)color;
-  }
-}
-
-void _owl_fmtext_set_bgcolor(owl_fmtext *f, int color, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->bgcolorbuff[i]=(short)color;
-  }
-}
-
 void _owl_fmtext_realloc(owl_fmtext *f, int newlen) /*noproto*/
 {
     if(newlen + 1 > f->bufflen) {
-      f->textbuff=owl_realloc(f->textbuff, newlen+1);
-      f->fmbuff=owl_realloc(f->fmbuff, newlen+1);
-      f->fgcolorbuff=owl_realloc(f->fgcolorbuff, (newlen+1) * sizeof(short));
-      f->bgcolorbuff=owl_realloc(f->bgcolorbuff, (newlen+1) * sizeof(short));
+      f->textbuff = owl_realloc(f->textbuff, newlen + 1);
       f->bufflen = newlen+1;
   }
 }
 
+int owl_fmtext_is_format_char(gunichar c)
+{
+  if ((c & ~OWL_FMTEXT_UC_ATTR_MASK) == OWL_FMTEXT_UC_ATTR) return 1;
+  if ((c & ~(OWL_FMTEXT_UC_ALLCOLOR_MASK)) == OWL_FMTEXT_UC_COLOR_BASE) return 1;
+  return 0;
+}
 /* append text to the end of 'f' with attribute 'attr' and color
  * 'color'
  */
-void owl_fmtext_append_attr(owl_fmtext *f, char *text, int attr, int fgcolor, int bgcolor)
+void owl_fmtext_append_attr(owl_fmtext *f, char *text, char attr, short fgcolor, short bgcolor)
 {
-  int newlen;
-  newlen=strlen(f->textbuff)+strlen(text);
+  char attrbuff[6];
+  int newlen, a = 0, fg = 0, bg = 0;
+  
+  if (attr != OWL_FMTEXT_ATTR_NONE) a=1;
+  if (fgcolor != OWL_COLOR_DEFAULT) fg=1;
+  if (bgcolor != OWL_COLOR_DEFAULT) bg=1;
+
+  /* Plane-16 characters in UTF-8 are 4 bytes long. */
+  newlen = strlen(f->textbuff) + strlen(text) + (8 * (a + fg + bg));
   _owl_fmtext_realloc(f, newlen);
+
+  /* Set attributes */
+  if (a) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_ATTR | attr, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (fg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_FGCOLOR | fgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (bg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_BGCOLOR | bgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
   
   strcat(f->textbuff, text);
-  _owl_fmtext_set_attr(f, attr, f->textlen, newlen);
-  _owl_fmtext_set_fgcolor(f, fgcolor, f->textlen, newlen);
-  _owl_fmtext_set_bgcolor(f, bgcolor, f->textlen, newlen);
+
+  /* Reset attributes */
+  if (bg) strcat(f->textbuff, OWL_FMTEXT_UTF8_BGDEFAULT);
+  if (fg) strcat(f->textbuff, OWL_FMTEXT_UTF8_FGDEFAULT);
+  if (a)  strcat(f->textbuff, OWL_FMTEXT_UTF8_ATTR_NONE);
   f->textlen=newlen;
 }
 
@@ -128,60 +113,105 @@
   owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_REVERSE | OWL_FMTEXT_ATTR_BOLD, OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
 }
 
-/* Add the attribute 'attr' to all text in 'f' */
-void owl_fmtext_addattr(owl_fmtext *f, int attr)
+/* Add the attribute 'attr' to the default atts for the text in 'f' */
+void owl_fmtext_addattr(owl_fmtext *f, char attr)
 {
   /* add the attribute to all text */
-  int i, j;
-
-  j=f->textlen;
-  for (i=0; i<j; i++) {
-    f->fmbuff[i] |= attr;
-  }
+  f->default_attrs |= attr;
 }
 
-/* Anywhere the color is NOT ALREDY SET, set the color to 'color'.
- * Other colors are left unchanged
+/* Set the default foreground color for this fmtext to 'color'.
+ * Only affects text that is colored default.
  */
 void owl_fmtext_colorize(owl_fmtext *f, int color)
 {
-  /* everywhere the fgcolor is OWL_COLOR_DEFAULT, change it to be 'color' */
-  int i, j;
-
-  j=f->textlen;
-  for(i=0; i<j; i++) {
-    if (f->fgcolorbuff[i]==OWL_COLOR_DEFAULT) f->fgcolorbuff[i] = (short)color;
-  }
+  f->default_fgcolor = color;
 }
 
+/* Set the default foreground color for this fmtext to 'color'.
+ * Only affects text that is colored default.
+ */
 void owl_fmtext_colorizebg(owl_fmtext *f, int color)
 {
-  /* everywhere the bgcolor is OWL_COLOR_DEFAULT, change it to be 'color' */
-  int i, j;
+  f->default_bgcolor = color;
+}
 
-  j=f->textlen;
-  for(i=0; i<j; i++) {
-    if (f->bgcolorbuff[i]==OWL_COLOR_DEFAULT) f->bgcolorbuff[i] = (short)color;
+/* Internal function. Parse attrbute character. */
+void _owl_fmtext_update_attributes(gunichar c, char *attr, short *fgcolor, short *bgcolor) /*noproto*/
+{
+  if ((c & OWL_FMTEXT_UC_ATTR) == OWL_FMTEXT_UC_ATTR) {
+    *attr = c & OWL_FMTEXT_UC_ATTR_MASK;
   }
+  else if ((c & OWL_FMTEXT_UC_COLOR_BASE) == OWL_FMTEXT_UC_COLOR_BASE) {
+    if ((c & OWL_FMTEXT_UC_BGCOLOR) == OWL_FMTEXT_UC_BGCOLOR) {
+      *bgcolor = (c == OWL_FMTEXT_UC_BGDEFAULT
+                  ? OWL_COLOR_DEFAULT
+                  : c & OWL_FMTEXT_UC_COLOR_MASK);
+    }
+    else if ((c & OWL_FMTEXT_UC_FGCOLOR) == OWL_FMTEXT_UC_FGCOLOR) {
+      *fgcolor = (c == OWL_FMTEXT_UC_FGDEFAULT
+                  ? OWL_COLOR_DEFAULT
+                  : c & OWL_FMTEXT_UC_COLOR_MASK);
+    }
+  }
 }
 
+/* Internal function. Scan for attribute characters. */
+void _owl_fmtext_scan_attributes(owl_fmtext *f, int start, char *attr, short *fgcolor, short *bgcolor) /*noproto*/
+{
+  char *p;
+  p = strchr(f->textbuff, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  while (p && p < f->textbuff + start) {
+    _owl_fmtext_update_attributes(g_utf8_get_char(p), attr, fgcolor, bgcolor);
+    p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  }
+}  
+
 /* Internal function.  Append text from 'in' between index 'start' and
  * 'stop' to the end of 'f'
  */
-void _owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in, int start, int stop)
+void _owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in, int start, int stop) /*noproto*/
 {
-  int newlen, i;
+  char attrbuff[6];
+  int newlen, a = 0, fg = 0, bg = 0;
+  char attr = 0;
+  short fgcolor = OWL_COLOR_DEFAULT;
+  short bgcolor = OWL_COLOR_DEFAULT;
 
-  newlen=strlen(f->textbuff)+(stop-start+1);
+  _owl_fmtext_scan_attributes(in, start, &attr, &fgcolor, &bgcolor);
+  if (attr != OWL_FMTEXT_ATTR_NONE) a=1;
+  if (fgcolor != OWL_COLOR_DEFAULT) fg=1;
+  if (bgcolor != OWL_COLOR_DEFAULT) bg=1;
+
+  /* We will reset to defaults after appending the text. We may need
+     to set initial attributes. */
+  newlen=strlen(f->textbuff)+(stop-start+1) + (4 * (a + fg + bg)) + 12;
   _owl_fmtext_realloc(f, newlen);
 
+  if (a) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_ATTR | attr, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (fg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_FGCOLOR | fgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (bg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_BGCOLOR | bgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+
   strncat(f->textbuff, in->textbuff+start, stop-start+1);
+
+  /* Reset attributes */
+  strcat(f->textbuff, OWL_FMTEXT_UTF8_BGDEFAULT);
+  strcat(f->textbuff, OWL_FMTEXT_UTF8_FGDEFAULT);
+  strcat(f->textbuff, OWL_FMTEXT_UTF8_ATTR_NONE);
+
   f->textbuff[newlen]='\0';
-  for (i=start; i<=stop; i++) {
-    f->fmbuff[f->textlen+(i-start)]=in->fmbuff[i];
-    f->fgcolorbuff[f->textlen+(i-start)]=in->fgcolorbuff[i];
-    f->bgcolorbuff[f->textlen+(i-start)]=in->bgcolorbuff[i];
-  }
   f->textlen=newlen;
 }
 
@@ -206,72 +236,141 @@
  */
 char *owl_fmtext_print_plain(owl_fmtext *f)
 {
-  return(owl_strdup(f->textbuff));
+  return owl_strip_format_chars(f->textbuff);
 }
 
+void _owl_fmtext_wattrset(WINDOW *w, int attrs) /*noproto*/
+{
+  wattrset(w, A_NORMAL);
+  if (attrs & OWL_FMTEXT_ATTR_BOLD) wattron(w, A_BOLD);
+  if (attrs & OWL_FMTEXT_ATTR_REVERSE) wattron(w, A_REVERSE);
+  if (attrs & OWL_FMTEXT_ATTR_UNDERLINE) wattron(w, A_UNDERLINE);
+}
+
+void _owl_fmtext_update_colorpair(short fg, short bg, short *pair) /*noproto*/
+{
+  if (owl_global_get_hascolors(&g)) {
+    *pair = owl_fmtext_get_colorpair(fg, bg);
+  }
+}
+
+void _owl_fmtext_wcolor_set(WINDOW *w, short pair) /*noproto*/
+{
+  if (owl_global_get_hascolors(&g)) {
+      wcolor_set(w,pair,NULL);
+  }
+}
+
 /* add the formatted text to the curses window 'w'.  The window 'w'
  * must already be initiatlized with curses
  */
-void owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w)
+void _owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w, int do_search) /*noproto*/
 {
-  char *tmpbuff;
-  int position, trans1, trans2, trans3, len, lastsame;
-
+  /* char *tmpbuff; */
+  /* int position, trans1, trans2, trans3, len, lastsame; */
+  char *s, *p;
+  char attr;
+  short fg, bg, pair;
+  int search_results, search_len;
+  
   if (w==NULL) {
     owl_function_debugmsg("Hit a null window in owl_fmtext_curs_waddstr.");
     return;
   }
 
-  tmpbuff=owl_malloc(f->textlen+10);
+  search_results = (do_search
+		    ? owl_fmtext_search(f, owl_global_get_search_string(&g))
+		    : 0);
+  search_len = (search_results
+		? strlen(owl_global_get_search_string(&g))
+		: 0);
+  s = f->textbuff;
+  /* Set default attributes. */
+  attr = f->default_attrs;
+  fg = f->default_fgcolor;
+  bg = f->default_bgcolor;
+  _owl_fmtext_wattrset(w, attr);
+  _owl_fmtext_update_colorpair(fg, bg, &pair);
+  _owl_fmtext_wcolor_set(w, pair);
 
-  position=0;
-  len=f->textlen;
-  while (position<=len) {
-    /* find the last char with the current format and color */
-    trans1=owl_util_find_trans(f->fmbuff+position, len-position);
-    trans2=owl_util_find_trans_short(f->fgcolorbuff+position, len-position);
-    trans3=owl_util_find_trans_short(f->bgcolorbuff+position, len-position);
+  /* Find next possible format character. */
+  p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  while(p) {
+    if (owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+      /* Deal with all text from last insert to here. */
+      char tmp;
+   
+      tmp = p[0];
+      p[0] = '\0';
+      if (search_results) {
+	/* Search is active, so highlight search results. */
+	char tmp2, *ss;
+	ss = stristr(s, owl_global_get_search_string(&g));
+	while (ss) {
+	  /* Found search string, highlight it. */
 
-    lastsame = (trans1 < trans2) ? trans1 : trans2;
-    lastsame = (lastsame < trans3) ? lastsame : trans3;
-    lastsame += position;
+	  tmp2 = ss[0];
+	  ss[0] = '\0';
+	  waddstr(w, s);
+	  ss[0] = tmp2;
 
-    /* set the format */
-    wattrset(w, A_NORMAL);
-    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_BOLD) {
-      wattron(w, A_BOLD);
-    }
-    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_REVERSE) {
-      wattron(w, A_REVERSE);
-    }
-    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_UNDERLINE) {
-      wattron(w, A_UNDERLINE);
-    }
+	  _owl_fmtext_wattrset(w, attr ^ OWL_FMTEXT_ATTR_REVERSE);
+	  _owl_fmtext_wcolor_set(w, pair);
+	  
+	  tmp2 = ss[search_len];
+	  ss[search_len] = '\0';
+	  waddstr(w, ss);
+	  ss[search_len] = tmp2;
 
-    /* set the color */
-    /* warning, this is sort of a hack */
-    if (owl_global_get_hascolors(&g)) {
-      short fg, bg, pair;
-      fg = f->fgcolorbuff[position];
-      bg = f->bgcolorbuff[position];
+	  _owl_fmtext_wattrset(w, attr);
+	  _owl_fmtext_wcolor_set(w, pair);
 
-      pair = owl_fmtext_get_colorpair(fg, bg);
-      if (pair != -1) {
-        wcolor_set(w,pair,NULL);
+	  s = ss + search_len;
+	  ss = stristr(s, owl_global_get_search_string(&g));
+	}
       }
-    }
+      /* Deal with remaining part of string. */
+      waddstr(w, s);
+      p[0] = tmp;
 
-    /* add the text */
-    strncpy(tmpbuff, f->textbuff + position, lastsame-position+1);
-    tmpbuff[lastsame-position+1]='\0';
-    waddstr(w, tmpbuff);
+      /* Deal with new attributes. Initialize to defaults, then
+	 process all consecutive formatting characters. */
+      attr = f->default_attrs;
+      fg = f->default_fgcolor;
+      bg = f->default_bgcolor;
+      while (p && owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+	_owl_fmtext_update_attributes(g_utf8_get_char(p), &attr, &fg, &bg);
+	p = g_utf8_next_char(p);
+      }
+      _owl_fmtext_wattrset(w, attr | f->default_attrs);
+      if (fg == OWL_COLOR_DEFAULT) fg = f->default_fgcolor;
+      if (bg == OWL_COLOR_DEFAULT) bg = f->default_bgcolor;
+      _owl_fmtext_update_colorpair(fg, bg, &pair);
+      _owl_fmtext_wcolor_set(w, pair);
 
-    position=lastsame+1;
+      /* Advance to next non-formatting character. */
+      s = p;
+      p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+    }
+    else {
+      p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+    }
   }
-  owl_free(tmpbuff);
+  if (s) {
+    waddstr(w, s);
+  }
 }
 
+void owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w)
+{
+  _owl_fmtext_curs_waddstr(f, w, owl_global_is_search_active(&g));
+}
 
+void owl_fmtext_curs_waddstr_without_search(owl_fmtext *f, WINDOW *w)
+{
+  _owl_fmtext_curs_waddstr(f, w, 0);
+}
+
 /* start with line 'aline' (where the first line is 0) and print
  * 'lines' number of lines into 'out'
  */
@@ -281,28 +380,32 @@
   int i, offset;
   
   /* find the starting line */
-  ptr1=in->textbuff;
-  if (aline!=0) {
-    for (i=0; i<aline; i++) {
-      ptr1=strchr(ptr1, '\n');
-      if (!ptr1) return(-1);
-      ptr1++;
-    }
+  ptr1 = in->textbuff;
+  for (i = 0; i < aline; i++) {
+    ptr1 = strchr(ptr1, '\n');
+    if (!ptr1) return(-1);
+    ptr1++;
   }
+  
   /* ptr1 now holds the starting point */
 
+  /* copy the default attributes */
+  out->default_attrs = in->default_attrs;
+  out->default_fgcolor = in->default_fgcolor;
+  out->default_bgcolor = in->default_bgcolor;
+    
   /* copy in the next 'lines' lines */
-  if (lines<1) return(-1);
+  if (lines < 1) return(-1);
 
-  for (i=0; i<lines; i++) {
-    offset=ptr1-in->textbuff;
-    ptr2=strchr(ptr1, '\n');
+  for (i = 0; i < lines; i++) {
+    offset = ptr1 - in->textbuff;
+    ptr2 = strchr(ptr1, '\n');
     if (!ptr2) {
-      _owl_fmtext_append_fmtext(out, in, offset, (in->textlen)-1);
+      _owl_fmtext_append_fmtext(out, in, offset, (in->textlen) - 1);
       return(-1);
     }
-    _owl_fmtext_append_fmtext(out, in, offset, (ptr2-ptr1)+offset);
-    ptr1=ptr2+1;
+    _owl_fmtext_append_fmtext(out, in, offset, (ptr2 - ptr1) + offset);
+    ptr1 = ptr2 + 1;
   }
   return(0);
 }
@@ -310,49 +413,82 @@
 /* Truncate the message so that each line begins at column 'acol' and
  * ends at 'bcol' or sooner.  The first column is number 0.  The new
  * message is placed in 'out'.  The message is * expected to end in a
- * new line for now
+ * new line for now. NOTE: This needs to be modified to deal with
+ * backing up if we find a SPACING COMBINING MARK at the end of a
+ * line. If that happens, we should back up to the last non-mark
+ * character and stop there.
  */
 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, st, padding, chwidth;
 
+  /* copy the default attributes */
+  out->default_attrs = in->default_attrs;
+  out->default_fgcolor = in->default_fgcolor;
+  out->default_bgcolor = in->default_bgcolor;
+
   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;
     }
 
-    /* we need to check that we won't run over here */
-    len=bcol-acol;
-    if (len > (ptr2-(ptr1+acol))) {
-      /* the whole line fits with room to spare, don't take a full 'len' */
-      len=ptr2-(ptr1+acol);
+    col = 0;
+    st = 0;
+    padding = 0;
+    chwidth = 0;
+    ptr_c = ptr_s;
+    while(ptr_c < ptr_e) {
+      gunichar c = g_utf8_get_char(ptr_c);
+      if (!owl_fmtext_is_format_char(c)) {
+	chwidth = mk_wcwidth(c);
+	if (col + chwidth > bcol) break;
+	
+	if (col >= acol) {
+	  if (st == 0) {
+	    ptr_s = ptr_c;
+	    padding = col - acol;
+	    ++st;
+	  }
+	}
+	col += chwidth;
+	chwidth = 0;
+      }
+      ptr_c = g_utf8_next_char(ptr_c);
     }
-    if (len>last-ptr1) {
-      /* the whole rest of the text fits with room to spare, adjust for it */
-      len-=(last-ptr1);
+    if (st) {
+      /* lead padding */
+      owl_fmtext_append_spaces(out, padding);
+      if (ptr_c == ptr_e) {
+	/* We made it to the newline. */
+	_owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
+      }
+      else {
+	if (chwidth > 1) {
+	  /* Last char is wide, truncate. */
+	  _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff - 1);
+	  owl_fmtext_append_normal(out, "\n");
+	}
+	else {
+	  /* Last char fits perfectly, leave alone.*/
+	  _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
+	}
+      }
     }
-    if (len<=0) {
-      /* saftey check */
+    else {
       owl_fmtext_append_normal(out, "\n");
-      ptr1=ptr2+1;
-      continue;
     }
-
-    offset=ptr1-in->textbuff;
-    _owl_fmtext_append_fmtext(out, in, offset+acol, offset+acol+len);
-
-    ptr1=ptr2+1;
+    ptr_s = g_utf8_next_char(ptr_e);
   }
 }
 
@@ -380,10 +516,13 @@
 }
 
 /* set the charater at 'index' to be 'char'.  If index is out of
- * bounds don't do anything */
-void owl_fmtext_set_char(owl_fmtext *f, int index, int ch)
+ * bounds don't do anything. If c or char at index is not ASCII, don't
+ * do anything because it's not UTF-8 safe. */
+void owl_fmtext_set_char(owl_fmtext *f, int index, char ch)
 {
   if ((index < 0) || (index > f->textlen-1)) return;
+  /* NOT ASCII*/
+  if (f->textbuff[index] & 0x80 || ch & 0x80) return; 
   f->textbuff[index]=ch;
 }
 
@@ -400,47 +539,17 @@
   dst->textlen=src->textlen;
   dst->bufflen=mallocsize;
   dst->textbuff=owl_malloc(mallocsize);
-  dst->fmbuff=owl_malloc(mallocsize);
-  dst->fgcolorbuff=owl_malloc(mallocsize * sizeof(short));
-  dst->bgcolorbuff=owl_malloc(mallocsize * sizeof(short));
   memcpy(dst->textbuff, src->textbuff, src->textlen+1);
-  memcpy(dst->fmbuff, src->fmbuff, src->textlen);
-  memcpy(dst->fgcolorbuff, src->fgcolorbuff, src->textlen * sizeof(short));
-  memcpy(dst->bgcolorbuff, src->bgcolorbuff, src->textlen * sizeof(short));
+  dst->default_attrs = src->default_attrs;
+  dst->default_fgcolor = src->default_fgcolor;
+  dst->default_bgcolor = src->default_bgcolor;
 }
 
-/* highlight all instances of "string".  Return the number of
- * instances found.  This is a case insensitive search.
- */
-int owl_fmtext_search_and_highlight(owl_fmtext *f, char *string)
-{
-
-  int found, len;
-  char *ptr1, *ptr2;
-
-  len=strlen(string);
-  found=0;
-  ptr1=f->textbuff;
-  while (ptr1-f->textbuff <= f->textlen) {
-    ptr2=stristr(ptr1, string);
-    if (!ptr2) return(found);
-
-    found++;
-    _owl_fmtext_add_attr(f, OWL_FMTEXT_ATTR_REVERSE,
-                         ptr2 - f->textbuff,
-                         ptr2 - f->textbuff + len - 1);
-
-    ptr1=ptr2+len;
-  }
-  return(found);
-}
-
 /* return 1 if the string is found, 0 if not.  This is a case
  *  insensitive search.
  */
 int owl_fmtext_search(owl_fmtext *f, char *string)
 {
-
   if (stristr(f->textbuff, string)) return(1);
   return(0);
 }
@@ -681,9 +790,6 @@
 void owl_fmtext_free(owl_fmtext *f)
 {
   if (f->textbuff) owl_free(f->textbuff);
-  if (f->fmbuff) owl_free(f->fmbuff);
-  if (f->fgcolorbuff) owl_free(f->fgcolorbuff);
-  if (f->bgcolorbuff) owl_free(f->bgcolorbuff);
 }
 
 /*** Color Pair manager ***/

Modified: trunk/owl/functions.c
===================================================================
--- trunk/owl/functions.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/functions.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -1605,7 +1605,7 @@
 	for (i=0; i<fields; i++) {
 	  sprintf(buff, "  Field %i   : ", i+1);
 	  
-	  ptr=owl_zephyr_get_field(n, i+1);
+	  ptr=owl_zephyr_get_field_as_utf8(n, i+1);
 	  len=strlen(ptr);
 	  if (len<30) {
 	    strncpy(tmpbuff, ptr, len);
@@ -2186,7 +2186,6 @@
 
 void owl_function_start_command(char *line)
 {
-  int i, j;
   owl_editwin *tw;
 
   tw=owl_global_get_typwin(&g);
@@ -2197,10 +2196,7 @@
   owl_editwin_set_locktext(tw, "command: ");
   owl_global_set_needrefresh(&g);
 
-  j=strlen(line);
-  for (i=0; i<j; i++) {
-    owl_editwin_process_char(tw, line[i]);
-  }
+  owl_editwin_insert_string(tw, line);
   owl_editwin_redisplay(tw, 0);
 
   owl_context_set_editline(owl_global_get_context(&g), tw);
@@ -2598,7 +2594,13 @@
     sprintf(filtname, "class-%s-instance-%s", class, instance);
   }
   /* 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, ' ', '.');
   owl_text_tr(filtname, '\'', '.');
@@ -3023,7 +3025,7 @@
   char *buff;
   char *quoted;
 
-  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
+  buff=owl_malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
   strcpy(buff, "class");
   if (!strcmp(class, "*")) {
     strcat(buff, " .*");
@@ -3327,7 +3329,7 @@
           ret=ZGetLocations(location, &numlocs);
           if (ret==0) {
             for (x=0; x<numlocs; x++) {
-              line=malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
+              line=owl_malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
               tmp=short_zuser(user);
               sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
                       tmp,
@@ -3370,6 +3372,7 @@
   owl_message *m;
   owl_view *v;
   FILE *file;
+  char *plaintext;
 
   v=owl_global_get_current_view(&g);
 
@@ -3392,7 +3395,11 @@
   j=owl_view_get_size(v);
   for (i=0; i<j; i++) {
     m=owl_view_get_element(v, i);
-    fputs(owl_message_get_text(m), file);
+    plaintext = owl_strip_format_chars(owl_message_get_text(m));
+    if (plaintext) {
+      fputs(plaintext, file);
+      owl_free(plaintext);
+    }
   }
   fclose(file);
   owl_function_makemsg("Messages dumped to %s", filename);
@@ -3433,7 +3440,7 @@
 	if (myargc <= 0) {
 	  _exit(127);
 	}
-	parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
+	parsed=owl_realloc(parsed, sizeof(*parsed) * (myargc+1));
 	parsed[myargc] = NULL;
 	
 	owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);

Copied: trunk/owl/glib_compat.c (from rev 802, branches/barnowl_unicode/owl/glib_compat.c)
===================================================================
--- trunk/owl/glib_compat.c	                        (rev 0)
+++ trunk/owl/glib_compat.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -0,0 +1,18 @@
+#include <owl.h>
+
+#if (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 14)
+/* Our own implementation of g_unichar_is_mark for glib versions that
+   are too old to have one. */
+int g_unichar_ismark(gunichar ucs)
+{
+  GUnicodeType t = g_unichar_type(ucs);
+  switch (t) {
+  case G_UNICODE_NON_SPACING_MARK:
+  case G_UNICODE_COMBINING_MARK:
+  case G_UNICODE_ENCLOSING_MARK:
+       return 1;
+  default:
+       return 0;
+  }
+}
+#endif

Modified: trunk/owl/global.c
===================================================================
--- trunk/owl/global.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/global.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -556,7 +556,7 @@
   for (i=0; i<argc; i++) {
     len+=strlen(argv[i])+5;
   }
-  g->startupargs=malloc(len+5);
+  g->startupargs=owl_malloc(len+5);
 
   strcpy(g->startupargs, "");
   for (i=0; i<argc; i++) {

Modified: trunk/owl/keymap.c
===================================================================
--- trunk/owl/keymap.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/keymap.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -4,7 +4,7 @@
 static const char fileIdent[] = "$Id$";
 
 /* returns 0 on success */
-int owl_keymap_init(owl_keymap *km, char *name, char *desc, void (*default_fn)(int), void (*prealways_fn)(int), void (*postalways_fn)(int))
+int owl_keymap_init(owl_keymap *km, char *name, char *desc, void (*default_fn)(owl_input), void (*prealways_fn)(owl_input), void (*postalways_fn)(owl_input))
 {
   if (!name || !desc) return(-1);
   if ((km->name = owl_strdup(name)) == NULL) return(-1);
@@ -150,7 +150,7 @@
   owl_dict_insert_element(&kh->keymaps, km->name, km, NULL);
 }
 
-owl_keymap *owl_keyhandler_create_and_add_keymap(owl_keyhandler *kh, char *name, char *desc, void (*default_fn)(int), void (*prealways_fn)(int), void (*postalways_fn)(int))
+owl_keymap *owl_keyhandler_create_and_add_keymap(owl_keyhandler *kh, char *name, char *desc, void (*default_fn)(owl_input), void (*prealways_fn)(owl_input), void (*postalways_fn)(owl_input))
 {
   owl_keymap *km;
   km = (owl_keymap*)owl_malloc(sizeof(owl_keymap));
@@ -201,7 +201,7 @@
 
 /* processes a keypress.  returns 0 if the keypress was handled,
  * 1 if not handled, -1 on error, and -2 if j==ERR. */
-int owl_keyhandler_process(owl_keyhandler *kh, int j)
+int owl_keyhandler_process(owl_keyhandler *kh, owl_input j)
 {
   owl_keymap     *km;
   owl_keybinding *kb;
@@ -213,7 +213,7 @@
   }
 
   /* temporarily disallow C-`/C-SPACE until we fix associated bugs */
-  if (j==ERR || j==0) {
+  if (j.ch == ERR || j.ch == 0) {
 	return(-1);
   }
 
@@ -223,16 +223,16 @@
   */
 
   /* deal with ESC prefixing */
-  if (!kh->in_esc && j==27) {
+  if (!kh->in_esc && j.ch == 27) {
     kh->in_esc = 1;
     return(0);
   }
   if (kh->in_esc) {
-    j = OWL_META(j);
+    j.ch = OWL_META(j.ch);
     kh->in_esc = 0;
   }
   
-  kh->kpstack[++(kh->kpstackpos)] = j;
+  kh->kpstack[++(kh->kpstackpos)] = j.ch;
   if (kh->kpstackpos >= OWL_KEYMAP_MAXSTACK) {
     owl_keyhandler_reset(kh);
     owl_function_makemsg("Too many prefix keys pressed...");
@@ -259,7 +259,7 @@
 	return(0);
       } else if (match == 2) {	/* exact match */
 	/* owl_function_debugmsg("processkey: found exact match in %s", km->name); */
-	owl_keybinding_execute(kb, j);
+	owl_keybinding_execute(kb, j.ch);
 	owl_keyhandler_reset(kh);
 	if (km->postalways_fn) {
 	  km->postalways_fn(j);

Modified: trunk/owl/keypress.c
===================================================================
--- trunk/owl/keypress.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/keypress.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -147,7 +147,7 @@
     }
   }
   if (!*kb) {
-    if (j&OWL_META(0)) {
+    if (j & OWL_META(0)) {
       strcat(kb, "M-");
       j &= ~OWL_META(0);
     }
@@ -162,6 +162,7 @@
       kb2[1] = 0;
       strcat(kb, kb2);    
     }
+    
   }  
   if (!*kb) {
     /* not a valid key */

Modified: trunk/owl/keys.c
===================================================================
--- trunk/owl/keys.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/keys.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -301,27 +301,27 @@
 /********************* Support Functions ************************/
 /****************************************************************/
 
-void owl_keys_recwin_prealways(int j) {
+void owl_keys_recwin_prealways(owl_input j) {
   /* Clear the message line on subsequent key presses */
   owl_function_makemsg("");
 }
 
-void owl_keys_editwin_default(int j) {
+void owl_keys_editwin_default(owl_input j) {
   owl_editwin *e;
   if (NULL != (e=owl_global_get_typwin(&g))) {
-    owl_editwin_process_char(e, j);
+       owl_editwin_process_char(e, j);
   }
 }
 
-void owl_keys_editwin_postalways(int j) {
+void owl_keys_editwin_postalways(owl_input j) {
   owl_editwin *e;
   if (NULL != (e=owl_global_get_typwin(&g))) {
     owl_editwin_post_process_char(e, j);
-  }  
+  }
   owl_global_set_needrefresh(&g);
 }
 
-void owl_keys_popless_postalways(int j) {
+void owl_keys_popless_postalways(owl_input j) {
   owl_viewwin *v = owl_global_get_viewwin(&g);
   owl_popwin *pw = owl_global_get_popwin(&g);
 
@@ -330,9 +330,9 @@
   }  
 }
 
-void owl_keys_default_invalid(int j) {
-  if (j==ERR) return;
-  if (j==410) return;
+void owl_keys_default_invalid(owl_input j) {
+  if (j.ch==ERR) return;
+  if (j.ch==410) return;
   owl_keyhandler_invalidkey(owl_global_get_keyhandler(&g));
 }
 

Modified: trunk/owl/logging.c
===================================================================
--- trunk/owl/logging.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/logging.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -154,9 +154,11 @@
   } else if (owl_message_is_type_jabber(m)) {
     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 {
     to = owl_sprintf("loopback");
@@ -266,11 +268,12 @@
     }
   } 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");
   } else if (owl_message_is_type_jabber(m)) {
@@ -289,7 +292,7 @@
   if (strchr(frombuff, '/')) from="weird";
 
   ch=frombuff[0];
-  if (!isalnum(ch)) from="weird";
+  if (!g_ascii_isalnum(ch)) from="weird";
 
   for (i=0; i<len; i++) {
     if (frombuff[i]<'!' || frombuff[i]>='~') from="weird";
@@ -298,7 +301,13 @@
   if (!strcmp(frombuff, ".") || !strcasecmp(frombuff, "..")) from="weird";
 
   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;
+      }
+    }
   }
 
   /* create the filename (expanding ~ in path names) */

Modified: trunk/owl/message.c
===================================================================
--- trunk/owl/message.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/message.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -78,7 +78,7 @@
     owl_pair_create(pair, owl_global_intern(&g, attrname), NULL);
     owl_list_append_element(&(m->attributes), pair);
   }
-  owl_pair_set_value(pair, owl_strdup(attrvalue));
+  owl_pair_set_value(pair, owl_validate_or_convert(attrvalue));
 }
 
 /* return the value associated with the named attribute, or NULL if
@@ -492,7 +492,7 @@
 void owl_message_set_zwriteline(owl_message *m, char *line)
 {
   if(m->zwriteline) owl_free(m->zwriteline);
-  m->zwriteline=strdup(line);
+  m->zwriteline=owl_strdup(line);
 }
 
 int owl_message_is_delete(owl_message *m)
@@ -534,19 +534,11 @@
   owl_fmtext_init_null(&a);
   owl_fmtext_init_null(&b);
   
-  owl_fmtext_truncate_lines(&(m->fmtext->fmtext), aline, bline-aline+1, &a);
+  owl_fmtext_truncate_lines(&(m->fmtext->fmtext), aline, bline-aline, &a);
   owl_fmtext_truncate_cols(&a, acol, bcol, &b);
-  if (fgcolor!=OWL_COLOR_DEFAULT) {
-    owl_fmtext_colorize(&b, fgcolor);
-  }
-  if (bgcolor!=OWL_COLOR_DEFAULT) {
-    owl_fmtext_colorizebg(&b, bgcolor);
-  }
+  owl_fmtext_colorize(&b, fgcolor);
+  owl_fmtext_colorizebg(&b, bgcolor);
 
-  if (owl_global_is_search_active(&g)) {
-    owl_fmtext_search_and_highlight(&b, owl_global_get_search_string(&g));
-  }
-      
   owl_fmtext_curs_waddstr(&b, win);
 
   owl_fmtext_free(&a);
@@ -891,7 +883,7 @@
     owl_message_set_attribute(m, "isauto", "");
   }
 
-  m->zwriteline=strdup("");
+  m->zwriteline=owl_strdup("");
 
   /* save the hostname */
   owl_function_debugmsg("About to do gethostbyaddr");
@@ -973,7 +965,7 @@
     owl_message_set_realm(m, owl_zephyr_get_realm());
   }
 
-  m->zwriteline=strdup("");
+  m->zwriteline=owl_strdup("");
 
   owl_message_set_body(m, "<uninitialized>");
 

Modified: trunk/owl/owl.c
===================================================================
--- trunk/owl/owl.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/owl.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -48,6 +48,7 @@
 #include <sys/time.h>
 #include <termios.h>
 #include <sys/stat.h>
+#include <locale.h>
 #include "owl.h"
 
 #if OWL_STDERR_REDIR
@@ -60,6 +61,8 @@
 int stderr_replace(void);
 #endif
 
+#define STDIN 0
+
 static const char fileIdent[] = "$Id$";
 
 owl_global g;
@@ -84,6 +87,9 @@
 #if OWL_STDERR_REDIR
   int newstderr;
 #endif
+  
+  if (!GLIB_CHECK_VERSION (2, 12, 0))
+    g_error ("GLib version 2.12.0 or above is needed.");
 
   argcsave=argc;
   argvsave=argv;
@@ -92,6 +98,9 @@
   tty=NULL;
   debug=0;
   initialsubs=1;
+
+  setlocale(LC_ALL, "");
+  
   if (argc>0) {
     argv++;
     argc--;
@@ -209,7 +218,7 @@
   /* prepare stdin dispatch */
   {
     owl_dispatch *d = owl_malloc(sizeof(owl_dispatch));
-    d->fd = fileno(stdin);
+    d->fd = STDIN;
     d->cfunc = &owl_process_input;
     d->pfunc = NULL;
     owl_select_add_dispatch(d);
@@ -519,15 +528,10 @@
       } else {
 	owl_function_set_cursor(sepwin);
       }
-      owl_function_debugmsg("owl.c -- doupdate()");
       doupdate();
       owl_global_set_noneedrefresh(&g);
     }
 
-    /* Handle all keypresses.  If no key has been pressed, sleep for a
-     * little bit, but otherwise do not.  This lets input be grabbed
-     * as quickly as possbile */
-
     /* select on FDs we know about. */
     owl_select();
 
@@ -663,18 +667,67 @@
 
 void owl_process_input()
 {
-  int ret, j;
+  int ret;
+  owl_input j;
   owl_popwin *pw;
   owl_editwin *tw;
+  WINDOW *typwin;
 
+  typwin = owl_global_get_curs_typwin(&g);
   while (1) {
-    j = wgetch(owl_global_get_curs_typwin(&g));
-    if (j == ERR) return;
-
+    j.ch = wgetch(typwin);
+    if (j.ch == ERR) return;
+    
     owl_global_set_lastinputtime(&g, time(NULL));
     pw=owl_global_get_popwin(&g);
     tw=owl_global_get_typwin(&g);
+
+    j.uch = '\0';
+    if (j.ch >= KEY_MIN && j.ch <= KEY_MAX) {
+      /* This is a curses control character. */
+    }
+    else if (j.ch > 0x7f && j.ch < 0xfe) {
+      /* Pull in a full utf-8 character. */
+      int bytes, i;
+      char utf8buf[7];
+      memset(utf8buf, '\0', 7);
+      
+      utf8buf[0] = j.ch;
+      
+      if ((j.ch & 0xc0) && (~j.ch & 0x20)) bytes = 2;
+      else if ((j.ch & 0xe0) && (~j.ch & 0x10)) bytes = 3;
+      else if ((j.ch & 0xf0) && (~j.ch & 0x08)) bytes = 4;
+      else if ((j.ch & 0xf8) && (~j.ch & 0x04)) bytes = 5;
+      else if ((j.ch & 0xfc) && (~j.ch & 0x02)) bytes = 6;
+      else bytes = 1;
+      
+      for (i = 1; i < bytes; i++) {
+        int tmp =  wgetch(typwin);
+        /* If what we got was not a byte, or not a continuation byte */
+        if (tmp > 0xff || !(tmp & 0x80 && ~tmp & 0x40)) {
+          /* ill-formed UTF-8 code unit subsequence, put back the
+             char we just got. */
+          ungetch(tmp);
+          j.ch = ERR;
+          break;
+        }
+        utf8buf[i] = tmp;
+      }
+      
+      if (j.ch != ERR) {
+        if (g_utf8_validate(utf8buf, -1, NULL)) {
+          j.uch = g_utf8_get_char(utf8buf);
+        }
+        else {
+          j.ch = ERR;
+        }
+      }
+    }
+    else if (j.ch <= 0x7f) {
+      j.uch = j.ch;
+    }
     
+    owl_global_set_lastinputtime(&g, time(NULL));
     /* find and activate the current keymap.
      * TODO: this should really get fixed by activating
      * keymaps as we switch between windows... 
@@ -684,13 +737,13 @@
                               owl_global_get_viewwin(&g));
       owl_function_activate_keymap("popless");
     } else if (owl_global_is_typwin_active(&g) 
-               && owl_editwin_get_style(tw) == OWL_EDITWIN_STYLE_ONELINE) {
+               && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_ONELINE) {
       /*
         owl_context_set_editline(owl_global_get_context(&g), tw);
         owl_function_activate_keymap("editline");
       */
     } else if (owl_global_is_typwin_active(&g) 
-               && owl_editwin_get_style(tw) == OWL_EDITWIN_STYLE_MULTILINE) {
+               && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_MULTILINE) {
       owl_context_set_editmulti(owl_global_get_context(&g), tw);
       owl_function_activate_keymap("editmulti");
     } else {
@@ -699,7 +752,7 @@
     }
     /* now actually handle the keypress */
     ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j);
-    if (ret != 0 && ret != 1) {
+    if (ret!=0 && ret!=1) {
       owl_function_makemsg("Unable to handle keypress");
     }
   }

Modified: trunk/owl/owl.h
===================================================================
--- trunk/owl/owl.h	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/owl.h	2008-05-12 02:57:44 UTC (rev 1040)
@@ -51,7 +51,9 @@
 #include <signal.h>
 #include <termios.h>
 #include <libfaim/aim.h>
+#include <wchar.h>
 #include "config.h"
+#include "glib.h"
 #ifdef HAVE_LIBZEPHYR
 #include <zephyr/zephyr.h>
 #endif
@@ -101,6 +103,23 @@
 #define OWL_FMTEXT_ATTR_REVERSE   2
 #define OWL_FMTEXT_ATTR_UNDERLINE 4
 
+#define OWL_FMTEXT_UC_BASE 0x100000 /* Unicode Plane 16 - Supplementary Private Use Area-B*/
+#define OWL_FMTEXT_UC_ATTR ( OWL_FMTEXT_UC_BASE | 0x800 )
+#define OWL_FMTEXT_UC_ATTR_MASK 0x7
+#define OWL_FMTEXT_UC_COLOR_BASE ( OWL_FMTEXT_UC_BASE | 0x400 )
+#define OWL_FMTEXT_UC_FGCOLOR OWL_FMTEXT_UC_COLOR_BASE
+#define OWL_FMTEXT_UC_BGCOLOR ( OWL_FMTEXT_UC_COLOR_BASE | 0x200 )
+#define OWL_FMTEXT_UC_DEFAULT_COLOR 0x100
+#define OWL_FMTEXT_UC_FGDEFAULT ( OWL_FMTEXT_UC_FGCOLOR | OWL_FMTEXT_UC_DEFAULT_COLOR )
+#define OWL_FMTEXT_UC_BGDEFAULT ( OWL_FMTEXT_UC_BGCOLOR | OWL_FMTEXT_UC_DEFAULT_COLOR )
+#define OWL_FMTEXT_UC_COLOR_MASK 0xFF
+#define OWL_FMTEXT_UC_ALLCOLOR_MASK ( OWL_FMTEXT_UC_COLOR_MASK | OWL_FMTEXT_UC_DEFAULT_COLOR | 0x200)
+#define OWL_FMTEXT_UC_STARTBYTE_UTF8 '\xf4'
+
+#define OWL_FMTEXT_UTF8_ATTR_NONE "\xf4\x80\xa0\x80"
+#define OWL_FMTEXT_UTF8_FGDEFAULT "\xf4\x80\x94\x80"
+#define OWL_FMTEXT_UTF8_BGDEFAULT "\xf4\x80\x9C\x80"
+
 #define OWL_COLOR_BLACK     0
 #define OWL_COLOR_RED       1
 #define OWL_COLOR_GREEN     2
@@ -209,7 +228,7 @@
 #define OWL_ENABLE_ZCRYPT 1
 #endif
 
-#define OWL_META(key) ((key)|0200)
+#define OWL_META(key) ((key)|010000)
 /* OWL_CTRL is definied in kepress.c */
 
 #define LINE 2048
@@ -249,13 +268,18 @@
 				/* frees val as needed */
 } owl_variable;
 
+typedef struct _owl_input {
+  int ch;
+  gunichar uch;
+} owl_input;
+
 typedef struct _owl_fmtext {
   int textlen;
   int bufflen;
   char *textbuff;
-  char *fmbuff;
-  short *fgcolorbuff;
-  short *bgcolorbuff;
+  char default_attrs;
+  short default_fgcolor;
+  short default_bgcolor;
 } owl_fmtext;
 
 typedef struct _owl_list {
@@ -485,9 +509,9 @@
   char     *desc;		/* description */
   owl_list  bindings;		/* key bindings */
   struct _owl_keymap *submap;	/* submap */
-  void (*default_fn)(int j);	/* default action (takes a keypress) */
-  void (*prealways_fn)(int j);	/* always called before a keypress is received */
-  void (*postalways_fn)(int j);	/* always called after keypress is processed */
+  void (*default_fn)(owl_input j);	/* default action (takes a keypress) */
+  void (*prealways_fn)(owl_input  j);	/* always called before a keypress is received */
+  void (*postalways_fn)(owl_input  j);	/* always called after keypress is processed */
 } owl_keymap;
 
 typedef struct _owl_keyhandler {

Modified: trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber/Connection.pm
===================================================================
--- trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber/Connection.pm	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber/Connection.pm	2008-05-12 02:57:44 UTC (rev 1040)
@@ -1,5 +1,6 @@
 use warnings;
 use strict;
+use utf8;
 
 =head1 NAME
 

Modified: trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm
===================================================================
--- trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	2008-05-12 02:57:44 UTC (rev 1040)
@@ -26,6 +26,8 @@
 use Getopt::Long;
 Getopt::Long::Configure(qw(no_getopt_compat prefix_pattern=-|--));
 
+use utf8;
+
 our $VERSION = 0.1;
 
 BEGIN {
@@ -377,7 +379,7 @@
                 if ( !$vars{jlogin_havepass} && ( !@result || $result[0] eq '401' || $result[0] eq 'error') ) {
                     $vars{jlogin_havepass} = 1;
                     $conn->removeConnection($jidStr);
-                    BarnOwl::start_password( "Password for $jidStr: ", \&do_login );
+                    BarnOwl::start_password("Password for $jidStr: ", \&do_login );
                     return "";
                 }
                 $conn->removeConnection($jidStr);
@@ -486,7 +488,7 @@
         return;
     }
     else {
-        $to = shift @ARGV;
+      $to = shift @ARGV;
     }
 
     my @candidates = guess_jwrite($from, $to);
@@ -530,7 +532,8 @@
     my $cmd = "jwrite $jwrite_to -a $jwrite_from";
     $cmd .= " -t $jwrite_thread" if $jwrite_thread;
     $cmd .= " -s $jwrite_subject" if $jwrite_subject;
-    BarnOwl::start_edit_win( $cmd, \&process_owl_jwrite );
+
+    BarnOwl::start_edit_win($cmd, \&process_owl_jwrite );
 }
 
 sub cmd_jmuc {

Modified: trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Debug.pm
===================================================================
--- trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Debug.pm	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Debug.pm	2008-05-12 02:57:44 UTC (rev 1040)
@@ -188,6 +188,7 @@
                         if (defined($self->{HANDLE}))
                         {
                             $self->{HANDLE}->autoflush(1);
+                            binmode $self->{HANDLE}, ":utf8";
                             $Net::XMPP::Debug::HANDLES{$args{file}} = $self->{HANDLE};
                         }
                         else

Modified: trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Message.pm
===================================================================
--- trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Message.pm	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/perl/modules/Jabber/lib/Net/XMPP/Message.pm	2008-05-12 02:57:44 UTC (rev 1040)
@@ -134,7 +134,7 @@
 
                             $Mess->SetMessage(TO=>"bob\@jabber.org",
                                               Subject=>"Lunch",
-                                              BoDy=>"Let's do lunch!");
+                                              Body=>"Let's do lunch!");
                             $Mess->SetMessage(to=>"bob\@jabber.org",
                                               from=>"jabber.org",
                                               errorcode=>404,

Modified: trunk/owl/perl/modules/Jabber/lib/XML/Stream.pm
===================================================================
--- trunk/owl/perl/modules/Jabber/lib/XML/Stream.pm	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/perl/modules/Jabber/lib/XML/Stream.pm	2008-05-12 02:57:44 UTC (rev 1040)
@@ -1658,7 +1658,7 @@
     if ($self->{SIDS}->{$sid}->{select}->can_write(0))
     {
         $self->debug(3,"Send: can_write");
-        
+
         $self->{SENDSTRING} = Encode::encode_utf8(join("",@_));
 
         $self->{SENDWRITTEN} = 0;

Modified: trunk/owl/perlconfig.c
===================================================================
--- trunk/owl/perlconfig.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/perlconfig.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -54,7 +54,7 @@
     av_zfields = newAV();
     j=owl_zephyr_get_num_fields(owl_message_get_notice(m));
     for (i=0; i<j; i++) {
-      ptr=owl_zephyr_get_field(owl_message_get_notice(m), i+1);
+      ptr=owl_zephyr_get_field_as_utf8(owl_message_get_notice(m), i+1);
       av_push(av_zfields, newSVpvn(ptr, strlen(ptr)));
       owl_free(ptr);
     }
@@ -433,7 +433,9 @@
 
   PUSHMARK(SP);
   for(i=0;i<argc;i++) {
-    XPUSHs(sv_2mortal(newSVpv(argv[i], 0)));
+    SV *tmp = newSVpv(argv[i], 0);
+    SvUTF8_on(tmp);
+    XPUSHs(sv_2mortal(tmp));
   }
   PUTBACK;
 
@@ -472,18 +474,21 @@
 void owl_perlconfig_edit_callback(owl_editwin *e)
 {
   SV *cb = (SV*)(e->cbdata);
+  SV *text;
   unsigned int n_a;
   dSP;
 
   if(cb == NULL) {
     owl_function_error("Perl callback is NULL!");
   }
+  text = newSVpv(owl_editwin_get_text(e), 0);
+  SvUTF8_on(text);
 
   ENTER;
   SAVETMPS;
 
   PUSHMARK(SP);
-  XPUSHs(sv_2mortal(newSVpv(owl_editwin_get_text(e), 0)));
+  XPUSHs(sv_2mortal(text));
   PUTBACK;
   
   call_sv(cb, G_DISCARD|G_KEEPERR|G_EVAL);

Modified: trunk/owl/text.c
===================================================================
--- trunk/owl/text.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/text.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -49,41 +49,68 @@
  * new line for now */
 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, padding;
+  
   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++;
+      ptr_s++;
       continue;
     }
 
+    col = 0;
+    cnt = 0;
+    padding = 0;
+    ptr_c = ptr_s;
+    while(col < bcol && ptr_c < ptr_e) {
+      gunichar c = g_utf8_get_char(ptr_c);
+      if (col + mk_wcwidth(c) > bcol) break;
+      col += mk_wcwidth(c);
+      ptr_c = g_utf8_next_char(ptr_c);
+      if (col >= acol) {
+	if (cnt == 0) {
+	  ptr_s = ptr_c;
+	  padding = col - acol;
+	}
+	++cnt;
+      }
+    }
+    if (cnt) {
+      while(padding-- > 0) {
+	strcat(tmpbuff, " ");
+      }
+      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);
+    if ((ptr_s+len)>=last) {
+      len-=last-(ptr_s+len);
     }
 
-    strncat(tmpbuff, ptr1+acol, len);
+    strncat(tmpbuff, ptr_s+acol, len);
     strcat(tmpbuff, "\n");
 
-    ptr1=ptr2+1;
+    ptr_s=ptr_e+1;
+#endif
   }
   strcpy(out, tmpbuff);
   owl_free(tmpbuff);
@@ -274,31 +301,36 @@
 /* exactly like strstr but case insensitive */
 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);
+  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);
   }
-  ret=ret-x+a;
-  owl_free(x);
-  owl_free(y);
   return(ret);
 }
 
 /* return 1 if a string is only whitespace, otherwise 0 */
 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);
 }
 
@@ -326,7 +358,7 @@
   outlen = strlen(in)+1;
   tolen  = strlen(to);
   fromlen  = strlen(from);
-  out = malloc(outlen);
+  out = owl_malloc(outlen);
 
   while (in[inpos]) {
     if (!strncmp(in+inpos, from, fromlen)) {

Modified: trunk/owl/util.c
===================================================================
--- trunk/owl/util.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/util.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -398,15 +398,6 @@
   return(i);
 }
 
-/* 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
  * and returns a single string containing no token more than once.
@@ -445,52 +436,38 @@
 
 void *owl_malloc(size_t size)
 {
-  return(malloc(size));
+  return(g_malloc(size));
 }
 
 void owl_free(void *ptr)
 {
-  free(ptr);
+  g_free(ptr);
 }
 
 char *owl_strdup(const char *s1)
 {
-  return(strdup(s1));
+  return(g_strdup(s1));
 }
 
 void *owl_realloc(void *ptr, size_t size)
 {
-  return(realloc(ptr, size));
+  return(g_realloc(ptr, size));
 }
 
 /* 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
  * if the named color is not available
  */
@@ -775,13 +752,106 @@
   return start;
 }
 
-char * owl_get_datadir() {
-    char * datadir = getenv("BARNOWL_DATA_DIR");
-    if(datadir != NULL)
-        return strchr(datadir, '=') + 1;
-    return DATADIR;
+char * owl_get_datadir()
+{
+  char * datadir = getenv("BARNOWL_DATA_DIR");
+  if(datadir != NULL)
+    return strchr(datadir, '=') + 1;
+  return DATADIR;
 }
 
+/* Strips format characters from a valid utf-8 string. Returns the
+   empty string if 'in' does not validate. */
+char * owl_strip_format_chars(char *in)
+{
+  char *r;
+  if (g_utf8_validate(in, -1, NULL)) {
+    char *s, *p;
+    r = owl_malloc(strlen(in)+1);
+    r[0] = '\0';
+    s = in;
+    p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+    while(p) {
+      /* If it's a format character, copy up to it, and skip all
+	 immediately following format characters. */
+      if (owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+	strncat(r, s, p-s);
+	p = g_utf8_next_char(p);
+	while (p && owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+	  p = g_utf8_next_char(p);
+	}
+	s = p;
+	p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+      }
+      else {
+	p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+      }
+    }
+    if (s) strcat(r,s);
+  }
+  else {
+    r = owl_strdup("");
+  }
+  return r;
+}
+
+/* If in is not UTF-8, convert from ISO-8859-1. We may want to allow
+ * the caller to specify an alternative in the future. We also strip
+ * out characters in Unicode Plane 16, as we use that plane internally
+ * for formatting.
+ */
+char * owl_validate_or_convert(char *in)
+{
+  if (g_utf8_validate(in, -1, NULL)) {
+    return owl_strip_format_chars(in);
+  }
+  else {
+    return g_convert(in, -1,
+		     "UTF-8", "ISO-8859-1",
+		     NULL, NULL, NULL);
+  }
+}
+/* Attempts to convert 'in' to ISO-8859-1. Returns that if possible,
+   else returns UTF-8.
+ */
+char * owl_get_iso_8859_1_if_possible(char *in)
+{
+  char *out;
+  if (g_utf8_validate(in, -1, NULL)) {
+    out = g_convert(in, -1,
+		    "ISO-8859-1", "UTF-8",
+		    NULL, NULL, NULL);
+    if (!out) {
+      out = owl_strdup(in);
+    }
+  }
+  else {
+    out = owl_strdup("");
+  }
+  return out;
+}
+
+/* This is based on _extract() and _isCJ() from perl's Text::WrapI18N */
+int owl_util_can_break_after(gunichar c)
+{
+  
+  if (c == ' ') return 1;
+  if (c >= 0x3000 && c <= 0x312f) {
+    /* CJK punctuations, Hiragana, Katakana, Bopomofo */
+    if (c == 0x300a || c == 0x300c || c == 0x300e ||
+        c == 0x3010 || c == 0x3014 || c == 0x3016 ||
+        c == 0x3018 || c == 0x301a)
+      return 0;
+    return 1;
+  }
+  if (c >= 0x31a0 && c <= 0x31bf) {return 1;}  /* Bopomofo */
+  if (c >= 0x31f0 && c <= 0x31ff) {return 1;}  /* Katakana extension */
+  if (c >= 0x3400 && c <= 0x9fff) {return 1;}  /* Han Ideogram */
+  if (c >= 0xf900 && c <= 0xfaff) {return 1;}  /* Han Ideogram */
+  if (c >= 0x20000 && c <= 0x2ffff) {return 1;}  /* Han Ideogram */
+  return 0;
+}
+
 /**************************************************************************/
 /************************* REGRESSION TESTS *******************************/
 /**************************************************************************/

Modified: trunk/owl/viewwin.c
===================================================================
--- trunk/owl/viewwin.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/viewwin.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -72,7 +72,7 @@
   owl_fmtext_truncate_lines(&(v->fmtext), v->topline, v->winlines-BOTTOM_OFFSET, &fm1);
   owl_fmtext_truncate_cols(&fm1, v->rightshift, v->wincols-1+v->rightshift, &fm2);
 
-  owl_fmtext_curs_waddstr(&fm2, v->curswin);
+  owl_fmtext_curs_waddstr_without_search(&fm2, v->curswin);
 
   /* print the message at the bottom */
   wmove(v->curswin, v->winlines-1, 0);

Copied: trunk/owl/wcwidth.c (from rev 802, branches/barnowl_unicode/owl/wcwidth.c)
===================================================================
--- trunk/owl/wcwidth.c	                        (rev 0)
+++ trunk/owl/wcwidth.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -0,0 +1,309 @@
+/*
+ * This is an implementation of wcwidth() and wcswidth() (defined in
+ * IEEE Std 1002.1-2001) for Unicode.
+ *
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+ *
+ * In fixed-width output devices, Latin characters all occupy a single
+ * "cell" position of equal width, whereas ideographic CJK characters
+ * occupy two such cells. Interoperability between terminal-line
+ * applications and (teletype-style) character terminals using the
+ * UTF-8 encoding requires agreement on which character should advance
+ * the cursor by how many cell positions. No established formal
+ * standards exist at present on which Unicode character shall occupy
+ * how many cell positions on character terminals. These routines are
+ * a first attempt of defining such behavior based on simple rules
+ * applied to data provided by the Unicode Consortium.
+ *
+ * For some graphical characters, the Unicode standard explicitly
+ * defines a character-cell width via the definition of the East Asian
+ * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+ * In all these cases, there is no ambiguity about which width a
+ * terminal shall use. For characters in the East Asian Ambiguous (A)
+ * class, the width choice depends purely on a preference of backward
+ * compatibility with either historic CJK or Western practice.
+ * Choosing single-width for these characters is easy to justify as
+ * the appropriate long-term solution, as the CJK practice of
+ * displaying these characters as double-width comes from historic
+ * implementation simplicity (8-bit encoded characters were displayed
+ * single-width and 16-bit ones double-width, even for Greek,
+ * Cyrillic, etc.) and not any typographic considerations.
+ *
+ * Much less clear is the choice of width for the Not East Asian
+ * (Neutral) class. Existing practice does not dictate a width for any
+ * of these characters. It would nevertheless make sense
+ * typographically to allocate two character cells to characters such
+ * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+ * represented adequately with a single-width glyph. The following
+ * routines at present merely assign a single-cell width to all
+ * neutral characters, in the interest of simplicity. This is not
+ * entirely satisfactory and should be reconsidered before
+ * establishing a formal standard in this area. At the moment, the
+ * decision which Not East Asian (Neutral) characters should be
+ * represented by double-width glyphs cannot yet be answered by
+ * applying a simple rule from the Unicode database content. Setting
+ * up a proper standard for the behavior of UTF-8 character terminals
+ * will require a careful analysis not only of each Unicode character,
+ * but also of each presentation form, something the author of these
+ * routines has avoided to do so far.
+ *
+ * http://www.unicode.org/unicode/reports/tr11/
+ *
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.
+ *
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+
+#include <wchar.h>
+
+static struct interval {
+  int first;
+  int last;
+};
+
+/* auxiliary function for binary search in interval table */
+static int bisearch(wchar_t ucs, const struct interval *table, int max) {
+  int min = 0;
+  int mid;
+
+  if (ucs < table[0].first || ucs > table[max].last)
+    return 0;
+  while (max >= min) {
+    mid = (min + max) / 2;
+    if (ucs > table[mid].last)
+      min = mid + 1;
+    else if (ucs < table[mid].first)
+      max = mid - 1;
+    else
+      return 1;
+  }
+
+  return 0;
+}
+
+
+/* The following two functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ *    - The null character (U+0000) has a column width of 0.
+ *
+ *    - Other C0/C1 control characters and DEL will lead to a return
+ *      value of -1.
+ *
+ *    - Non-spacing and enclosing combining characters (general
+ *      category code Mn or Me in the Unicode database) have a
+ *      column width of 0.
+ *
+ *    - SOFT HYPHEN (U+00AD) has a column width of 1.
+ *
+ *    - Other format characters (general category code Cf in the Unicode
+ *      database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ *    - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ *      have a column width of 0.
+ *
+ *    - Spacing characters in the East Asian Wide (W) or East Asian
+ *      Full-width (F) category as defined in Unicode Technical
+ *      Report #11 have a column width of 2.
+ *
+ *    - All remaining characters (including all printable
+ *      ISO 8859-1 and WGL4 characters, Unicode control characters,
+ *      etc.) have a column width of 1.
+ *
+ * This implementation assumes that wchar_t characters are encoded
+ * in ISO 10646.
+ */
+
+int mk_wcwidth(wchar_t ucs)
+{
+  /* sorted list of non-overlapping intervals of non-spacing characters */
+  /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+  static const struct interval combining[] = {
+    { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
+    { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+    { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
+    { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
+    { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+    { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+    { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
+    { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
+    { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
+    { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
+    { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
+    { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
+    { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
+    { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
+    { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
+    { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
+    { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
+    { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
+    { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
+    { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+    { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
+    { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
+    { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
+    { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
+    { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
+    { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
+    { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
+    { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
+    { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
+    { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
+    { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
+    { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
+    { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
+    { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
+    { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
+    { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
+    { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
+    { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
+    { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
+    { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
+    { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
+    { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
+    { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
+    { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
+    { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
+    { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
+    { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
+    { 0xE0100, 0xE01EF }
+  };
+
+  /* test for 8-bit control characters */
+  if (ucs == 0)
+    return 0;
+  if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+    return -1;
+
+  /* binary search in table of non-spacing characters */
+  if (bisearch(ucs, combining,
+	       sizeof(combining) / sizeof(struct interval) - 1))
+    return 0;
+
+  /* if we arrive here, ucs is not a combining or C0/C1 control character */
+
+  return 1 + 
+    (ucs >= 0x1100 &&
+     (ucs <= 0x115f ||                    /* Hangul Jamo init. consonants */
+      ucs == 0x2329 || ucs == 0x232a ||
+      (ucs >= 0x2e80 && ucs <= 0xa4cf &&
+       ucs != 0x303f) ||                  /* CJK ... Yi */
+      (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+      (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+      (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
+      (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+      (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
+      (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+      (ucs >= 0x20000 && ucs <= 0x2fffd) ||
+      (ucs >= 0x30000 && ucs <= 0x3fffd)));
+}
+
+
+int mk_wcswidth(const wchar_t *pwcs, size_t n)
+{
+  int w, width = 0;
+
+  for (;*pwcs && n-- > 0; pwcs++)
+    if ((w = mk_wcwidth(*pwcs)) < 0)
+      return -1;
+    else
+      width += w;
+
+  return width;
+}
+
+
+/*
+ * The following functions are the same as mk_wcwidth() and
+ * mk_wcswidth(), except that spacing characters in the East Asian
+ * Ambiguous (A) category as defined in Unicode Technical Report #11
+ * have a column width of 2. This variant might be useful for users of
+ * CJK legacy encodings who want to migrate to UCS without changing
+ * the traditional terminal character-width behaviour. It is not
+ * otherwise recommended for general use.
+ */
+int mk_wcwidth_cjk(wchar_t ucs)
+{
+  /* sorted list of non-overlapping intervals of East Asian Ambiguous
+   * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
+  static const struct interval ambiguous[] = {
+    { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
+    { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
+    { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
+    { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
+    { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
+    { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
+    { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
+    { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
+    { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
+    { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
+    { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
+    { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
+    { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
+    { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
+    { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
+    { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
+    { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
+    { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
+    { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
+    { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
+    { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
+    { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
+    { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
+    { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
+    { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
+    { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
+    { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
+    { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
+    { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
+    { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
+    { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
+    { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
+    { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
+    { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
+    { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
+    { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
+    { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
+    { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
+    { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
+    { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
+    { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
+    { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
+    { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
+    { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
+    { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
+    { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
+    { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
+    { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
+    { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
+    { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
+    { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
+    { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
+  };
+
+  /* binary search in table of non-spacing characters */
+  if (bisearch(ucs, ambiguous,
+	       sizeof(ambiguous) / sizeof(struct interval) - 1))
+    return 2;
+
+  return mk_wcwidth(ucs);
+}
+
+
+int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
+{
+  int w, width = 0;
+
+  for (;*pwcs && n-- > 0; pwcs++)
+    if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
+      return -1;
+    else
+      width += w;
+
+  return width;
+}

Modified: trunk/owl/zcrypt.c
===================================================================
--- trunk/owl/zcrypt.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/zcrypt.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -384,7 +384,7 @@
 }
 
 /* Build a space-separated string from argv from elements between start  *
- * and end - 1.  malloc()'s the returned string. */
+ * and end - 1.  owl_malloc()'s the returned string. */
 char *BuildArgString(char **argv, int start, int end) {
   int len = 1;
   int i;
@@ -396,7 +396,7 @@
   }
 
   /* Allocate memory */
-  result = (char *)malloc(len);
+  result = (char *)owl_malloc(len);
   if (result) {
     /* Build the string */
     char *ptr = result;
@@ -481,7 +481,7 @@
     } else {
       /* Prepare result to be returned */
       char *temp = keyfile;
-      keyfile = (char *)malloc(strlen(temp) + 1);
+      keyfile = (char *)owl_malloc(strlen(temp) + 1);
       if (keyfile) {
 	strcpy(keyfile, temp);
       } else {
@@ -610,7 +610,7 @@
 	printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
       }
       use_buffer = TRUE;
-      if ((inptr = inbuff = (char *)malloc(MAX_RESULT)) == NULL) {
+      if ((inptr = inbuff = (char *)owl_malloc(MAX_RESULT)) == NULL) {
 	printf("Memory allocation error\n");
 	return FALSE;
       }
@@ -638,7 +638,7 @@
     if (!outfile) {
       printf("Could not run zwrite\n");
       if (freein && inbuff) {
-	free(inbuff);
+	owl_free(inbuff);
       }
       return(FALSE);
     }
@@ -684,7 +684,7 @@
   if (zephyr) CloseZephyrPipe(outfile);
 
   /* Free the input buffer, if necessary */
-  if (freein && inbuff) free(inbuff);
+  if (freein && inbuff) owl_free(inbuff);
 
   return(!error);
 }

Modified: trunk/owl/zephyr.c
===================================================================
--- trunk/owl/zephyr.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/zephyr.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -352,11 +352,49 @@
 
   return(owl_strdup(""));
 }
+
+char *owl_zephyr_get_field_as_utf8(ZNotice_t *n, int j)
+{
+  int i, count, save;
+
+  /* If there's no message here, just run along now */
+  if (n->z_message_len == 0)
+    return(owl_strdup(""));
+
+  count=save=0;
+  for (i = 0; i < n->z_message_len; i++) {
+    if (n->z_message[i]=='\0') {
+      count++;
+      if (count == j) {
+	/* just found the end of the field we're looking for */
+	return(owl_validate_or_convert(n->z_message + save));
+      } else {
+	save = i + 1;
+      }
+    }
+  }
+  /* catch the last field, which might not be null terminated */
+  if (count == j - 1) {
+    char *tmp, *out;
+    tmp = owl_malloc(n->z_message_len-save+5);
+    memcpy(tmp, n->z_message+save, n->z_message_len-save);
+    tmp[n->z_message_len-save]='\0';
+    out = owl_validate_or_convert(tmp);
+    owl_free(tmp);
+    return out;
+  }
+
+  return(owl_strdup(""));
+}
 #else
 char *owl_zephyr_get_field(void *n, int j)
 {
   return(owl_strdup(""));
 }
+char *owl_zephyr_get_field_as_utf8(void *n, int j)
+{
+  return owl_zephyr_get_field(n, j);
+}
 #endif
 
 

Modified: trunk/owl/zwrite.c
===================================================================
--- trunk/owl/zwrite.c	2008-05-11 17:32:06 UTC (rev 1039)
+++ trunk/owl/zwrite.c	2008-05-12 02:57:44 UTC (rev 1040)
@@ -43,7 +43,7 @@
 	badargs=1;
 	break;
       }
-      z->class=owl_strdup(myargv[1]);
+      z->class=owl_get_iso_8859_1_if_possible(myargv[1]);
       myargv+=2;
       myargc-=2;
     } else if (!strcmp(myargv[0], "-i")) {
@@ -51,7 +51,7 @@
 	badargs=1;
 	break;
       }
-      z->inst=owl_strdup(myargv[1]);
+      z->inst=owl_get_iso_8859_1_if_possible(myargv[1]);
       myargv+=2;
       myargc-=2;
     } else if (!strcmp(myargv[0], "-r")) {
@@ -59,7 +59,7 @@
 	badargs=1;
 	break;
       }
-      z->realm=owl_strdup(myargv[1]);
+      z->realm=owl_get_iso_8859_1_if_possible(myargv[1]);
       myargv+=2;
       myargc-=2;
     } else if (!strcmp(myargv[0], "-s")) {
@@ -67,7 +67,7 @@
 	badargs=1;
 	break;
       }
-      z->zsig=owl_strdup(myargv[1]);
+      z->zsig=owl_get_iso_8859_1_if_possible(myargv[1]);
       myargv+=2;
       myargc-=2;
     } else if (!strcmp(myargv[0], "-O")) {
@@ -75,7 +75,7 @@
 	badargs=1;
 	break;
       }
-      z->opcode=owl_strdup(myargv[1]);
+      z->opcode=owl_get_iso_8859_1_if_possible(myargv[1]);
       myargv+=2;
       myargc-=2;
     } else if (!strcmp(myargv[0], "-m")) {
@@ -92,9 +92,9 @@
       /* Once we have -m, gobble up everything else on the line */
       myargv++;
       myargc--;
-      z->message=owl_strdup("");
+      z->message=owl_get_iso_8859_1_if_possible("");
       while (myargc) {
-	z->message=realloc(z->message, strlen(z->message)+strlen(myargv[0])+5);
+	z->message=owl_realloc(z->message, strlen(z->message)+strlen(myargv[0])+5);
 	strcat(z->message, myargv[0]);
 	strcat(z->message, " ");
 	myargc--;
@@ -112,7 +112,7 @@
       myargc--;
     } else {
       /* anything unattached is a recipient */
-      owl_list_append_element(&(z->recips), strdup(myargv[0]));
+      owl_list_append_element(&(z->recips), owl_get_iso_8859_1_if_possible(myargv[0]));
       myargv++;
       myargc--;
     }
@@ -145,7 +145,7 @@
     zsigzvar = owl_zephyr_get_variable("zwrite-signature");
 
     if (zsigowlvar && *zsigowlvar) {
-      z->zsig=owl_strdup(zsigowlvar);
+      z->zsig=owl_get_iso_8859_1_if_possible(zsigowlvar);
     } else if (zsigproc && *zsigproc) {
       FILE *file;
       char buff[LINE], *openline;
@@ -160,7 +160,7 @@
       owl_free(openline);
       if (!file) {
 	if (zsigzvar && *zsigzvar) {
-	  z->zsig=owl_strdup(zsigzvar);
+	  z->zsig=owl_get_iso_8859_1_if_possible(zsigzvar);
 	}
       } else {
 	z->zsig=owl_malloc(LINE*5);
@@ -174,9 +174,9 @@
 	}
       }
     } else if (zsigzvar) {
-      z->zsig=owl_strdup(zsigzvar);
+      z->zsig=owl_get_iso_8859_1_if_possible(zsigzvar);
     } else if (((pw=getpwuid(getuid()))!=NULL) && (pw->pw_gecos)) {
-      z->zsig=strdup(pw->pw_gecos);
+      z->zsig=owl_get_iso_8859_1_if_possible(pw->pw_gecos);
       ptr=strchr(z->zsig, ',');
       if (ptr) {
 	ptr[0]='\0';
@@ -217,6 +217,7 @@
 {
   int i, j;
   char toline[LINE];
+  char *tmp = NULL;
 
   if (z->message) owl_free(z->message);
 
@@ -230,10 +231,12 @@
 	sprintf(toline, "%s%s ", toline, (char *) owl_list_get_element(&(z->recips), i));
       }
     }
-    z->message=owl_sprintf("%s\n%s", toline, msg);
+    tmp = owl_get_iso_8859_1_if_possible(msg);
+    z->message=owl_sprintf("%s\n%s", toline, tmp);
   } else {
-    z->message=owl_strdup(msg);
+    z->message=owl_get_iso_8859_1_if_possible(msg);
   }
+  if (tmp) owl_free(tmp);
 }
 
 char *owl_zwrite_get_message(owl_zwrite *z)
@@ -304,7 +307,7 @@
 void owl_zwrite_set_opcode(owl_zwrite *z, char *opcode)
 {
   if (z->opcode) owl_free(z->opcode);
-  z->opcode=owl_strdup(opcode);
+  z->opcode=owl_get_iso_8859_1_if_possible(opcode);
 }
 
 char *owl_zwrite_get_realm(owl_zwrite *z)


home help back first fref pref prev next nref lref last post