Index: message.c
===================================================================
--- message.c	(revision 8fa9562d57e3973e92ad34c23fc4eb965a550e47)
+++ message.c	(revision 30678ae9bb1c30b7fc37b6cf4e1290116ddebe0c)
@@ -16,5 +16,4 @@
 {
   m->id=owl_global_get_nextmsgid(&g);
-  m->type=OWL_MESSAGE_TYPE_GENERIC;
   owl_message_set_direction_none(m);
   m->delete=0;
@@ -324,83 +323,63 @@
 void owl_message_set_type_admin(owl_message *m)
 {
-  m->type=OWL_MESSAGE_TYPE_ADMIN;
+  owl_message_set_attribute(m, "type", "admin");
 }
 
 void owl_message_set_type_loopback(owl_message *m)
 {
-  m->type=OWL_MESSAGE_TYPE_LOOPBACK;
+  owl_message_set_attribute(m, "type", "loopback");
 }
 
 void owl_message_set_type_zephyr(owl_message *m)
 {
-  m->type=OWL_MESSAGE_TYPE_ZEPHYR;
+  owl_message_set_attribute(m, "type", "zephyr");
 }
 
 void owl_message_set_type_aim(owl_message *m)
 {
-  m->type=OWL_MESSAGE_TYPE_AIM;
-}
-
-void owl_message_set_type(owl_message *m, int type)
-{
-  m->type=type;
+  owl_message_set_attribute(m, "type", "aim");
+}
+
+void owl_message_set_type(owl_message *m, char* type)
+{
+  owl_message_set_attribute(m, "type", type);
+}
+
+int owl_message_is_type(owl_message *m, char *type) {
+  char * t = owl_message_get_attribute_value(m, "type");
+  if(!t) return 0;
+  return !strcmp(t, type);
 }
 						
 int owl_message_is_type_admin(owl_message *m)
 {
-  if (m->type==OWL_MESSAGE_TYPE_ADMIN) return(1);
-  return(0);
+  return owl_message_is_type(m, "admin");
 }
 
 int owl_message_is_type_generic(owl_message *m)
 {
-  if (m->type==OWL_MESSAGE_TYPE_GENERIC) return(1);
-  return(0);
+  char * t = owl_message_get_attribute_value(m, "type");
+  return (t == NULL);
 }
 
 int owl_message_is_type_zephyr(owl_message *m)
 {
-  if (m->type==OWL_MESSAGE_TYPE_ZEPHYR) return(1);
-  return(0);
+  return owl_message_is_type(m, "zephyr");
 }
 
 int owl_message_is_type_aim(owl_message *m)
 {
-  if (m->type==OWL_MESSAGE_TYPE_AIM) return(1);
-  return(0);
-}
-
+  return owl_message_is_type(m, "aim");
+}
+
+/* XXX TODO: deprecate this */
 int owl_message_is_type_jabber(owl_message *m)
 {
-  if (m->type==OWL_MESSAGE_TYPE_JABBER) return(1);
-
-  return(0);
-}
-
-int owl_message_is_type_icq(owl_message *m)
-{
-  if (m->type==OWL_MESSAGE_TYPE_ICQ) return(1);
-
-  return(0);
-}
-
-int owl_message_is_type_yahoo(owl_message *m)
-{
-  if (m->type==OWL_MESSAGE_TYPE_YAHOO) return(1);
-
-  return(0);
-}
-
-int owl_message_is_type_msn(owl_message *m)
-{
-  if (m->type==OWL_MESSAGE_TYPE_MSN) return(1);
-
-  return(0);
+  return owl_message_is_type(m, "jabber");
 }
 
 int owl_message_is_type_loopback(owl_message *m)
 {
-  if (m->type==OWL_MESSAGE_TYPE_LOOPBACK) return(1);
-  return(0);
+  return owl_message_is_type(m, "loopback");
 }
 
