Blame src/srvc_aware.c

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