diff src/protocols/sametime/meanwhile/common.c @ 10969:3ef77720e577

[gaim-migrate @ 12790] importing meanwhile library for use in the sametime plugin committer: Tailor Script <tailor@pidgin.im>
author Christopher O'Brien <siege@pidgin.im>
date Sun, 05 Jun 2005 02:50:13 +0000
parents
children 0110fc7c6a8a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/sametime/meanwhile/common.c	Sun Jun 05 02:50:13 2005 +0000
@@ -0,0 +1,982 @@
+
+/*
+  Meanwhile - Unofficial Lotus Sametime Community Client Library
+  Copyright (C) 2004  Christopher (siege) O'Brien
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+  
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+  
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <glib.h>
+#include <string.h>
+
+#include "mw_common.h"
+
+
+/** @todo the *_get functions should make sure to clear their
+    structures in the event of failure, to prevent memory leaks */
+
+
+#define MW16_PUT(b, val) \
+  *(b)++ = ((val) >> 0x08) & 0xff; \
+  *(b)++ = (val) & 0xff;
+
+
+#define MW16_GET(b, val) \
+  val = (*(b)++ & 0xff) << 8; \
+  val = val | (*(b)++ & 0xff);
+
+
+#define MW32_PUT(b, val) \
+  *(b)++ = ((val) >> 0x18) & 0xff; \
+  *(b)++ = ((val) >> 0x10) & 0xff; \
+  *(b)++ = ((val) >> 0x08) & 0xff; \
+  *(b)++ = (val) & 0xff;
+
+
+#define MW32_GET(b, val) \
+  val = (*(b)++ & 0xff) << 0x18; \
+  val = val | (*(b)++ & 0xff) << 0x10; \
+  val = val | (*(b)++ & 0xff) << 0x08; \
+  val = val | (*(b)++ & 0xff);
+
+
+struct mwPutBuffer {
+  char *buf;  /**< head of buffer */
+  gsize len;  /**< length of buffer */
+
+  char *ptr;  /**< offset to first unused byte */
+  gsize rem;  /**< count of unused bytes remaining */
+};
+
+
+struct mwGetBuffer {
+  char *buf;  /**< head of buffer */
+  gsize len;  /**< length of buffer */
+
+  char *ptr;  /**< offset to first unused byte */
+  gsize rem;  /**< count of unused bytes remaining */
+
+  gboolean wrap;   /**< TRUE to indicate buf shouldn't be freed */
+  gboolean error;  /**< TRUE to indicate an error */
+};
+
+
+#define BUFFER_USED(buffer) \
+  ((buffer)->len - (buffer)->rem)
+
+
+/** ensure that there's at least enough space remaining in the put
+    buffer to fit needed. */
+static void ensure_buffer(struct mwPutBuffer *b, gsize needed) {
+  if(b->rem < needed) {
+    gsize len = b->len, use = BUFFER_USED(b);
+    char *buf;
+
+    /* newly created buffers are empty until written to, and then they
+       have 1024 available */
+    if(! len) len = 1024;
+
+    /* double len until it's large enough to fit needed */
+    while( (len - use) < needed ) len = len << 1;
+
+    /* create the new buffer. if there was anything in the old buffer,
+       copy it into the new buffer and free the old copy */
+    buf = g_malloc(len);
+    if(b->buf) {
+      memcpy(buf, b->buf, use);
+      g_free(b->buf);
+    }
+
+    /* put the new buffer into b */
+    b->buf = buf;
+    b->len = len;
+    b->ptr = buf + use;
+    b->rem = len - use;
+  }
+}
+
+
+/** determine if there are at least needed bytes available in the
+    buffer. sets the error flag if there's not at least needed bytes
+    left in the buffer
+
+    @returns true if there's enough data, false if not */
+static gboolean check_buffer(struct mwGetBuffer *b, gsize needed) {
+  if(! b->error)  b->error = (b->rem < needed);
+  return ! b->error;
+}
+
+
+struct mwPutBuffer *mwPutBuffer_new() {
+  return g_new0(struct mwPutBuffer, 1);
+}
+
+
+void mwPutBuffer_write(struct mwPutBuffer *b, gpointer data, gsize len) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(data != NULL);
+
+  if(! len) return;
+
+  ensure_buffer(b, len);
+  memcpy(b->ptr, data, len);
+  b->ptr += len;
+  b->rem -= len;
+}
+
+
+void mwPutBuffer_free(struct mwPutBuffer *b) {
+  if(! b) return;
+  g_free(b->buf);
+  g_free(b);
+}
+
+
+void mwPutBuffer_finalize(struct mwOpaque *to, struct mwPutBuffer *from) {
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  to->len = BUFFER_USED(from);
+  to->data = from->buf;
+
+  g_free(from);
+}
+
+
+struct mwGetBuffer *mwGetBuffer_new(struct mwOpaque *o) {
+  struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1);
+
+  if(o && o->len) {
+    b->buf = b->ptr = g_memdup(o->data, o->len);
+    b->len = b->rem = o->len;
+  }
+
+  return b;
+}
+
+
+struct mwGetBuffer *mwGetBuffer_wrap(const struct mwOpaque *o) {
+  struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1);
+
+  if(o && o->len) {
+    b->buf = b->ptr = (char *) o->data;
+    b->len = b->rem = o->len;
+  }
+  b->wrap = TRUE;
+
+  return b;
+}
+
+
+gsize mwGetBuffer_read(struct mwGetBuffer *b, gpointer data, gsize len) {
+  g_return_val_if_fail(b != NULL, 0);
+  g_return_val_if_fail(data != NULL, 0);
+
+  if(b->error) return 0;
+  if(! len) return 0;
+
+  if(b->rem < len)
+    len = b->rem;
+
+  memcpy(data, b->ptr, len);
+  b->ptr += len;
+  b->rem -= len;
+
+  return len;
+}
+
+
+gsize mwGetBuffer_advance(struct mwGetBuffer *b, gsize len) {
+  g_return_val_if_fail(b != NULL, 0);
+
+  if(b->error) return 0;
+  if(! len) return 0;
+
+  if(b->rem < len)
+    len = b->rem;
+
+  b->ptr += len;
+  b->rem -= len;
+
+  return len;
+}
+
+
+void mwGetBuffer_reset(struct mwGetBuffer *b) {
+  g_return_if_fail(b != NULL);
+
+  b->rem = b->len;
+  b->ptr = b->buf;
+  b->error = FALSE;
+}
+
+
+gsize mwGetBuffer_remaining(struct mwGetBuffer *b) {
+  g_return_val_if_fail(b != NULL, 0);
+  return b->rem;
+}
+
+
+gboolean mwGetBuffer_error(struct mwGetBuffer *b) {
+  g_return_val_if_fail(b != NULL, TRUE);
+  return b->error;
+}
+
+
+void mwGetBuffer_free(struct mwGetBuffer *b) {
+  if(! b) return;
+  if(! b->wrap) g_free(b->buf);
+  g_free(b);
+}
+
+
+#define guint16_buflen()  2
+
+
+void guint16_put(struct mwPutBuffer *b, guint16 val) {
+  g_return_if_fail(b != NULL);
+
+  ensure_buffer(b, guint16_buflen());
+  MW16_PUT(b->ptr, val);
+  b->rem -= guint16_buflen();
+}
+
+
+void guint16_get(struct mwGetBuffer *b, guint16 *val) {
+  g_return_if_fail(b != NULL);
+
+  if(b->error) return;
+  g_return_if_fail(check_buffer(b, guint16_buflen()));
+
+  MW16_GET(b->ptr, *val);
+  b->rem -= guint16_buflen();
+}
+
+
+guint16 guint16_peek(struct mwGetBuffer *b) {
+  char *buf = b->buf;
+  guint16 r = 0;
+  
+  if(b->rem >= guint16_buflen())
+    MW16_GET(buf, r);
+
+  return r;
+}
+
+
+#define guint32_buflen()  4
+
+
+void guint32_put(struct mwPutBuffer *b, guint32 val) {
+  g_return_if_fail(b != NULL);
+
+  ensure_buffer(b, guint32_buflen());
+  MW32_PUT(b->ptr, val);
+  b->rem -= guint32_buflen();
+}
+
+
+void guint32_get(struct mwGetBuffer *b, guint32 *val) {
+  g_return_if_fail(b != NULL);
+
+  if(b->error) return;
+  g_return_if_fail(check_buffer(b, guint32_buflen()));
+
+  MW32_GET(b->ptr, *val);
+  b->rem -= guint32_buflen();
+}
+
+
+guint32 guint32_peek(struct mwGetBuffer *b) {
+  char *buf = b->buf;
+  guint32 r = 0;
+
+  if(b->rem >= guint32_buflen())
+    MW32_GET(buf, r);
+
+  return r;
+}
+
+
+#define gboolean_buflen()  1
+
+
+void gboolean_put(struct mwPutBuffer *b, gboolean val) {
+  g_return_if_fail(b != NULL);
+
+  ensure_buffer(b, gboolean_buflen());
+  *(b->ptr) = !! val;
+  b->ptr++;
+  b->rem--;
+}
+
+
+void gboolean_get(struct mwGetBuffer *b, gboolean *val) {
+  g_return_if_fail(b != NULL);
+
+  if(b->error) return;
+  g_return_if_fail(check_buffer(b, gboolean_buflen()));
+
+  *val = !! *(b->ptr);
+  b->ptr++;
+  b->rem--;
+}
+
+
+gboolean gboolean_peek(struct mwGetBuffer *b) {
+  gboolean v = FALSE;
+
+  if(b->rem >= gboolean_buflen())
+    v = !! *(b->ptr);
+
+  return v;
+}
+
+
+gboolean mw_streq(const char *a, const char *b) {
+  return (a == b) || (a && b && !strcmp(a, b));
+}
+
+
+void mwString_put(struct mwPutBuffer *b, const char *val) {
+  gsize len = 0;
+
+  g_return_if_fail(b != NULL);
+
+  if(val) len = strlen(val);
+
+  guint16_put(b, (guint16) len);
+
+  if(len) {
+    ensure_buffer(b, len);
+    memcpy(b->ptr, val, len);
+    b->ptr += len;
+    b->rem -= len;
+  }
+}
+
+
+void mwString_get(struct mwGetBuffer *b, char **val) {
+  guint16 len = 0;
+
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(val != NULL);
+
+  *val = NULL;
+
+  if(b->error) return;
+  guint16_get(b, &len);
+
+  g_return_if_fail(check_buffer(b, (gsize) len));
+
+  if(len) {
+    *val = g_malloc0(len + 1);
+    memcpy(*val, b->ptr, len);
+    b->ptr += len;
+    b->rem -= len;
+  }
+}
+
+
+void mwOpaque_put(struct mwPutBuffer *b, const struct mwOpaque *o) {
+  gsize len;
+
+  g_return_if_fail(b != NULL);
+
+  if(! o) {
+    guint32_put(b, 0x00);
+    return;
+  }
+
+  len = o->len;
+  if(len)
+    g_return_if_fail(o->data != NULL);
+  
+  guint32_put(b, (guint32) len);
+
+  if(len) {
+    ensure_buffer(b, len);
+    memcpy(b->ptr, o->data, len);
+    b->ptr += len;
+    b->rem -= len;
+  }
+}
+
+
+void mwOpaque_get(struct mwGetBuffer *b, struct mwOpaque *o) {
+  guint32 tmp = 0;
+
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(o != NULL);
+
+  o->len = 0;
+  o->data = NULL;
+  
+  if(b->error) return;
+  guint32_get(b, &tmp);
+
+  g_return_if_fail(check_buffer(b, (gsize) tmp));
+
+  o->len = (gsize) tmp;
+  if(tmp > 0) {
+    o->data = g_memdup(b->ptr, tmp);
+    b->ptr += tmp;
+    b->rem -= tmp;
+  }
+}
+
+
+void mwOpaque_clear(struct mwOpaque *o) {
+  if(! o) return;
+  g_free(o->data);
+  o->data = NULL;
+  o->len = 0;
+}
+
+
+void mwOpaque_free(struct mwOpaque *o) {
+  if(! o) return;
+  g_free(o->data);
+  g_free(o);
+}
+
+
+void mwOpaque_clone(struct mwOpaque *to, const struct mwOpaque *from) {
+  g_return_if_fail(to != NULL);
+
+  to->len = 0;
+  to->data = NULL;
+
+  if(from) {
+    to->len = from->len;
+    if(to->len)
+      to->data = g_memdup(from->data, to->len);
+  }
+}
+
+
+/* 8.2 Common Structures */
+/* 8.2.1 Login Info block */
+
+
+void mwLoginInfo_put(struct mwPutBuffer *b, const struct mwLoginInfo *login) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(login != NULL);
+
+  mwString_put(b, login->login_id);
+  guint16_put(b, login->type);
+  mwString_put(b, login->user_id);
+  mwString_put(b, login->user_name);
+  mwString_put(b, login->community);
+  gboolean_put(b, login->full);
+
+  if(login->full) {
+    mwString_put(b, login->desc);
+    guint32_put(b, login->ip_addr);
+    mwString_put(b, login->server_id);
+  }
+}
+
+
+void mwLoginInfo_get(struct mwGetBuffer *b, struct mwLoginInfo *login) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(login != NULL);
+
+  if(b->error) return;
+
+  mwString_get(b, &login->login_id);
+  guint16_get(b, &login->type);
+  mwString_get(b, &login->user_id);
+  mwString_get(b, &login->user_name);
+  mwString_get(b, &login->community);
+  gboolean_get(b, &login->full);
+  
+  if(login->full) {
+    mwString_get(b, &login->desc);
+    guint32_get(b, &login->ip_addr);
+    mwString_get(b, &login->server_id);
+  }
+}
+
+
+void mwLoginInfo_clear(struct mwLoginInfo *login) {
+  if(! login) return;
+
+  g_free(login->login_id);
+  g_free(login->user_id);
+  g_free(login->user_name);
+  g_free(login->community);
+  g_free(login->desc);
+  g_free(login->server_id);
+
+  memset(login, 0x00, sizeof(struct mwLoginInfo));
+}
+
+
+void mwLoginInfo_clone(struct mwLoginInfo *to,
+		       const struct mwLoginInfo *from) {
+
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  to->login_id= g_strdup(from->login_id);
+  to->type = from->type;
+  to->user_id = g_strdup(from->user_id);
+  to->user_name = g_strdup(from->user_name);
+  to->community = g_strdup(from->community);
+
+  if( (to->full = from->full) ) {
+    to->desc = g_strdup(from->desc);
+    to->ip_addr = from->ip_addr;
+    to->server_id = g_strdup(from->server_id);
+  }
+}
+
+
+/* 8.2.2 Private Info Block */
+
+
+void mwUserItem_put(struct mwPutBuffer *b, const struct mwUserItem *user) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(user != NULL);
+
+  gboolean_put(b, user->full);
+  mwString_put(b, user->id);
+  mwString_put(b, user->community);
+  
+  if(user->full)
+    mwString_put(b, user->name);
+}
+
+
+void mwUserItem_get(struct mwGetBuffer *b, struct mwUserItem *user) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(user != NULL);
+
+  if(b->error) return;
+
+  gboolean_get(b, &user->full);
+  mwString_get(b, &user->id);
+  mwString_get(b, &user->community);
+
+  if(user->full)
+    mwString_get(b, &user->name);
+}
+
+
+void mwUserItem_clear(struct mwUserItem *user) {
+  if(! user) return;
+
+  g_free(user->id);
+  g_free(user->community);
+  g_free(user->name);
+
+  memset(user, 0x00, sizeof(struct mwUserItem));
+}
+
+
+void mwUserItem_clone(struct mwUserItem *to,
+		      const struct mwUserItem *from) {
+
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  to->full = from->full;
+  to->id = g_strdup(from->id);
+  to->community = g_strdup(from->community);
+  to->name = (to->full)? g_strdup(from->name): NULL;
+}
+
+
+void mwPrivacyInfo_put(struct mwPutBuffer *b,
+		       const struct mwPrivacyInfo *info) {
+  guint32 c;
+
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(info != NULL);
+
+  gboolean_put(b, info->deny);
+  guint32_put(b, info->count);
+
+  for(c = info->count; c--; ) mwUserItem_put(b, info->users + c);
+}
+
+
+void mwPrivacyInfo_get(struct mwGetBuffer *b, struct mwPrivacyInfo *info) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(info != NULL);
+
+  if(b->error) return;
+
+  gboolean_get(b, &info->deny);
+  guint32_get(b, &info->count);
+
+  if(info->count) {
+    guint32 c = info->count;
+    info->users = g_new0(struct mwUserItem, c);
+    while(c--) mwUserItem_get(b, info->users + c);
+  }
+}
+
+
+void mwPrivacyInfo_clone(struct mwPrivacyInfo *to,
+			 const struct mwPrivacyInfo *from) {
+
+  guint32 c;
+
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  to->deny = from->deny;
+  c = to->count = from->count;
+
+  to->users = g_new0(struct mwUserItem, c);
+  while(c--) mwUserItem_clone(to->users+c, from->users+c);
+}
+
+
+void mwPrivacyInfo_clear(struct mwPrivacyInfo *info) {
+  struct mwUserItem *u;
+  guint32 c;
+
+  g_return_if_fail(info != NULL);
+
+  u = info->users;
+  c = info->count;
+
+  while(c--) mwUserItem_clear(u + c);
+  g_free(u);
+
+  info->count = 0;
+  info->users = NULL;
+}
+
+
+/* 8.2.3 User Status Block */
+
+
+void mwUserStatus_put(struct mwPutBuffer *b,
+		      const struct mwUserStatus *stat) {
+
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(stat != NULL);
+
+  guint16_put(b, stat->status);
+  guint32_put(b, stat->time);
+  mwString_put(b, stat->desc);
+}
+
+
+void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(stat != NULL);
+
+  if(b->error) return;
+
+  guint16_get(b, &stat->status);
+  guint32_get(b, &stat->time);
+  mwString_get(b, &stat->desc);
+}
+
+
+void mwUserStatus_clear(struct mwUserStatus *stat) {
+  if(! stat) return;
+  g_free(stat->desc);
+  memset(stat, 0x00, sizeof(struct mwUserStatus));
+}
+
+
+void mwUserStatus_clone(struct mwUserStatus *to,
+			const struct mwUserStatus *from) {
+
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  to->status = from->status;
+  to->time = from->time;
+  to->desc = g_strdup(from->desc);
+}
+
+
+/* 8.2.4 ID Block */
+
+
+void mwIdBlock_put(struct mwPutBuffer *b, const struct mwIdBlock *id) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(id != NULL);
+
+  mwString_put(b, id->user);
+  mwString_put(b, id->community);
+}
+
+
+void mwIdBlock_get(struct mwGetBuffer *b, struct mwIdBlock *id) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(id != NULL);
+
+  if(b->error) return;
+
+  mwString_get(b, &id->user);
+  mwString_get(b, &id->community);
+}
+
+
+void mwIdBlock_clear(struct mwIdBlock *id) {
+  if(! id) return;
+
+  g_free(id->user);
+  id->user = NULL;
+
+  g_free(id->community);
+  id->community = NULL;
+}
+
+
+void mwIdBlock_clone(struct mwIdBlock *to, const struct mwIdBlock *from) {
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  to->user = g_strdup(from->user);
+  to->community = g_strdup(from->community);
+}
+
+
+guint mwIdBlock_hash(const struct mwIdBlock *idb) {
+  return (idb)? g_str_hash(idb->user): 0;
+}
+
+
+gboolean mwIdBlock_equal(const struct mwIdBlock *a,
+			 const struct mwIdBlock *b) {
+
+  g_return_val_if_fail(a != NULL, FALSE);
+  g_return_val_if_fail(b != NULL, FALSE);
+
+  return ( mw_streq(a->user, b->user) &&
+	   mw_streq(a->community, b->community) );
+}
+
+
+/* 8.2.5 Encryption Block */
+
+/** @todo I think this can be put into cipher */
+
+void mwEncryptItem_put(struct mwPutBuffer *b,
+		       const struct mwEncryptItem *ei) {
+
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(ei != NULL);
+  
+  guint16_put(b, ei->id);
+  mwOpaque_put(b, &ei->info);
+
+}
+
+
+void mwEncryptItem_get(struct mwGetBuffer *b, struct mwEncryptItem *ei) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(ei != NULL);
+
+  if(b->error) return;
+
+  guint16_get(b, &ei->id);
+  mwOpaque_get(b, &ei->info);
+}
+
+
+void mwEncryptItem_clear(struct mwEncryptItem *ei) {
+  if(! ei) return;
+  ei->id = 0x0000;
+  mwOpaque_clear(&ei->info);
+}
+
+
+/* 8.4.2.1 Awareness ID Block */
+
+
+/** @todo move this into srvc_aware */
+
+void mwAwareIdBlock_put(struct mwPutBuffer *b,
+			const struct mwAwareIdBlock *idb) {
+
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(idb != NULL);
+
+  guint16_put(b, idb->type);
+  mwString_put(b, idb->user);
+  mwString_put(b, idb->community);
+}
+
+
+void mwAwareIdBlock_get(struct mwGetBuffer *b, struct mwAwareIdBlock *idb) {
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(idb != NULL);
+
+  if(b->error) return;
+
+  guint16_get(b, &idb->type);
+  mwString_get(b, &idb->user);
+  mwString_get(b, &idb->community);
+}
+
+
+void mwAwareIdBlock_clone(struct mwAwareIdBlock *to,
+			  const struct mwAwareIdBlock *from) {
+
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  to->type = from->type;
+  to->user = g_strdup(from->user);
+  to->community = g_strdup(from->community);
+}
+
+
+void mwAwareIdBlock_clear(struct mwAwareIdBlock *idb) {
+  if(! idb) return;
+  g_free(idb->user);
+  g_free(idb->community);
+  memset(idb, 0x00, sizeof(struct mwAwareIdBlock));
+}
+
+
+guint mwAwareIdBlock_hash(const struct mwAwareIdBlock *a) {
+  return (a)? g_str_hash(a->user): 0;
+}
+
+
+gboolean mwAwareIdBlock_equal(const struct mwAwareIdBlock *a,
+			      const struct mwAwareIdBlock *b) {
+
+  g_return_val_if_fail(a != NULL, FALSE);
+  g_return_val_if_fail(b != NULL, FALSE);
+  
+  return ( (a->type == b->type) &&
+	   mw_streq(a->user, b->user) &&
+	   mw_streq(a->community, b->community) );
+}
+
+
+/* 8.4.2.4 Snapshot */
+
+void mwAwareSnapshot_get(struct mwGetBuffer *b, struct mwAwareSnapshot *idb) {
+  guint32 junk;
+  char *empty = NULL;
+
+  g_return_if_fail(b != NULL);
+  g_return_if_fail(idb != NULL);
+
+  guint32_get(b, &junk);
+  mwAwareIdBlock_get(b, &idb->id);
+  mwString_get(b, &idb->group);
+  gboolean_get(b, &idb->online);
+
+  g_free(empty);
+
+  if(idb->online) {
+    mwString_get(b, &idb->alt_id);
+    mwUserStatus_get(b, &idb->status);
+    mwString_get(b, &idb->name);
+  }
+}
+
+
+void mwAwareSnapshot_clone(struct mwAwareSnapshot *to,
+			   const struct mwAwareSnapshot *from) {
+
+  g_return_if_fail(to != NULL);
+  g_return_if_fail(from != NULL);
+
+  mwAwareIdBlock_clone(&to->id, &from->id);
+  if( (to->online = from->online) ) {
+    to->alt_id = g_strdup(from->alt_id);
+    mwUserStatus_clone(&to->status, &from->status);
+    to->name = g_strdup(from->name);
+    to->group = g_strdup(from->group);
+  }
+}
+
+
+void mwAwareSnapshot_clear(struct mwAwareSnapshot *idb) {
+  if(! idb) return;
+  mwAwareIdBlock_clear(&idb->id);
+  mwUserStatus_clear(&idb->status);
+  g_free(idb->alt_id);
+  g_free(idb->name);
+  g_free(idb->group);
+  memset(idb, 0x00, sizeof(struct mwAwareSnapshot));
+}
+
+
+const char *mwLoginType_getName(enum mwLoginType type) {
+  switch(type) {
+  case mwLogin_LIB:
+    return "Lotus Binary Library";
+
+  case mwLogin_JAVA_WEB:
+    return "Lotus Java Client Applet";
+
+  case mwLogin_BINARY:
+    return "Lotus Sametime";
+
+  case mwLogin_JAVA_APP:
+    return "Lotus Java Client Application";
+
+  case mwLogin_NOTES_6_5:
+    return "Lotus Notes Client 6.5.2+";
+
+  case mwLogin_NOTES_7_0:
+    return "Lotus Notes Client 7";
+
+  case mwLogin_ICT:
+    return "IBM Community Tools (ICT)";
+
+  case mwLogin_NOTESBUDDY:
+  case mwLogin_NOTESBUDDY_4_15:
+    return "Alphaworks NotesBuddy";
+
+  case mwLogin_SANITY:
+    return "Sanity";
+
+  case mwLogin_ST_PERL:
+    return "ST-Send-Message";
+
+  case mwLogin_PMR_ALERT:
+    return "PMR Alert";
+
+  case mwLogin_TRILLIAN:
+  case mwLogin_TRILLIAN_IBM:
+    return "Trillian";
+
+  case mwLogin_MEANWHILE:
+    return "Meanwhile";
+
+  case mwLogin_MW_PYTHON:
+    return "Meanwhile Python";
+
+  case mwLogin_MW_GAIM:
+    return "Meanwhile Gaim";
+
+  case mwLogin_MW_ADIUM:
+    return "Meanwhile Adium";
+
+  case mwLogin_MW_KOPETE:
+    return "Meanwhile Kopete";
+
+  default:
+    return NULL;
+  }
+}
+