Blame src/srvc_aware.c.fix-glib-headers

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