Blame src/srvc_place.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
Packit 16808d
#include <stdio.h>
Packit 16808d
#include <stdlib.h>
Packit 16808d
Packit 16808d
#include "mw_channel.h"
Packit 16808d
#include "mw_common.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_place.h"
Packit 16808d
#include "mw_util.h"
Packit 16808d
Packit 16808d
Packit 16808d
#define PROTOCOL_TYPE  0x00
Packit 16808d
#define PROTOCOL_VER   0x05
Packit 16808d
Packit 16808d
Packit 16808d
enum incoming_msg {
Packit 16808d
  msg_in_JOIN_RESPONSE  = 0x0000,  /* ? */
Packit 16808d
  msg_in_INFO           = 0x0002,
Packit 16808d
  msg_in_MESSAGE        = 0x0004,
Packit 16808d
  msg_in_SECTION        = 0x0014,  /* see in_section_subtype */
Packit 16808d
  msg_in_UNKNOWNa       = 0x0015,
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
enum in_section_subtype {
Packit 16808d
  msg_in_SECTION_LIST  = 0x0000,  /* list of section members */
Packit 16808d
  msg_in_SECTION_PEER  = 0x0001,  /* see in_section_peer_subtye */
Packit 16808d
  msg_in_SECTION_PART  = 0x0003,
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
enum in_section_peer_subtype {
Packit 16808d
  msg_in_SECTION_PEER_JOIN        = 0x0000,
Packit 16808d
  msg_in_SECTION_PEER_PART        = 0x0001,  /* after msg_in_SECTION_PART */
Packit 16808d
  msg_in_SECTION_PEER_CLEAR_ATTR  = 0x0003,
Packit 16808d
  msg_in_SECTION_PEER_SET_ATTR    = 0x0004,
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
enum outgoing_msg {
Packit 16808d
  msg_out_JOIN_PLACE  = 0x0000,  /* ? */
Packit 16808d
  msg_out_PEER_INFO   = 0x0002,  /* ? */
Packit 16808d
  msg_out_MESSAGE     = 0x0003,
Packit 16808d
  msg_out_OLD_INVITE  = 0x0005,  /* old-style conf. invitation */
Packit 16808d
  msg_out_SET_ATTR    = 0x000a,
Packit 16808d
  msg_out_CLEAR_ATTR  = 0x000b,
Packit 16808d
  msg_out_SECTION     = 0x0014,  /* see out_section_subtype */
Packit 16808d
  msg_out_UNKNOWNb    = 0x001e,  /* ? maybe enter stage ? */
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
enum out_section_subtype {
Packit 16808d
  msg_out_SECTION_LIST  = 0x0002,  /* req list of members */
Packit 16808d
  msg_out_SECTION_PART  = 0x0003,
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
/*
Packit 16808d
  : allocate section
Packit 16808d
  : state = NEW
Packit 16808d
Packit 16808d
  : create channel
Packit 16808d
  : state = PENDING
Packit 16808d
Packit 16808d
  : channel accepted
Packit 16808d
  : msg_out_JOIN_PLACE  (maybe create?)
Packit 16808d
  : state = JOINING
Packit 16808d
Packit 16808d
  : msg_in_JOIN_RESPONSE (contains our place member ID and section ID)
Packit 16808d
  : msg_in_INFO (for place, not peer)
Packit 16808d
  : state = JOINED
Packit 16808d
Packit 16808d
  : msg_out_SECTION_LIST (asking for all sections) (optional)
Packit 16808d
  : msg_in_SECTION_LIST (listing all sections, as requested above)
Packit 16808d
Packit 16808d
  : msg_out_PEER_INFO (with our place member ID) (optional)
Packit 16808d
  : msg_in_INFO (peer info as requested above)
Packit 16808d
Packit 16808d
  : msg_out_SECTION_LIST (with our section ID) (sorta optional)
Packit 16808d
  : msg_in_SECTION_LIST (section listing as requested above)
Packit 16808d
Packit 16808d
  : msg_out_UNKNOWNb
Packit 16808d
  : msg_in_SECTION_PEER_JOINED (empty, with our place member ID)
Packit 16808d
  : state = OPEN
Packit 16808d
Packit 16808d
  : stuff... (invites, joins, parts, messages, attr)
Packit 16808d
Packit 16808d
  : state = CLOSING
Packit 16808d
  : msg_out_SECTION_PART
Packit 16808d
  : destroy channel
Packit 16808d
  : deallocate section
Packit 16808d
*/
Packit 16808d
Packit 16808d
Packit 16808d
struct mwServicePlace {
Packit 16808d
  struct mwService service;
Packit 16808d
  struct mwPlaceHandler *handler;
Packit 16808d
  GList *places;
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
enum mwPlaceState {
Packit 16808d
  mwPlace_NEW,
Packit 16808d
  mwPlace_PENDING,
Packit 16808d
  mwPlace_JOINING,
Packit 16808d
  mwPlace_JOINED,
Packit 16808d
  mwPlace_OPEN,
Packit 16808d
  mwPlace_CLOSING,
Packit 16808d
  mwPlace_ERROR,
Packit 16808d
  mwPlace_UNKNOWN,
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
struct mwPlace {
Packit 16808d
  struct mwServicePlace *service;
Packit 16808d
Packit 16808d
  enum mwPlaceState state;
Packit 16808d
  struct mwChannel *channel;
Packit 16808d
Packit 16808d
  char *name;
Packit 16808d
  char *title;
Packit 16808d
  GHashTable *members;  /* mapping of member ID: place_member */
Packit 16808d
  guint32 our_id;       /* our member ID */
Packit 16808d
  guint32 section;      /* the section we're using */
Packit 16808d
Packit 16808d
  guint32 requests;     /* counter for requests */
Packit 16808d
Packit 16808d
  struct mw_datum client_data;
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
struct place_member {
Packit 16808d
  guint32 place_id;
Packit 16808d
  guint16 member_type;
Packit 16808d
  struct mwIdBlock idb;
Packit 16808d
  char *login_id;
Packit 16808d
  char *name;
Packit 16808d
  guint16 login_type;
Packit 16808d
  guint32 unknown_a;
Packit 16808d
  guint32 unknown_b;
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
#define GET_MEMBER(place, id) \
Packit 16808d
  (g_hash_table_lookup(place->members, GUINT_TO_POINTER(id)))
Packit 16808d
Packit 16808d
Packit 16808d
#define PUT_MEMBER(place, member) \
Packit 16808d
  (g_hash_table_insert(place->members, \
Packit 16808d
                       GUINT_TO_POINTER(member->place_id), member))
Packit 16808d
Packit 16808d
Packit 16808d
#define REMOVE_MEMBER_ID(place, id) \
Packit 16808d
  (g_hash_table_remove(place->members, GUINT_TO_POINTER(id)))
Packit 16808d
Packit 16808d
Packit 16808d
#define REMOVE_MEMBER(place, member) \
Packit 16808d
  REMOVE_MEMBER_ID(place, member->place_id)
Packit 16808d
Packit 16808d
Packit 16808d
static void member_free(struct place_member *p) {
Packit 16808d
  mwIdBlock_clear(&p->idb);
Packit 16808d
  g_free(p->login_id);
Packit 16808d
  g_free(p->name);
Packit 16808d
  g_free(p);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
__attribute__((used))
Packit 16808d
static const struct mwLoginInfo *
Packit 16808d
member_as_login_info(struct place_member *p) {
Packit 16808d
  static struct mwLoginInfo li;
Packit 16808d
  
Packit 16808d
  li.login_id = p->login_id;
Packit 16808d
  li.type = p->login_type;
Packit 16808d
  li.user_id = p->idb.user;
Packit 16808d
  li.user_name = p->name;
Packit 16808d
  li.community = p->idb.community;
Packit 16808d
  li.full = FALSE;
Packit 16808d
Packit 16808d
  return &li;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static const char *place_state_str(enum mwPlaceState s) {
Packit 16808d
  switch(s) {
Packit 16808d
  case mwPlace_NEW:      return "new";
Packit 16808d
  case mwPlace_PENDING:  return "pending";
Packit 16808d
  case mwPlace_JOINING:  return "joining";
Packit 16808d
  case mwPlace_JOINED:   return "joined";
Packit 16808d
  case mwPlace_OPEN:     return "open";
Packit 16808d
  case mwPlace_CLOSING:  return "closing";
Packit 16808d
  case mwPlace_ERROR:    return "error";
Packit 16808d
Packit 16808d
  case mwPlace_UNKNOWN:  /* fall-through */
Packit 16808d
  default:               return "UNKNOWN";
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void place_state(struct mwPlace *place, enum mwPlaceState s) {
Packit 16808d
  g_return_if_fail(place != NULL);
Packit 16808d
  
Packit 16808d
  if(place->state == s) return;
Packit 16808d
Packit 16808d
  place->state = s;
Packit 16808d
  g_message("place %s state: %s", NSTR(place->name), place_state_str(s));
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void place_free(struct mwPlace *place) {
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
Packit 16808d
  if(! place) return;
Packit 16808d
  
Packit 16808d
  srvc = place->service;
Packit 16808d
  g_return_if_fail(srvc != NULL);
Packit 16808d
Packit 16808d
  srvc->places = g_list_remove_all(srvc->places, place);
Packit 16808d
Packit 16808d
  mw_datum_clear(&place->client_data);
Packit 16808d
Packit 16808d
  g_hash_table_destroy(place->members);
Packit 16808d
Packit 16808d
  g_free(place->name);
Packit 16808d
  g_free(place->title);
Packit 16808d
  g_free(place);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_JOIN_RESPONSE(struct mwPlace *place,
Packit 16808d
			      struct mwGetBuffer *b) {
Packit 16808d
  
Packit 16808d
  int ret = 0;
Packit 16808d
  guint32 our_id, section;
Packit 16808d
Packit 16808d
  guint32_get(b, &our_id);
Packit 16808d
  guint32_get(b, &section);
Packit 16808d
Packit 16808d
  place->our_id = our_id;
Packit 16808d
  place->section = section;
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int send_SECTION_LIST(struct mwPlace *place, guint32 section) {
Packit 16808d
  int ret = 0;
Packit 16808d
  struct mwOpaque o = {0, 0};
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  guint16_put(b, msg_out_SECTION_LIST);
Packit 16808d
  guint32_put(b, section);
Packit 16808d
  gboolean_put(b, FALSE);
Packit 16808d
  guint32_put(b, ++place->requests);
Packit 16808d
  mwPutBuffer_finalize(&o, b);
Packit 16808d
Packit 16808d
  ret = mwChannel_send(place->channel, msg_out_SECTION, &o);
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_INFO(struct mwPlace *place,
Packit 16808d
		     struct mwGetBuffer *b) {
Packit 16808d
Packit 16808d
  int ret = 0;
Packit 16808d
  guint32 skip = 0;
Packit 16808d
  guint32 section = 0;
Packit 16808d
Packit 16808d
  guint32_get(b, &skip);
Packit 16808d
  guint32_get(b, &section);
Packit 16808d
  mwGetBuffer_advance(b, skip);
Packit 16808d
Packit 16808d
  if(! section) {
Packit 16808d
    /* this is a place info rather than member info */
Packit 16808d
    if(place->title) g_free(place->title);
Packit 16808d
    mwGetBuffer_advance(b, 2);
Packit 16808d
    mwString_get(b, &place->title);
Packit 16808d
Packit 16808d
    place_state(place, mwPlace_JOINED);
Packit 16808d
    ret = send_SECTION_LIST(place, place->section);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_MESSAGE(struct mwPlace *place,
Packit 16808d
			struct mwGetBuffer *b) {
Packit 16808d
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  guint32 pm_id;
Packit 16808d
  guint32 unkn_a, unkn_b, ign;
Packit 16808d
  struct place_member *pm;
Packit 16808d
  char *msg = NULL;
Packit 16808d
  int ret = 0;
Packit 16808d
Packit 16808d
  srvc = place->service;
Packit 16808d
Packit 16808d
  /* no messages before becoming fully open, please */
Packit 16808d
  g_return_val_if_fail(place->state == mwPlace_OPEN, -1);
Packit 16808d
Packit 16808d
  /* regarding unkn_a and unkn_b:
Packit 16808d
Packit 16808d
     they're probably a section indicator and a message count, I'm
Packit 16808d
     just not sure which is which. Until this implementation supports
Packit 16808d
     place sections in the API, it really doesn't matter. */
Packit 16808d
  
Packit 16808d
  guint32_get(b, &pm_id);
Packit 16808d
  pm = GET_MEMBER(place, pm_id);
Packit 16808d
  g_return_val_if_fail(pm != NULL, -1);
Packit 16808d
Packit 16808d
  guint32_get(b, &unkn_a);
Packit 16808d
  guint32_get(b, &ign;;     /* actually an opaque length */
Packit 16808d
  
Packit 16808d
  if(! ign) return ret;
Packit 16808d
Packit 16808d
  guint32_get(b, &unkn_b);
Packit 16808d
  mwString_get(b, &msg;;
Packit 16808d
Packit 16808d
  if(srvc->handler && srvc->handler->message)
Packit 16808d
    srvc->handler->message(place, &pm->idb, msg);
Packit 16808d
Packit 16808d
  g_free(msg);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void place_opened(struct mwPlace *place) {
Packit 16808d
    struct mwServicePlace *srvc;
Packit 16808d
Packit 16808d
    place_state(place, mwPlace_OPEN);
Packit 16808d
Packit 16808d
    srvc = place->service;
Packit 16808d
    if(srvc->handler && srvc->handler->opened)
Packit 16808d
      srvc->handler->opened(place);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION_PEER_JOIN(struct mwPlace *place,
Packit 16808d
				  struct mwGetBuffer *b) {
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  struct place_member *pm;
Packit 16808d
  guint32 section;
Packit 16808d
  int ret = 0;
Packit 16808d
Packit 16808d
  srvc = place->service;
Packit 16808d
Packit 16808d
  guint32_get(b, &section);
Packit 16808d
  if(! section) {
Packit 16808d
    g_info("SECTION_PEER_JOIN with section 0x00");
Packit 16808d
    return 0;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  mwGetBuffer_advance(b, 4);
Packit 16808d
Packit 16808d
  pm = g_new0(struct place_member, 1);
Packit 16808d
  guint32_get(b, &pm->place_id);
Packit 16808d
  guint16_get(b, &pm->member_type);
Packit 16808d
  mwIdBlock_get(b, &pm->idb);
Packit 16808d
  mwString_get(b, &pm->login_id);
Packit 16808d
  mwString_get(b, &pm->name);
Packit 16808d
  guint16_get(b, &pm->login_type);
Packit 16808d
  guint32_get(b, &pm->unknown_a);
Packit 16808d
  guint32_get(b, &pm->unknown_b);
Packit 16808d
Packit 16808d
  PUT_MEMBER(place, pm);
Packit 16808d
  if(srvc->handler && srvc->handler->peerJoined)
Packit 16808d
    srvc->handler->peerJoined(place, &pm->idb);
Packit 16808d
Packit 16808d
  if(pm->place_id == place->our_id)
Packit 16808d
    place_opened(place);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION_PEER_PART(struct mwPlace *place,
Packit 16808d
				  struct mwGetBuffer *b) {
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  int ret = 0;
Packit 16808d
  guint32 section, id;
Packit 16808d
  struct place_member *pm;
Packit 16808d
Packit 16808d
  srvc = place->service;
Packit 16808d
Packit 16808d
  guint32_get(b, &section);
Packit 16808d
  g_return_val_if_fail(section == place->section, 0);
Packit 16808d
Packit 16808d
  guint32_get(b, &id;;
Packit 16808d
  pm = GET_MEMBER(place, id);
Packit 16808d
Packit 16808d
  /* SECTION_PART may have been called already */
Packit 16808d
  if(! pm) return 0;
Packit 16808d
Packit 16808d
  if(srvc->handler && srvc->handler->peerParted)
Packit 16808d
    srvc->handler->peerParted(place, &pm->idb);
Packit 16808d
Packit 16808d
  REMOVE_MEMBER(place, pm);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION_PEER_CLEAR_ATTR(struct mwPlace *place,
Packit 16808d
					struct mwGetBuffer *b) {
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  int ret = 0;
Packit 16808d
  guint32 id, attr;
Packit 16808d
  struct place_member *pm;
Packit 16808d
  
Packit 16808d
  srvc = place->service;
Packit 16808d
Packit 16808d
  guint32_get(b, &id;;
Packit 16808d
  guint32_get(b, &attr);
Packit 16808d
Packit 16808d
  pm = GET_MEMBER(place, id);
Packit 16808d
  g_return_val_if_fail(pm != NULL, -1);
Packit 16808d
Packit 16808d
  if(srvc->handler && srvc->handler->peerUnsetAttribute)
Packit 16808d
    srvc->handler->peerUnsetAttribute(place, &pm->idb, attr);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION_PEER_SET_ATTR(struct mwPlace *place,
Packit 16808d
				      struct mwGetBuffer *b) {
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  int ret = 0;
Packit 16808d
  guint32 id, attr;
Packit 16808d
  struct mwOpaque o = {0,0};
Packit 16808d
  struct place_member *pm;
Packit 16808d
  
Packit 16808d
  srvc = place->service;
Packit 16808d
Packit 16808d
  guint32_get(b, &id;;
Packit 16808d
  mwGetBuffer_advance(b, 4);
Packit 16808d
  mwOpaque_get(b, &o);
Packit 16808d
  mwGetBuffer_advance(b, 4);
Packit 16808d
  guint32_get(b, &attr);
Packit 16808d
Packit 16808d
  pm = GET_MEMBER(place, id);
Packit 16808d
  g_return_val_if_fail(pm != NULL, -1);
Packit 16808d
Packit 16808d
  if(srvc->handler && srvc->handler->peerSetAttribute)
Packit 16808d
    srvc->handler->peerSetAttribute(place, &pm->idb, attr, &o);
Packit 16808d
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION_PEER(struct mwPlace *place,
Packit 16808d
			      struct mwGetBuffer *b) {
Packit 16808d
  guint16 subtype;
Packit 16808d
  int res;
Packit 16808d
Packit 16808d
  guint16_get(b, &subtype);
Packit 16808d
Packit 16808d
  g_return_val_if_fail(! mwGetBuffer_error(b), -1);
Packit 16808d
Packit 16808d
  switch(subtype) {
Packit 16808d
  case msg_in_SECTION_PEER_JOIN:
Packit 16808d
    res = recv_SECTION_PEER_JOIN(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_SECTION_PEER_PART:
Packit 16808d
    res = recv_SECTION_PEER_PART(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_SECTION_PEER_CLEAR_ATTR:
Packit 16808d
    res = recv_SECTION_PEER_CLEAR_ATTR(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_SECTION_PEER_SET_ATTR:
Packit 16808d
    res = recv_SECTION_PEER_SET_ATTR(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  default:
Packit 16808d
    res = -1;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return res;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION_LIST(struct mwPlace *place,
Packit 16808d
			     struct mwGetBuffer *b) {
Packit 16808d
  int ret = 0;
Packit 16808d
  guint32 sec, count;
Packit 16808d
Packit 16808d
  mwGetBuffer_advance(b, 4);
Packit 16808d
  guint32_get(b, &sec);
Packit 16808d
Packit 16808d
  g_return_val_if_fail(sec == place->section, -1);
Packit 16808d
Packit 16808d
  mwGetBuffer_advance(b, 8);
Packit 16808d
  guint32_get(b, &count);
Packit 16808d
  mwGetBuffer_advance(b, 8);
Packit 16808d
Packit 16808d
  while(count--) {
Packit 16808d
    struct place_member *m;
Packit 16808d
Packit 16808d
    m = g_new0(struct place_member, 1);
Packit 16808d
    mwGetBuffer_advance(b, 4);
Packit 16808d
    guint32_get(b, &m->place_id);
Packit 16808d
    guint16_get(b, &m->member_type);
Packit 16808d
    mwIdBlock_get(b, &m->idb);
Packit 16808d
    mwString_get(b, &m->login_id);
Packit 16808d
    mwString_get(b, &m->name);
Packit 16808d
    guint16_get(b, &m->login_type);
Packit 16808d
    guint32_get(b, &m->unknown_a);
Packit 16808d
    guint32_get(b, &m->unknown_b);
Packit 16808d
Packit 16808d
    PUT_MEMBER(place, m);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  if(place->state != mwPlace_OPEN)
Packit 16808d
    place_opened(place);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION_PART(struct mwPlace *place,
Packit 16808d
			     struct mwGetBuffer *b) {
Packit 16808d
  /* look up user in place
Packit 16808d
     remove user from place
Packit 16808d
     trigger event */
Packit 16808d
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  guint32 pm_id;
Packit 16808d
  struct place_member *pm;
Packit 16808d
Packit 16808d
  srvc = place->service;
Packit 16808d
Packit 16808d
  guint32_get(b, &pm_id);
Packit 16808d
  pm = GET_MEMBER(place, pm_id);
Packit 16808d
Packit 16808d
  /* SECTION_PEER_PART may have been called already */
Packit 16808d
  if(! pm) return 0;
Packit 16808d
Packit 16808d
  if(srvc->handler && srvc->handler->peerParted)
Packit 16808d
    srvc->handler->peerParted(place, &pm->idb);
Packit 16808d
Packit 16808d
  REMOVE_MEMBER(place, pm);
Packit 16808d
Packit 16808d
  return 0;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_SECTION(struct mwPlace *place, struct mwGetBuffer *b) {
Packit 16808d
  guint16 subtype;
Packit 16808d
  int res;
Packit 16808d
Packit 16808d
  guint16_get(b, &subtype);
Packit 16808d
Packit 16808d
  g_return_val_if_fail(! mwGetBuffer_error(b), -1);
Packit 16808d
Packit 16808d
  switch(subtype) {
Packit 16808d
  case msg_in_SECTION_LIST:
Packit 16808d
    res = recv_SECTION_LIST(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_SECTION_PEER:
Packit 16808d
    res = recv_SECTION_PEER(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_SECTION_PART:
Packit 16808d
    res = recv_SECTION_PART(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  default:
Packit 16808d
    res = -1;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return res;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int recv_UNKNOWNa(struct mwPlace *place, struct mwGetBuffer *b) {
Packit 16808d
  int res = 0;
Packit 16808d
Packit 16808d
  if(place->state == mwPlace_JOINING) {
Packit 16808d
    ;
Packit 16808d
    /* place_state(place, mwPlace_JOINED);
Packit 16808d
       res = send_SECTION_LIST(place, place->section); */
Packit 16808d
  
Packit 16808d
  } else if(place->state == mwPlace_JOINED) {
Packit 16808d
    ;
Packit 16808d
    /* if(GET_MEMBER(place, place->our_id))
Packit 16808d
       place_opened(place); */
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return res;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void recv(struct mwService *service, struct mwChannel *chan,
Packit 16808d
		 guint16 type, struct mwOpaque *data) {
Packit 16808d
Packit 16808d
  struct mwPlace *place;
Packit 16808d
  struct mwGetBuffer *b;
Packit 16808d
  int res = 0;
Packit 16808d
Packit 16808d
  place = mwChannel_getServiceData(chan);
Packit 16808d
  g_return_if_fail(place != NULL);
Packit 16808d
Packit 16808d
  b = mwGetBuffer_wrap(data);
Packit 16808d
  switch(type) {
Packit 16808d
  case msg_in_JOIN_RESPONSE:
Packit 16808d
    res = recv_JOIN_RESPONSE(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_INFO:
Packit 16808d
    res = recv_INFO(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_MESSAGE:
Packit 16808d
    res = recv_MESSAGE(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_SECTION:
Packit 16808d
    res = recv_SECTION(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case msg_in_UNKNOWNa:
Packit 16808d
    res = recv_UNKNOWNa(place, b);
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  default:
Packit 16808d
    mw_mailme_opaque(data, "Received unknown message type 0x%x on place %s",
Packit 16808d
		     type, NSTR(place->name));
Packit 16808d
  }
Packit 16808d
Packit 16808d
  if(res) {
Packit 16808d
    mw_mailme_opaque(data, "Troubling parsing message type 0x0%x on place %s",
Packit 16808d
		     type, NSTR(place->name));
Packit 16808d
  }
Packit 16808d
Packit 16808d
  mwGetBuffer_free(b);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void stop(struct mwServicePlace *srvc) {
Packit 16808d
  while(srvc->places)
Packit 16808d
    mwPlace_destroy(srvc->places->data, ERR_SUCCESS);
Packit 16808d
Packit 16808d
  mwService_stopped(MW_SERVICE(srvc));
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int send_JOIN_PLACE(struct mwPlace *place) {
Packit 16808d
  struct mwOpaque o = {0, 0};
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
  int ret;
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  gboolean_put(b, FALSE);
Packit 16808d
  guint16_put(b, 0x01);
Packit 16808d
  guint16_put(b, 0x02); /* 0x01 */
Packit 16808d
  guint16_put(b, 0x01); /* 0x00 */
Packit 16808d
Packit 16808d
  mwPutBuffer_finalize(&o, b);
Packit 16808d
Packit 16808d
  ret = mwChannel_send(place->channel, msg_out_JOIN_PLACE, &o);
Packit 16808d
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
Packit 16808d
  if(ret) {
Packit 16808d
    place_state(place, mwPlace_ERROR);
Packit 16808d
  } else {
Packit 16808d
    place_state(place, mwPlace_JOINING);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void recv_channelAccept(struct mwService *service,
Packit 16808d
			       struct mwChannel *chan,
Packit 16808d
			       struct mwMsgChannelAccept *msg) {
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  struct mwPlace *place;
Packit 16808d
  int res;
Packit 16808d
Packit 16808d
  srvc = (struct mwServicePlace *) service;
Packit 16808d
  g_return_if_fail(srvc != NULL);
Packit 16808d
Packit 16808d
  place = mwChannel_getServiceData(chan);
Packit 16808d
  g_return_if_fail(place != NULL);
Packit 16808d
Packit 16808d
  res = send_JOIN_PLACE(place);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void recv_channelDestroy(struct mwService *service,
Packit 16808d
				struct mwChannel *chan,
Packit 16808d
				struct mwMsgChannelDestroy *msg) {
Packit 16808d
  struct mwServicePlace *srvc;
Packit 16808d
  struct mwPlace *place;
Packit 16808d
Packit 16808d
  srvc = (struct mwServicePlace *) service;
Packit 16808d
  g_return_if_fail(srvc != NULL);
Packit 16808d
Packit 16808d
  place = mwChannel_getServiceData(chan);
Packit 16808d
  g_return_if_fail(place != NULL);
Packit 16808d
Packit 16808d
  place_state(place, mwPlace_ERROR);
Packit 16808d
Packit 16808d
  place->channel = NULL;
Packit 16808d
Packit 16808d
  if(srvc->handler && srvc->handler->closed)
Packit 16808d
    srvc->handler->closed(place, msg->reason);  
Packit 16808d
Packit 16808d
  mwPlace_destroy(place, msg->reason);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void clear(struct mwServicePlace *srvc) {
Packit 16808d
Packit 16808d
  if(srvc->handler && srvc->handler->clear)
Packit 16808d
    srvc->handler->clear(srvc);
Packit 16808d
Packit 16808d
  while(srvc->places)
Packit 16808d
    place_free(srvc->places->data);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static const char *get_name(struct mwService *srvc) {
Packit 16808d
  return "Places Conferencing";
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static const char *get_desc(struct mwService *srvc) {
Packit 16808d
  return "Barebones conferencing via Places";
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
struct mwServicePlace *
Packit 16808d
mwServicePlace_new(struct mwSession *session,
Packit 16808d
		   struct mwPlaceHandler *handler) {
Packit 16808d
Packit 16808d
  struct mwServicePlace *srvc_place;
Packit 16808d
  struct mwService *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_place = g_new0(struct mwServicePlace, 1);
Packit 16808d
  srvc_place->handler = handler;
Packit 16808d
Packit 16808d
  srvc = MW_SERVICE(srvc_place);
Packit 16808d
  mwService_init(srvc, session, mwService_PLACE);
Packit 16808d
  srvc->start = NULL;
Packit 16808d
  srvc->stop = (mwService_funcStop) stop;
Packit 16808d
  srvc->recv_create = NULL;
Packit 16808d
  srvc->recv_accept = recv_channelAccept;
Packit 16808d
  srvc->recv_destroy = recv_channelDestroy;
Packit 16808d
  srvc->recv = recv;
Packit 16808d
  srvc->clear = (mwService_funcClear) clear;
Packit 16808d
  srvc->get_name = get_name;
Packit 16808d
  srvc->get_desc = get_desc;
Packit 16808d
Packit 16808d
  return srvc_place;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
struct mwPlaceHandler *
Packit 16808d
mwServicePlace_getHandler(struct mwServicePlace *srvc) {
Packit 16808d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit 16808d
  return srvc->handler;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc) {
Packit 16808d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit 16808d
  return srvc->places;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
struct mwPlace *mwPlace_new(struct mwServicePlace *srvc,
Packit 16808d
			    const char *name, const char *title) {
Packit 16808d
  struct mwPlace *place;
Packit 16808d
Packit 16808d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit 16808d
  
Packit 16808d
  place = g_new0(struct mwPlace, 1);
Packit 16808d
  place->service = srvc;
Packit 16808d
  place->name = g_strdup(name);
Packit 16808d
  place->title = g_strdup(title);
Packit 16808d
  place->state = mwPlace_NEW;
Packit 16808d
Packit 16808d
  place->members = g_hash_table_new_full(g_direct_hash, g_direct_equal,
Packit 16808d
					 NULL, (GDestroyNotify) member_free);
Packit 16808d
Packit 16808d
  srvc->places = g_list_prepend(srvc->places, place);
Packit 16808d
  
Packit 16808d
  return place;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
struct mwServicePlace *mwPlace_getService(struct mwPlace *place) {
Packit 16808d
  g_return_val_if_fail(place != NULL, NULL);
Packit 16808d
  return place->service;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static char *place_generate_name(const char *user) {
Packit 16808d
  guint a, b;
Packit 16808d
  char *ret;
Packit 16808d
  
Packit 16808d
  user = user? user: "meanwhile";
Packit 16808d
Packit 16808d
  srand(clock() + rand());
Packit 16808d
  a = ((rand() & 0xff) << 8) | (rand() & 0xff);
Packit 16808d
  b = time(NULL);
Packit 16808d
Packit 16808d
  ret = g_strdup_printf("%s(%08x,%04x)", user, b, a);
Packit 16808d
  g_debug("generated random conference name: '%s'", ret);
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
const char *mwPlace_getName(struct mwPlace *place) {
Packit 16808d
  g_return_val_if_fail(place != NULL, NULL);
Packit 16808d
Packit 16808d
  if(! place->name) {
Packit 16808d
    struct mwSession *session;
Packit 16808d
    struct mwLoginInfo *li;
Packit 16808d
Packit 16808d
    session = mwService_getSession(MW_SERVICE(place->service));
Packit 16808d
    li = mwSession_getLoginInfo(session);
Packit 16808d
Packit 16808d
    place->name = place_generate_name(li? li->user_id: NULL);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return place->name;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static char *place_generate_title(const char *user) {
Packit 16808d
  char *ret;
Packit 16808d
  
Packit 16808d
  user = user? user: "Meanwhile";
Packit 16808d
  ret = g_strdup_printf("%s's Conference", user);
Packit 16808d
  g_debug("generated conference title: %s", ret);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
const char *mwPlace_getTitle(struct mwPlace *place) {
Packit 16808d
  g_return_val_if_fail(place != NULL, NULL);
Packit 16808d
Packit 16808d
  if(! place->title) {
Packit 16808d
    struct mwSession *session;
Packit 16808d
    struct mwLoginInfo *li;
Packit 16808d
Packit 16808d
    session = mwService_getSession(MW_SERVICE(place->service));
Packit 16808d
    li = mwSession_getLoginInfo(session);
Packit 16808d
Packit 16808d
    place->title = place_generate_title(li? li->user_name: NULL);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return place->title;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int mwPlace_open(struct mwPlace *p) {
Packit 16808d
  struct mwSession *session;
Packit 16808d
  struct mwChannelSet *cs;
Packit 16808d
  struct mwChannel *chan;
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
  int ret;
Packit 16808d
Packit 16808d
  g_return_val_if_fail(p != NULL, -1);
Packit 16808d
  g_return_val_if_fail(p->service != NULL, -1);
Packit 16808d
Packit 16808d
  session = mwService_getSession(MW_SERVICE(p->service));
Packit 16808d
  g_return_val_if_fail(session != NULL, -1);
Packit 16808d
Packit 16808d
  cs = mwSession_getChannels(session);
Packit 16808d
  g_return_val_if_fail(cs != NULL, -1);
Packit 16808d
Packit 16808d
  chan = mwChannel_newOutgoing(cs);
Packit 16808d
  mwChannel_setService(chan, MW_SERVICE(p->service));
Packit 16808d
  mwChannel_setProtoType(chan, PROTOCOL_TYPE);
Packit 16808d
  mwChannel_setProtoVer(chan, PROTOCOL_VER);
Packit 16808d
Packit 16808d
  mwChannel_populateSupportedCipherInstances(chan);
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  mwString_put(b, mwPlace_getName(p));
Packit 16808d
  mwString_put(b, mwPlace_getTitle(p));
Packit 16808d
  guint32_put(b, 0x00); /* ? */
Packit 16808d
Packit 16808d
  mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
Packit 16808d
Packit 16808d
  ret = mwChannel_create(chan);
Packit 16808d
  if(ret) {
Packit 16808d
    place_state(p, mwPlace_ERROR);
Packit 16808d
  } else {
Packit 16808d
    place_state(p, mwPlace_PENDING);
Packit 16808d
    p->channel = chan;
Packit 16808d
    mwChannel_setServiceData(chan, p, NULL);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int mwPlace_destroy(struct mwPlace *p, guint32 code) {
Packit 16808d
  int ret = 0;
Packit 16808d
Packit 16808d
  place_state(p, mwPlace_CLOSING);
Packit 16808d
Packit 16808d
  if(p->channel) {
Packit 16808d
    ret = mwChannel_destroy(p->channel, code, NULL);
Packit 16808d
    p->channel = NULL;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  place_free(p);
Packit 16808d
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
GList *mwPlace_getMembers(struct mwPlace *place) {
Packit 16808d
  GList *l, *ll;
Packit 16808d
Packit 16808d
  g_return_val_if_fail(place != NULL, NULL);
Packit 16808d
  g_return_val_if_fail(place->members != NULL, NULL);
Packit 16808d
Packit 16808d
  ll = map_collect_values(place->members);
Packit 16808d
  for(l = ll; l; l = l->next) {
Packit 16808d
    struct place_member *pm = l->data;
Packit 16808d
    l->data = &pm->idb;
Packit 16808d
    g_info("collected member %u: %s, %s", pm->place_id,
Packit 16808d
	   NSTR(pm->idb.user), NSTR(pm->idb.community));
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return ll;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int mwPlace_sendText(struct mwPlace *place, const char *msg) {
Packit 16808d
  struct mwOpaque o = {0,0};
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
  int ret;
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  guint32_put(b, 0x01);  /* probably a message type */
Packit 16808d
  mwString_put(b, msg);
Packit 16808d
  mwPutBuffer_finalize(&o, b);
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  guint32_put(b, place->section);
Packit 16808d
  mwOpaque_put(b, &o);
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
  mwPutBuffer_finalize(&o, b);
Packit 16808d
Packit 16808d
  ret = mwChannel_send(place->channel, msg_out_MESSAGE, &o);
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int mwPlace_legacyInvite(struct mwPlace *place,
Packit 16808d
			 struct mwIdBlock *idb,
Packit 16808d
			 const char *message) {
Packit 16808d
Packit 16808d
  struct mwOpaque o = {0,0};
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
  int ret;
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  mwIdBlock_put(b, idb);
Packit 16808d
  mwString_put(b, idb->user);
Packit 16808d
  mwString_put(b, idb->user);
Packit 16808d
  mwString_put(b, message);
Packit 16808d
  gboolean_put(b, FALSE);
Packit 16808d
  mwPutBuffer_finalize(&o, b);
Packit 16808d
Packit 16808d
  ret = mwChannel_send(place->channel, msg_out_OLD_INVITE, &o);
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib,
Packit 16808d
			 struct mwOpaque *data) {
Packit 16808d
Packit 16808d
  struct mwOpaque o = {0,0};
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
  int ret;
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  guint32_put(b, place->our_id);
Packit 16808d
  guint32_put(b, 0x00);
Packit 16808d
  guint32_put(b, attrib);
Packit 16808d
  mwOpaque_put(b, data);
Packit 16808d
  
Packit 16808d
  ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o);
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib) {
Packit 16808d
  struct mwOpaque o = {0,0};
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
  int ret;
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  guint32_put(b, place->our_id);
Packit 16808d
  guint32_put(b, attrib);
Packit 16808d
  
Packit 16808d
  ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o);
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
  return ret;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
void mwPlace_setClientData(struct mwPlace *place,
Packit 16808d
			   gpointer data, GDestroyNotify clear) {
Packit 16808d
Packit 16808d
  g_return_if_fail(place != NULL);
Packit 16808d
  mw_datum_set(&place->client_data, data, clear);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
gpointer mwPlace_getClientData(struct mwPlace *place) {
Packit 16808d
  g_return_val_if_fail(place != NULL, NULL);
Packit 16808d
  return mw_datum_get(&place->client_data);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
void mwPlace_removeClientData(struct mwPlace *place) {
Packit 16808d
  g_return_if_fail(place != NULL);
Packit 16808d
  mw_datum_clear(&place->client_data);
Packit 16808d
}