@@ -666,48 +645,9 @@
 
 char *owl_message_get_type(owl_message *m) {
-  switch (m->type) {
-  case OWL_MESSAGE_TYPE_ADMIN:
-    return("admin");
-  case OWL_MESSAGE_TYPE_ZEPHYR:
-    return("zephyr");
-  case OWL_MESSAGE_TYPE_GENERIC:
-    return("generic");
-  case OWL_MESSAGE_TYPE_AIM:
-    return("aim");
-  case OWL_MESSAGE_TYPE_JABBER:
-    return("jabber");
-  case OWL_MESSAGE_TYPE_ICQ:
-    return("icq");
-  case OWL_MESSAGE_TYPE_YAHOO:
-    return("yahoo");
-  case OWL_MESSAGE_TYPE_MSN:
-    return("msn");
-  case OWL_MESSAGE_TYPE_LOOPBACK:
-    return("loopback");
-  default:
-    return("unknown");
-  }
-}
-
-int owl_message_parse_type(char *type) {
-  if(!strcmp(type, "admin")) {
-    return OWL_MESSAGE_TYPE_ADMIN;
-  } else if(!strcmp(type, "zephyr")) {
-    return OWL_MESSAGE_TYPE_ZEPHYR;
-  } if(!strcmp(type, "aim")) {
-    return OWL_MESSAGE_TYPE_AIM;
-  } else if(!strcmp(type, "jabber")) {
-    return OWL_MESSAGE_TYPE_JABBER;
-  } else if(!strcmp(type, "icq")) {
-    return OWL_MESSAGE_TYPE_ICQ;
-  } else if(!strcmp(type, "yahoo")) {
-    return OWL_MESSAGE_TYPE_YAHOO;
-  } else if(!strcmp(type, "msn")) {
-    return OWL_MESSAGE_TYPE_MSN;
-  } else if(!strcmp(type, "loopback")) {
-    return OWL_MESSAGE_TYPE_LOOPBACK;
-  } else {
-    return OWL_MESSAGE_TYPE_GENERIC;
-  }
+  char * type = owl_message_get_attribute_value(m, "type");
+  if(!type) {
+    return "generic";
+  }
+  return type;
 }
 
Index: owl.h
===================================================================
--- owl.h	(revision 99c75496776069ef63e9cc696ac8c40c5ab1f4ec)
+++ owl.h	(revision 30678ae9bb1c30b7fc37b6cf4e1290116ddebe0c)
@@ -109,14 +109,4 @@
 #define OWL_PROTOCOL_MSN            5
 
-#define OWL_MESSAGE_TYPE_ADMIN      0
-#define OWL_MESSAGE_TYPE_GENERIC    1
-#define OWL_MESSAGE_TYPE_ZEPHYR     2
-#define OWL_MESSAGE_TYPE_AIM        3
-#define OWL_MESSAGE_TYPE_JABBER     4
-#define OWL_MESSAGE_TYPE_ICQ        5
-#define OWL_MESSAGE_TYPE_YAHOO      6
-#define OWL_MESSAGE_TYPE_MSN        7
-#define OWL_MESSAGE_TYPE_LOOPBACK   8
-
 #define OWL_MESSAGE_DIRECTION_NONE  0
 #define OWL_MESSAGE_DIRECTION_IN    1
@@ -334,5 +324,4 @@
 typedef struct _owl_message {
   int id;
-  int type;
   int direction;
 #ifdef HAVE_LIBZEPHYR
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision 8203afdd0879526e14674b39e741493894354216)
+++ perlconfig.c	(revision 30678ae9bb1c30b7fc37b6cf4e1290116ddebe0c)
@@ -26,9 +26,9 @@
 }
 
-SV *owl_perlconfig_message2hashref(owl_message *m)  /*noproto*/
+SV *owl_perlconfig_message2hashref(owl_message *m)
 {
   HV *h;
   SV *hr;
-  char *ptr, *blessas;
+  char *ptr, *blessas, *type;
   int i, j;
   owl_pair *pair;
@@ -86,15 +86,16 @@
   hv_store(h, "private", strlen("private"), newSViv(owl_message_is_private(m)),0);
 
-  if (owl_message_is_type_zephyr(m))       blessas = "BarnOwl::Message::Zephyr";
-  else if (owl_message_is_type_aim(m))     blessas = "BarnOwl::Message::AIM";
-  else if (owl_message_is_type_jabber(m))  blessas = "BarnOwl::Message::Jabber";
-  else if (owl_message_is_type_admin(m))   blessas = "BarnOwl::Message::Admin";
-  else if (owl_message_is_type_generic(m)) blessas = "BarnOwl::Message::Generic";
-  else                                     blessas = "BarnOwl::Message";
+  type = owl_message_get_type(m);
+  if(!type) type = "generic";
+  type = owl_strdup(type);
+  type[0] = toupper(type[0]);
+  blessas = owl_sprintf("BarnOwl::Message::%s", type);
 
   hr = sv_2mortal(newRV_noinc((SV*)h));
-  return sv_bless(hr, gv_stashpv(blessas,0));
-}
-
+  hr = sv_bless(hr, gv_stashpv(blessas,0));
+  owl_free(type);
+  owl_free(blessas);
+  return hr;
+}
 
 SV *owl_perlconfig_curmessage2hashref(void) /*noproto*/
