src/protocols/sametime/meanwhile/srvc_aware.c

changeset 12957
9af807a5c9e7
parent 12956
39a4efae983c
child 12958
706645a0b944
--- a/src/protocols/sametime/meanwhile/srvc_aware.c	Fri Jan 20 00:19:53 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1318 +0,0 @@
-
-/*
-  Meanwhile - Unofficial Lotus Sametime Community Client Library
-  Copyright (C) 2004  Christopher (siege) O'Brien
-  
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Library General Public
-  License as published by the Free Software Foundation; either
-  version 2 of the License, or (at your option) any later version.
-  
-  This library is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  Library General Public License for more details.
-  
-  You should have received a copy of the GNU Library General Public
-  License along with this library; if not, write to the Free
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <glib.h>
-#include <glib/ghash.h>
-#include <glib/glist.h>
-#include <string.h>
-
-#include "mw_channel.h"
-#include "mw_debug.h"
-#include "mw_error.h"
-#include "mw_message.h"
-#include "mw_service.h"
-#include "mw_session.h"
-#include "mw_srvc_aware.h"
-#include "mw_util.h"
-
-
-struct mwServiceAware {
-  struct mwService service;
-
-  struct mwAwareHandler *handler;
-
-  /** map of ENTRY_KEY(aware_entry):aware_entry */
-  GHashTable *entries;
-
-  /** set of guint32:attrib_watch_entry attribute keys */
-  GHashTable *attribs;
-
-  /** collection of lists of awareness for this service. Each item is
-      a mwAwareList */
-  GList *lists;
-
-  /** the buddy list channel */
-  struct mwChannel *channel;
-};
-
-
-struct mwAwareList {
-
-  /** the owning service */
-  struct mwServiceAware *service;
-
-  /** map of ENTRY_KEY(aware_entry):aware_entry */
-  GHashTable *entries;
-
-  /** set of guint32:attrib_watch_entry attribute keys */
-  GHashTable *attribs;
-
-  struct mwAwareListHandler *handler;
-  struct mw_datum client_data;
-};
-
-
-struct mwAwareAttribute {
-  guint32 key;
-  struct mwOpaque data;
-};
-
-
-struct attrib_entry {
-  guint32 key;
-  GList *membership;
-};
-
-
-/** an actual awareness entry, belonging to any number of aware lists */
-struct aware_entry {
-  struct mwAwareSnapshot aware;
-
-  /** list of mwAwareList containing this entry */
-  GList *membership;
-
-  /** collection of attribute values for this entry.
-      map of ATTRIB_KEY(mwAwareAttribute):mwAwareAttribute */
-  GHashTable *attribs;
-};
-
-
-#define ENTRY_KEY(entry) &entry->aware.id
-
-
-/** the channel send types used by this service */
-enum msg_types {
-  msg_AWARE_ADD       = 0x0068,  /**< remove an aware */
-  msg_AWARE_REMOVE    = 0x0069,  /**< add an aware */
-
-  msg_OPT_DO_SET      = 0x00c9,  /**< set an attribute */
-  msg_OPT_DO_UNSET    = 0x00ca,  /**< unset an attribute */
-  msg_OPT_WATCH       = 0x00cb,  /**< set the attribute watch list */
-
-  msg_AWARE_SNAPSHOT  = 0x01f4,  /**< recv aware snapshot */
-  msg_AWARE_UPDATE    = 0x01f5,  /**< recv aware update */
-  msg_AWARE_GROUP     = 0x01f6,  /**< recv group aware */
-
-  msg_OPT_GOT_SET     = 0x0259,  /**< recv attribute set update */
-  msg_OPT_GOT_UNSET   = 0x025a,  /**< recv attribute unset update */
-
-  msg_OPT_GOT_UNKNOWN = 0x025b,  /**< UNKNOWN */
-  
-  msg_OPT_DID_SET     = 0x025d,  /**< attribute set response */
-  msg_OPT_DID_UNSET   = 0x025e,  /**< attribute unset response */
-  msg_OPT_DID_ERROR   = 0x025f,  /**< attribute set/unset error */
-};
-
-
-static void aware_entry_free(struct aware_entry *ae) {
-  mwAwareSnapshot_clear(&ae->aware);
-  g_list_free(ae->membership);
-  g_hash_table_destroy(ae->attribs);
-  g_free(ae);
-}
-
-
-static void attrib_entry_free(struct attrib_entry *ae) {
-  g_list_free(ae->membership);
-  g_free(ae);
-}
-
-
-static void attrib_free(struct mwAwareAttribute *attrib) {
-  mwOpaque_clear(&attrib->data);
-  g_free(attrib);
-}
-
-
-static struct aware_entry *aware_find(struct mwServiceAware *srvc,
-				      struct mwAwareIdBlock *srch) {
-  g_return_val_if_fail(srvc != NULL, NULL);
-  g_return_val_if_fail(srvc->entries != NULL, NULL);
-  g_return_val_if_fail(srch != NULL, NULL);
-  
-  return g_hash_table_lookup(srvc->entries, srch);
-}
-
-
-static struct aware_entry *list_aware_find(struct mwAwareList *list,
-					   struct mwAwareIdBlock *srch) {
-  g_return_val_if_fail(list != NULL, NULL);
-  g_return_val_if_fail(list->entries != NULL, NULL);
-  g_return_val_if_fail(srch != NULL, NULL);
-
-  return g_hash_table_lookup(list->entries, srch);
-}
-
-
-static void compose_list(struct mwPutBuffer *b, GList *id_list) {
-  guint32_put(b, g_list_length(id_list));
-  for(; id_list; id_list = id_list->next)
-    mwAwareIdBlock_put(b, id_list->data);
-}
-
-
-static int send_add(struct mwChannel *chan, GList *id_list) {
-  struct mwPutBuffer *b = mwPutBuffer_new();
-  struct mwOpaque o;
-  int ret;
-
-  g_return_val_if_fail(chan != NULL, 0);
-
-  compose_list(b, id_list);
-
-  mwPutBuffer_finalize(&o, b);
-
-  ret = mwChannel_send(chan, msg_AWARE_ADD, &o);
-  mwOpaque_clear(&o);
-
-  return ret;  
-}
-
-
-static int send_rem(struct mwChannel *chan, GList *id_list) {
-  struct mwPutBuffer *b = mwPutBuffer_new();
-  struct mwOpaque o;
-  int ret;
-
-  g_return_val_if_fail(chan != NULL, 0);
-
-  compose_list(b, id_list);
-  mwPutBuffer_finalize(&o, b);
-
-  ret = mwChannel_send(chan, msg_AWARE_REMOVE, &o);
-  mwOpaque_clear(&o);
-
-  return ret;
-}
-
-
-static gboolean collect_dead(gpointer key, gpointer val, gpointer data) {
-  struct aware_entry *aware = val;
-  GList **dead = data;
-
-  if(aware->membership == NULL) {
-    g_info(" removing %s, %s",
-	   NSTR(aware->aware.id.user), NSTR(aware->aware.id.community));
-    *dead = g_list_append(*dead, aware);
-    return TRUE;
-
-  } else {
-    return FALSE;
-  }
-}
-
-
-static int remove_unused(struct mwServiceAware *srvc) {
-  /* - create a GList of all the unused aware entries
-     - remove each unused aware from the service
-     - if the service is alive, send a removal message for the collected
-     unused.
-  */
-
-  int ret = 0;
-  GList *dead = NULL, *l;
-
-  if(srvc->entries) {
-    g_info("bring out your dead *clang*");
-    g_hash_table_foreach_steal(srvc->entries, collect_dead, &dead);
-  }
- 
-  if(dead) {
-    if(MW_SERVICE_IS_LIVE(srvc))
-      ret = send_rem(srvc->channel, dead) || ret;
-    
-    for(l = dead; l; l = l->next)
-      aware_entry_free(l->data);
-
-    g_list_free(dead);
-  }
-
-  return ret;
-}
-
-
-static int send_attrib_list(struct mwServiceAware *srvc) {
-  struct mwPutBuffer *b;
-  struct mwOpaque o;
-
-  int tmp;
-  GList *l;
-
-  g_return_val_if_fail(srvc != NULL, -1);
-  g_return_val_if_fail(srvc->channel != NULL, 0);
-
-  l = map_collect_keys(srvc->attribs);
-  tmp = g_list_length(l);
-
-  b = mwPutBuffer_new();
-  guint32_put(b, 0x00);
-  guint32_put(b, tmp);
-  
-  for(; l; l = g_list_delete_link(l, l)) {
-    guint32_put(b, GPOINTER_TO_UINT(l->data));
-  }
-
-  mwPutBuffer_finalize(&o, b);
-  tmp = mwChannel_send(srvc->channel, msg_OPT_WATCH, &o);
-  mwOpaque_clear(&o);
-
-  return tmp;
-}
-
-
-static gboolean collect_attrib_dead(gpointer key, gpointer val,
-				    gpointer data) {
-
-  struct attrib_entry *attrib = val;
-  GList **dead = data;
-
-  if(attrib->membership == NULL) {
-    g_info(" removing 0x%08x", GPOINTER_TO_UINT(key));
-    *dead = g_list_append(*dead, attrib);
-    return TRUE;
-
-  } else {
-    return FALSE;
-  }
-}
-
-
-static int remove_unused_attrib(struct mwServiceAware *srvc) {
-  GList *dead = NULL;
-
-  if(srvc->attribs) {
-    g_info("collecting dead attributes");
-    g_hash_table_foreach_steal(srvc->attribs, collect_attrib_dead, &dead);
-  }
- 
-  /* since we stole them, we'll have to clean 'em up manually */
-  for(; dead; dead = g_list_delete_link(dead, dead)) {
-    attrib_entry_free(dead->data);
-  }
-
-  return MW_SERVICE_IS_LIVE(srvc)? send_attrib_list(srvc): 0;
-}
-
-
-static void recv_accept(struct mwServiceAware *srvc,
-			struct mwChannel *chan,
-			struct mwMsgChannelAccept *msg) {
-
-  g_return_if_fail(srvc->channel != NULL);
-  g_return_if_fail(srvc->channel == chan);
-
-  if(MW_SERVICE_IS_STARTING(MW_SERVICE(srvc))) {
-    GList *list = NULL;
-
-    list = map_collect_values(srvc->entries);
-    send_add(chan, list);
-    g_list_free(list);
-
-    send_attrib_list(srvc);
-
-    mwService_started(MW_SERVICE(srvc));
-
-  } else {
-    mwChannel_destroy(chan, ERR_FAILURE, NULL);
-  }
-}
-
-
-static void recv_destroy(struct mwServiceAware *srvc,
-			 struct mwChannel *chan,
-			 struct mwMsgChannelDestroy *msg) {
-
-  srvc->channel = NULL;
-  mwService_stop(MW_SERVICE(srvc));
-
-  /** @todo session sense service and mwService_start */
-}
-
-
-/** called from SNAPSHOT_recv, UPDATE_recv, and
-    mwServiceAware_setStatus */
-static void status_recv(struct mwServiceAware *srvc,
-			struct mwAwareSnapshot *idb) {
-
-  struct aware_entry *aware;
-  GList *l;
-
-  aware = aware_find(srvc, &idb->id);
-
-  if(! aware) {
-    /* we don't deal with receiving status for something we're not
-       monitoring, but it will happen sometimes, eg from manually set
-       status */
-    return;
-  }
-  
-  /* clear the existing status, then clone in the new status */
-  mwAwareSnapshot_clear(&aware->aware);
-  mwAwareSnapshot_clone(&aware->aware, idb);
-  
-  /* trigger each of the entry's lists */
-  for(l = aware->membership; l; l = l->next) {
-    struct mwAwareList *alist = l->data;
-    struct mwAwareListHandler *handler = alist->handler;
-
-    if(handler && handler->on_aware)
-      handler->on_aware(alist, idb);
-  }
-}
-
-
-static void attrib_recv(struct mwServiceAware *srvc,
-			struct mwAwareIdBlock *idb,
-			struct mwAwareAttribute *attrib) {
-
-  struct aware_entry *aware;
-  struct mwAwareAttribute *old_attrib = NULL;
-  GList *l;
-  guint32 key;
-  gpointer k;
-
-  aware = aware_find(srvc, idb);
-  g_return_if_fail(aware != NULL);
-
-  key = attrib->key;
-  k = GUINT_TO_POINTER(key);
-
-  if(aware->attribs)
-    old_attrib = g_hash_table_lookup(aware->attribs, k);
-
-  if(! old_attrib) {
-    old_attrib = g_new0(struct mwAwareAttribute, 1);
-    old_attrib->key = key;
-    g_hash_table_insert(aware->attribs, k, old_attrib);
-  }
-  
-  mwOpaque_clear(&old_attrib->data);
-  mwOpaque_clone(&old_attrib->data, &attrib->data);
-  
-  for(l = aware->membership; l; l = l->next) {
-    struct mwAwareList *list = l->data;
-    struct mwAwareListHandler *h = list->handler;
-
-    if(h && h->on_attrib &&
-       list->attribs && g_hash_table_lookup(list->attribs, k))
-
-      h->on_attrib(list, idb, old_attrib);
-  }
-}
-
-
-gboolean list_add(struct mwAwareList *list, struct mwAwareIdBlock *id) {
-
-  struct mwServiceAware *srvc = list->service;
-  struct aware_entry *aware;
-
-  g_return_val_if_fail(id->user != NULL, FALSE);
-  g_return_val_if_fail(strlen(id->user) > 0, FALSE);
-
-  if(! list->entries)
-    list->entries = g_hash_table_new((GHashFunc) mwAwareIdBlock_hash,
-				     (GEqualFunc) mwAwareIdBlock_equal);
-
-  aware = list_aware_find(list, id);
-  if(aware) return FALSE;
-
-  aware = aware_find(srvc, id);
-  if(! aware) {
-    aware = g_new0(struct aware_entry, 1);
-    aware->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
-					   (GDestroyNotify) attrib_free);
-    mwAwareIdBlock_clone(ENTRY_KEY(aware), id);
-
-    g_hash_table_insert(srvc->entries, ENTRY_KEY(aware), aware);
-  }
-
-  aware->membership = g_list_append(aware->membership, list);
-
-  g_hash_table_insert(list->entries, ENTRY_KEY(aware), aware);
-
-  return TRUE;
-}
-
-
-static void group_member_recv(struct mwServiceAware *srvc,
-			      struct mwAwareSnapshot *idb) {
-  /* @todo
-     - look up group by id
-     - find each list group belongs to
-     - add user to lists
-  */
-
-  struct mwAwareIdBlock gsrch = { mwAware_GROUP, idb->group, NULL };
-  struct aware_entry *grp;
-  GList *l, *m;
-
-  grp = aware_find(srvc, &gsrch);
-  g_return_if_fail(grp != NULL); /* this could happen, with timing. */
-
-  l = g_list_prepend(NULL, &idb->id);
-
-  for(m = grp->membership; m; m = m->next) {
-
-    /* if we just list_add, we won't receive updates for attributes,
-       so annoyingly we have to turn around and send out an add aware
-       message for each incoming group member */
-
-    /* list_add(m->data, &idb->id); */
-    mwAwareList_addAware(m->data, l);
-  }
-
-  g_list_free(l);
-}
-
-
-static void recv_SNAPSHOT(struct mwServiceAware *srvc,
-			  struct mwGetBuffer *b) {
-
-  guint32 count;
-
-  struct mwAwareSnapshot *snap;
-  snap = g_new0(struct mwAwareSnapshot, 1);
-
-  guint32_get(b, &count);
-
-  while(count--) {
-    mwAwareSnapshot_get(b, snap);
-
-    if(mwGetBuffer_error(b)) {
-      mwAwareSnapshot_clear(snap);
-      break;
-    }
-
-    if(snap->group)
-      group_member_recv(srvc, snap);
-
-    status_recv(srvc, snap);
-    mwAwareSnapshot_clear(snap);
-  }
-
-  g_free(snap);
-}
-
-
-static void recv_UPDATE(struct mwServiceAware *srvc,
-			struct mwGetBuffer *b) {
-
-  struct mwAwareSnapshot *snap;
-
-  snap = g_new0(struct mwAwareSnapshot, 1);
-  mwAwareSnapshot_get(b, snap);
-
-  if(snap->group)
-    group_member_recv(srvc, snap);
-
-  if(! mwGetBuffer_error(b))
-    status_recv(srvc, snap);
-
-  mwAwareSnapshot_clear(snap);
-  g_free(snap);
-}
-
-
-static void recv_GROUP(struct mwServiceAware *srvc,
-		       struct mwGetBuffer *b) {
-
-  struct mwAwareIdBlock idb = { 0, 0, 0 };
-
-  /* really nothing to be done with this. The group should have
-     already been added to the list and service, and is now simply
-     awaiting a snapshot/update with users listed as belonging in said
-     group. */
-
-  mwAwareIdBlock_get(b, &idb);
-  mwAwareIdBlock_clear(&idb);
-}
-
-
-static void recv_OPT_GOT_SET(struct mwServiceAware *srvc,
-			     struct mwGetBuffer *b) {
-
-  struct mwAwareAttribute attrib;
-  struct mwAwareIdBlock idb;
-  guint32 junk, check;
-
-  guint32_get(b, &junk);
-  mwAwareIdBlock_get(b, &idb);
-  guint32_get(b, &junk);
-  guint32_get(b, &check);
-  guint32_get(b, &junk);
-  guint32_get(b, &attrib.key);
-
-  if(check) {
-    mwOpaque_get(b, &attrib.data);
-  } else {
-    attrib.data.len = 0;
-    attrib.data.data = NULL;
-  }
-
-  attrib_recv(srvc, &idb, &attrib);
-
-  mwAwareIdBlock_clear(&idb);
-  mwOpaque_clear(&attrib.data);
-}
-
-
-static void recv_OPT_GOT_UNSET(struct mwServiceAware *srvc,
-			       struct mwGetBuffer *b) {
-
-  struct mwAwareAttribute attrib;
-  struct mwAwareIdBlock idb;
-  guint32 junk;
-
-  attrib.key = 0;
-  attrib.data.len = 0;
-  attrib.data.data = NULL;
-
-  guint32_get(b, &junk);
-  mwAwareIdBlock_get(b, &idb);
-  guint32_get(b, &attrib.key);
-
-  attrib_recv(srvc, &idb, &attrib);
-
-  mwAwareIdBlock_clear(&idb);
-}
-
-
-static void recv(struct mwService *srvc, struct mwChannel *chan,
-		 guint16 type, struct mwOpaque *data) {
-
-  struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc;
-  struct mwGetBuffer *b;
-
-  g_return_if_fail(srvc_aware->channel == chan);
-  g_return_if_fail(srvc->session == mwChannel_getSession(chan));
-  g_return_if_fail(data != NULL);
-
-  b = mwGetBuffer_wrap(data);
-
-  switch(type) {
-  case msg_AWARE_SNAPSHOT:
-    recv_SNAPSHOT(srvc_aware, b);
-    break;
-
-  case msg_AWARE_UPDATE:
-    recv_UPDATE(srvc_aware, b);
-    break;
-
-  case msg_AWARE_GROUP:
-    recv_GROUP(srvc_aware, b);
-    break;
-
-  case msg_OPT_GOT_SET:
-    recv_OPT_GOT_SET(srvc_aware, b);
-    break;
-
-  case msg_OPT_GOT_UNSET:
-    recv_OPT_GOT_UNSET(srvc_aware, b);
-    break;
-
-  case msg_OPT_GOT_UNKNOWN:
-  case msg_OPT_DID_SET:
-  case msg_OPT_DID_UNSET:
-  case msg_OPT_DID_ERROR:
-    break;
-
-  default:
-    mw_mailme_opaque(data, "unknown message in aware service: 0x%04x", type);
-  }
-
-  mwGetBuffer_free(b);  
-}
-
-
-static void clear(struct mwService *srvc) {
-  struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc;
-
-  g_return_if_fail(srvc != NULL);
-
-  while(srvc_aware->lists)
-    mwAwareList_free( (struct mwAwareList *) srvc_aware->lists->data );
-
-  g_hash_table_destroy(srvc_aware->entries);
-  srvc_aware->entries = NULL;
-
-  g_hash_table_destroy(srvc_aware->attribs);
-  srvc_aware->attribs = NULL;
-}
-
-
-static const char *name(struct mwService *srvc) {
-  return "Presence Awareness";
-}
-
-
-static const char *desc(struct mwService *srvc) {
-  return "Buddy list service with support for server-side groups";
-}
-
-
-static struct mwChannel *make_blist(struct mwServiceAware *srvc,
-				    struct mwChannelSet *cs) {
-
-  struct mwChannel *chan = mwChannel_newOutgoing(cs);
-
-  mwChannel_setService(chan, MW_SERVICE(srvc));
-  mwChannel_setProtoType(chan, 0x00000011);
-  mwChannel_setProtoVer(chan, 0x00030005);
-
-  return mwChannel_create(chan)? NULL: chan;
-}
-
-
-static void start(struct mwService *srvc) {
-  struct mwServiceAware *srvc_aware;
-  struct mwChannel *chan = NULL;
-
-  srvc_aware = (struct mwServiceAware *) srvc;
-  chan = make_blist(srvc_aware, mwSession_getChannels(srvc->session));
-
-  if(chan != NULL) {
-    srvc_aware->channel = chan;
-  } else {
-    mwService_stopped(srvc);
-  }
-}
-
-
-static void stop(struct mwService *srvc) {
-  struct mwServiceAware *srvc_aware;
-
-  srvc_aware = (struct mwServiceAware *) srvc;
-
-  if(srvc_aware->channel) {
-    mwChannel_destroy(srvc_aware->channel, ERR_SUCCESS, NULL);
-    srvc_aware->channel = NULL;
-  }
-
-  mwService_stopped(srvc);
-}
-
-
-struct mwServiceAware *
-mwServiceAware_new(struct mwSession *session,
-		   struct mwAwareHandler *handler) {
-
-  struct mwService *service;
-  struct mwServiceAware *srvc;
-
-  g_return_val_if_fail(session != NULL, NULL);
-  g_return_val_if_fail(handler != NULL, NULL);
-
-  srvc = g_new0(struct mwServiceAware, 1);
-  srvc->handler = handler;
-  srvc->entries = g_hash_table_new_full((GHashFunc) mwAwareIdBlock_hash,
-					(GEqualFunc) mwAwareIdBlock_equal,
-					NULL,
-					(GDestroyNotify) aware_entry_free);
-
-  srvc->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
-					(GDestroyNotify) attrib_entry_free);
-
-  service = MW_SERVICE(srvc);
-  mwService_init(service, session, mwService_AWARE);
-
-  service->recv_accept = (mwService_funcRecvAccept) recv_accept;
-  service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
-  service->recv = recv;
-  service->start = start;
-  service->stop = stop;
-  service->clear = clear;
-  service->get_name = name;
-  service->get_desc = desc;
-
-  return srvc;
-}
-
-
-int mwServiceAware_setAttribute(struct mwServiceAware *srvc,
-				guint32 key, struct mwOpaque *data) {
-  struct mwPutBuffer *b;
-  struct mwOpaque o;
-  int ret;
-
-  b = mwPutBuffer_new();
-
-  guint32_put(b, 0x00);
-  guint32_put(b, data->len);
-  guint32_put(b, 0x00);
-  guint32_put(b, key);
-  mwOpaque_put(b, data);
-
-  mwPutBuffer_finalize(&o, b);
-  ret = mwChannel_send(srvc->channel, msg_OPT_DO_SET, &o);
-  mwOpaque_clear(&o);
-
-  return ret;
-}
-
-
-int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc,
-				       guint32 key, gboolean val) {
-  int ret;
-  struct mwPutBuffer *b;
-  struct mwOpaque o;
- 
-  b = mwPutBuffer_new();
-
-  gboolean_put(b, FALSE);
-  gboolean_put(b, val);
-
-  mwPutBuffer_finalize(&o, b);
-
-  ret = mwServiceAware_setAttribute(srvc, key, &o);
-  mwOpaque_clear(&o);
-
-  return ret;
-}
-
-
-int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc,
-				       guint32 key, guint32 val) {
-  int ret;
-  struct mwPutBuffer *b;
-  struct mwOpaque o;
-  
-  b = mwPutBuffer_new();
-  guint32_put(b, val);
-
-  mwPutBuffer_finalize(&o, b);
-
-  ret = mwServiceAware_setAttribute(srvc, key, &o);
-  mwOpaque_clear(&o);
-
-  return ret;
-}
-
-
-int mwServiceAware_setAttributeString(struct mwServiceAware *srvc,
-				      guint32 key, const char *str) {
-  int ret;
-  struct mwPutBuffer *b;
-  struct mwOpaque o;
-
-  b = mwPutBuffer_new();
-  mwString_put(b, str);
-
-  mwPutBuffer_finalize(&o, b);
-
-  ret = mwServiceAware_setAttribute(srvc, key, &o);
-  mwOpaque_clear(&o);
-
-  return ret;
-}
-
-
-int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc,
-				  guint32 key) {
-  struct mwPutBuffer *b;
-  struct mwOpaque o;
-  int ret;
-
-  b = mwPutBuffer_new();
-
-  guint32_put(b, 0x00);
-  guint32_put(b, key);
-  
-  mwPutBuffer_finalize(&o, b);
-  ret = mwChannel_send(srvc->channel, msg_OPT_DO_UNSET, &o);
-  mwOpaque_clear(&o);
-
-  return ret;
-}
-
-
-guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib) {
-  g_return_val_if_fail(attrib != NULL, 0x00);
-  return attrib->key;
-}
-
-
-gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib) {
-  struct mwGetBuffer *b;
-  gboolean ret;
-  
-  if(! attrib) return FALSE;
-
-  b = mwGetBuffer_wrap(&attrib->data);
-  if(attrib->data.len >= 4) {
-    guint32 r32 = 0x00;
-    guint32_get(b, &r32);
-    ret = !! r32;
-
-  } else if(attrib->data.len >= 2) {
-    guint16 r16 = 0x00;
-    guint16_get(b, &r16);
-    ret = !! r16;
-
-  } else if(attrib->data.len) {
-    gboolean_get(b, &ret);
-  }
-
-  mwGetBuffer_free(b);
-
-  return ret;
-}
-
-
-guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib) {
-  struct mwGetBuffer *b;
-  guint32 r32 = 0x00;
-  
-  if(! attrib) return 0x00;
-
-  b = mwGetBuffer_wrap(&attrib->data);
-  if(attrib->data.len >= 4) {
-    guint32_get(b, &r32);
-
-  } else if(attrib->data.len == 3) {
-    gboolean rb = FALSE;
-    guint16 r16 = 0x00;
-    gboolean_get(b, &rb);
-    guint16_get(b, &r16);
-    r32 = (guint32) r16;
-
-  } else if(attrib->data.len == 2) {
-    guint16 r16 = 0x00;
-    guint16_get(b, &r16);
-    r32 = (guint32) r16;
-
-  } else if(attrib->data.len) {
-    gboolean rb = FALSE;
-    gboolean_get(b, &rb);
-    r32 = (guint32) rb;
-  }
-
-  mwGetBuffer_free(b);
-
-  return r32;
-}
-
-
-char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib) {
-  struct mwGetBuffer *b;
-  char *ret = NULL;
-
-  if(! attrib) return NULL;
-
-  b = mwGetBuffer_wrap(&attrib->data);
-  mwString_get(b, &ret);
-  mwGetBuffer_free(b);
-
-  return ret;
-}
-
-
-const struct mwOpaque *
-mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib) {
-  g_return_val_if_fail(attrib != NULL, NULL);
-  return &attrib->data;
-}
-			  
-
-struct mwAwareList *
-mwAwareList_new(struct mwServiceAware *srvc,
-		struct mwAwareListHandler *handler) {
-
-  struct mwAwareList *al;
-
-  g_return_val_if_fail(srvc != NULL, NULL);
-  g_return_val_if_fail(handler != NULL, NULL);
-
-  al = g_new0(struct mwAwareList, 1);
-  al->service = srvc;
-  al->handler = handler;
-
-  srvc->lists = g_list_prepend(srvc->lists, al);
-
-  return al;
-}
-
-
-void mwAwareList_free(struct mwAwareList *list) {
-  struct mwServiceAware *srvc;
-  struct mwAwareListHandler *handler;
-
-  g_return_if_fail(list != NULL);
-  g_return_if_fail(list->service != NULL);
-
-  srvc = list->service;
-  srvc->lists = g_list_remove_all(srvc->lists, list);
-
-  handler = list->handler;
-  if(handler && handler->clear) {
-    handler->clear(list);
-    list->handler = NULL;
-  }
-
-  mw_datum_clear(&list->client_data);
-
-  mwAwareList_unwatchAllAttributes(list);
-  mwAwareList_removeAllAware(list);
-
-  list->service = NULL;
-
-  g_free(list);
-}
-
-
-struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list) {
-  g_return_val_if_fail(list != NULL, NULL);
-  return list->handler;
-}
-
-
-static void watch_add(struct mwAwareList *list, guint32 key) {
-  struct mwServiceAware *srvc;
-  struct attrib_entry *watch;
-  gpointer k = GUINT_TO_POINTER(key);
-
-  if(! list->attribs)
-    list->attribs = g_hash_table_new(g_direct_hash, g_direct_equal);
-
-  if(g_hash_table_lookup(list->attribs, k))
-    return;
-
-  srvc = list->service;
-
-  watch = g_hash_table_lookup(srvc->attribs, k);
-  if(! watch) {
-    watch = g_new0(struct attrib_entry, 1);
-    watch->key = key;
-    g_hash_table_insert(srvc->attribs, k, watch);
-  }
-
-  g_hash_table_insert(list->attribs, k, watch);
-
-  watch->membership = g_list_prepend(watch->membership, list);
-}
-
-
-static void watch_remove(struct mwAwareList *list, guint32 key) {
-  struct attrib_entry *watch = NULL;
-  gpointer k = GUINT_TO_POINTER(key);
-
-  if(list->attribs)
-    watch = g_hash_table_lookup(list->attribs, k);
-
-  g_return_if_fail(watch != NULL);
-
-  g_hash_table_remove(list->attribs, k);
-  watch->membership = g_list_remove(watch->membership, list);
-}
-
-
-int mwAwareList_watchAttributeArray(struct mwAwareList *list,
-				    guint32 *keys) {
-  guint32 k;
-
-  g_return_val_if_fail(list != NULL, -1);
-  g_return_val_if_fail(list->service != NULL, -1);
-
-  if(! keys) return 0;
-
-  for(k = *keys; k; keys++)
-    watch_add(list, k);
-
-  return send_attrib_list(list->service);
-}
-
-
-int mwAwareList_watchAttributes(struct mwAwareList *list,
-				guint32 key, ...) {
-  guint32 k;
-  va_list args;
-
-  g_return_val_if_fail(list != NULL, -1);
-  g_return_val_if_fail(list->service != NULL, -1);
-
-  va_start(args, key);
-  for(k = key; k; k = va_arg(args, guint32))
-    watch_add(list, k);
-  va_end(args);
-
-  return send_attrib_list(list->service);
-}
-
-
-int mwAwareList_unwatchAttributeArray(struct mwAwareList *list,
-				      guint32 *keys) {
-  guint32 k;
-
-  g_return_val_if_fail(list != NULL, -1);
-  g_return_val_if_fail(list->service != NULL, -1);
-
-  if(! keys) return 0;
-
-  for(k = *keys; k; keys++)
-    watch_add(list, k);
-
-  return remove_unused_attrib(list->service);
-}
-
-
-int mwAwareList_unwatchAttributes(struct mwAwareList *list,
-				  guint32 key, ...) {
-  guint32 k;
-  va_list args;
-
-  g_return_val_if_fail(list != NULL, -1);
-  g_return_val_if_fail(list->service != NULL, -1);
-
-  va_start(args, key);
-  for(k = key; k; k = va_arg(args, guint32))
-    watch_remove(list, k);
-  va_end(args);
-
-  return remove_unused_attrib(list->service);
-}
-
-
-static void dismember_attrib(gpointer k, struct attrib_entry *watch,
-			    struct mwAwareList *list) {
-
-  watch->membership = g_list_remove(watch->membership, list);
-}
-
-
-int mwAwareList_unwatchAllAttributes(struct mwAwareList *list) {
-  
-  struct mwServiceAware *srvc;
-
-  g_return_val_if_fail(list != NULL, -1);
-  srvc = list->service;
-
-  if(list->attribs) {
-    g_hash_table_foreach(list->attribs, (GHFunc) dismember_attrib, list);
-    g_hash_table_destroy(list->attribs);
-  }
-
-  return remove_unused_attrib(srvc);
-}
-
-
-static void collect_attrib_keys(gpointer key, struct attrib_entry *attrib,
-				guint32 **ck) {
-  guint32 *keys = (*ck)++;
-  *keys = GPOINTER_TO_UINT(key);
-}
-
-
-guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list) {
-  guint32 *keys, **ck;
-  guint count;
-
-  g_return_val_if_fail(list != NULL, NULL);
-  g_return_val_if_fail(list->attribs != NULL, NULL);
-  
-  count = g_hash_table_size(list->attribs);
-  keys = g_new0(guint32, count + 1);
-
-  ck = &keys;
-  g_hash_table_foreach(list->attribs, (GHFunc) collect_attrib_keys, ck);
-
-  return keys;
-}
-
-
-int mwAwareList_addAware(struct mwAwareList *list, GList *id_list) {
-
-  /* for each awareness id:
-     - if it's already in the list, continue
-     - if it's not in the service list:
-       - create an awareness
-       - add it to the service list
-     - add this list to the membership
-     - add to the list
-  */
-
-  struct mwServiceAware *srvc;
-  GList *additions = NULL;
-  int ret = 0;
-
-  g_return_val_if_fail(list != NULL, -1);
-
-  srvc = list->service;
-  g_return_val_if_fail(srvc != NULL, -1);
-
-  for(; id_list; id_list = id_list->next) {
-    if(list_add(list, id_list->data))
-      additions = g_list_prepend(additions, id_list->data);
-  }
-
-  /* if the service is alive-- or getting there-- we'll need to send
-     these additions upstream */
-  if(MW_SERVICE_IS_LIVE(srvc) && additions)
-    ret = send_add(srvc->channel, additions);
-
-  g_list_free(additions);
-  return ret;
-}
-
-
-int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list) {
-
-  /* for each awareness id:
-     - if it's not in the list, forget it
-     - remove from the list
-     - remove list from the membership
-
-     - call remove round
-  */
-
-  struct mwServiceAware *srvc;
-  struct mwAwareIdBlock *id;
-  struct aware_entry *aware;
-
-  g_return_val_if_fail(list != NULL, -1);
-
-  srvc = list->service;
-  g_return_val_if_fail(srvc != NULL, -1);
-
-  for(; id_list; id_list = id_list->next) {
-    id = id_list->data;
-    aware = list_aware_find(list, id);
-
-    if(! aware) {
-      g_warning("buddy %s, %s not in list",
-		NSTR(id->user),
-		NSTR(id->community));
-      continue;
-    }
-
-    aware->membership = g_list_remove(aware->membership, list);
-    g_hash_table_remove(list->entries, id);
-  }
-
-  return remove_unused(srvc);
-}
-
-
-static void dismember_aware(gpointer k, struct aware_entry *aware,
-			    struct mwAwareList *list) {
-
-  aware->membership = g_list_remove(aware->membership, list);
-}
-
-
-int mwAwareList_removeAllAware(struct mwAwareList *list) {
-  struct mwServiceAware *srvc;
-
-  g_return_val_if_fail(list != NULL, -1);
-  srvc = list->service;
-
-  g_return_val_if_fail(srvc != NULL, -1);
-
-  /* for each entry, remove the aware list from the service entry's
-     membership collection */
-  if(list->entries) {
-    g_hash_table_foreach(list->entries, (GHFunc) dismember_aware, list);
-    g_hash_table_destroy(list->entries);
-  }
-
-  return remove_unused(srvc);
-}
-
-
-void mwAwareList_setClientData(struct mwAwareList *list,
-			       gpointer data, GDestroyNotify clear) {
-
-  g_return_if_fail(list != NULL);
-  mw_datum_set(&list->client_data, data, clear);
-}
-
-
-gpointer mwAwareList_getClientData(struct mwAwareList *list) {
-  g_return_val_if_fail(list != NULL, NULL);
-  return mw_datum_get(&list->client_data);
-}
-
-
-void mwAwareList_removeClientData(struct mwAwareList *list) {
-  g_return_if_fail(list != NULL);
-  mw_datum_clear(&list->client_data);
-}
-
-
-void mwServiceAware_setStatus(struct mwServiceAware *srvc,
-			      struct mwAwareIdBlock *user,
-			      struct mwUserStatus *stat) {
-
-  struct mwAwareSnapshot idb;
-
-  g_return_if_fail(srvc != NULL);
-  g_return_if_fail(user != NULL);
-  g_return_if_fail(stat != NULL);
-
-  /* just reference the strings. then we don't need to free them */
-  idb.id.type = user->type;
-  idb.id.user = user->user;
-  idb.id.community = user->community;
-
-  idb.group = NULL;
-  idb.online = TRUE;
-  idb.alt_id = NULL;
-
-  idb.status.status = stat->status;
-  idb.status.time = stat->time;
-  idb.status.desc = stat->desc;
-
-  idb.name = NULL;
-
-  status_recv(srvc, &idb);
-}
-
-
-const struct mwAwareAttribute *
-mwServiceAware_getAttribute(struct mwServiceAware *srvc,
-			    struct mwAwareIdBlock *user,
-			    guint32 key) {
-
-  struct aware_entry *aware;
-
-  g_return_val_if_fail(srvc != NULL, NULL);
-  g_return_val_if_fail(user != NULL, NULL);
-  g_return_val_if_fail(key != 0x00, NULL);
-
-  aware = aware_find(srvc, user);
-  g_return_val_if_fail(aware != NULL, NULL);
-
-  return g_hash_table_lookup(aware->attribs, GUINT_TO_POINTER(key));
-}
-
-
-const char *mwServiceAware_getText(struct mwServiceAware *srvc,
-				   struct mwAwareIdBlock *user) {
-
-  struct aware_entry *aware;
-
-  g_return_val_if_fail(srvc != NULL, NULL);
-  g_return_val_if_fail(user != NULL, NULL);
-
-  aware = aware_find(srvc, user);
-  if(! aware) return NULL;
-
-  return aware->aware.status.desc;
-}
-
-

mercurial