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

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