@@ -110,4 +111,53 @@
 }
 
+/* XXX TODO: Messages should round-trip properly between
+   message2hashref and hashref2message. Currently we lose
+   zephyr-specific properties stored in the ZNotice_t
+ */
+owl_message * owl_perlconfig_hashref2message(SV *msg)
+{
+  owl_message * m;
+  HE * ent;
+  I32 count, len;
+  char *key,*val;
+  HV * hash;
+
+  hash = (HV*)SvRV(msg);
+
+  m = owl_malloc(sizeof(owl_message));
+  owl_message_init(m);
+
+  count = hv_iterinit(hash);
+  while((ent = hv_iternext(hash))) {
+    key = hv_iterkey(ent, &len);
+    val = SvPV_nolen(hv_iterval(hash, ent));
+    if(!strcmp(key, "type")) {
+      owl_message_set_type(m, val);
+    } else if(!strcmp(key, "direction")) {
+      owl_message_set_direction(m, owl_message_parse_direction(val));
+    } else if(!strcmp(key, "private")) {
+      SV * v = hv_iterval(hash, ent);
+      if(SvTRUE(v)) {
+        owl_message_set_isprivate(m);
+      }
+    } else if (!strcmp(key, "hostname")) {
+      owl_message_set_hostname(m, val);
+    } else if (!strcmp(key, "zwriteline")) {
+      owl_message_set_zwriteline(m, val);
+    } else if (!strcmp(key, "time")) {
+      m->timestr = owl_strdup(val);
+      struct tm tm;
+      strptime(val, "%a %b %d %T %Y", &tm);
+      m->time = mktime(&tm);
+    } else {
+      owl_message_set_attribute(m, key, val);
+    }
+  }
+  if(owl_message_is_type_admin(m)) {
+    if(!owl_message_get_attribute_value(m, "adminheader"))
+      owl_message_set_attribute(m, "adminheader", "");
+  }
+  return m;
+}
 
 /* Calls in a scalar context, passing it a hash reference.
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision 7f792c1a023da8876558bfa531134db65e527ef8)
+++ perlglue.xs	(revision 30678ae9bb1c30b7fc37b6cf4e1290116ddebe0c)
@@ -117,11 +117,5 @@
 	SV *msg
 	PREINIT:
-		char * key;
-		char * val;
 		owl_message *m;
-		HV * hash;
-		HE * ent;
-		I32 count;
-		I32 len;
 	CODE:
 	{
@@ -130,38 +124,5 @@
 		}
 
-		hash = (HV*)SvRV(msg);
-		m = owl_malloc(sizeof(owl_message));
-		owl_message_init(m);
-
-		count = hv_iterinit(hash);
-		while((ent = hv_iternext(hash))) {
-			key = hv_iterkey(ent, &len);
-			val = SvPV_nolen(hv_iterval(hash, ent));
-			if(!strcmp(key, "type")) {
-				owl_message_set_type(m, owl_message_parse_type(val));
-			} else if(!strcmp(key, "direction")) {
-				owl_message_set_direction(m, owl_message_parse_direction(val));
-			} else if(!strcmp(key, "private")) {
-				SV * v = hv_iterval(hash, ent);
-				if(SvTRUE(v)) {
-					owl_message_set_isprivate(m);
-				}
-			} else if (!strcmp(key, "hostname")) {
-				owl_message_set_hostname(m, val);
-			} else if (!strcmp(key, "zwriteline")) {
-				owl_message_set_zwriteline(m, val);
-			} else if (!strcmp(key, "time")) {
-				m->timestr = owl_strdup(val);
-				struct tm tm;
-				strptime(val, "%a %b %d %T %Y", &tm);
-				m->time = mktime(&tm);
-			} else {
-				owl_message_set_attribute(m, key, val);
-			}
-		}
-		if(owl_message_is_type_admin(m)) {
-			if(!owl_message_get_attribute_value(m, "adminheader"))
-				owl_message_set_attribute(m, "adminheader", "");
-		} 
+		m = owl_perlconfig_hashref2message(msg);
 
 		owl_global_messagequeue_addmsg(&g, m);
