Blame src/srvc_aware.c

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