Blame src/srvc_conf.c

Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Meanwhile - Unofficial Lotus Sametime Community Client Library
Packit Service 37472d
  Copyright (C) 2004  Christopher (siege) O'Brien
Packit Service 37472d
  
Packit Service 37472d
  This library is free software; you can redistribute it and/or
Packit Service 37472d
  modify it under the terms of the GNU Library General Public
Packit Service 37472d
  License as published by the Free Software Foundation; either
Packit Service 37472d
  version 2 of the License, or (at your option) any later version.
Packit Service 37472d
  
Packit Service 37472d
  This library is distributed in the hope that it will be useful,
Packit Service 37472d
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 37472d
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 37472d
  Library General Public License for more details.
Packit Service 37472d
  
Packit Service 37472d
  You should have received a copy of the GNU Library General Public
Packit Service 37472d
  License along with this library; if not, write to the Free
Packit Service 37472d
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service 37472d
*/
Packit Service 37472d
Packit Service 37472d
#include <glib.h>
Packit Service 37472d
Packit Service 37472d
#include <stdio.h>
Packit Service 37472d
#include <stdlib.h>
Packit Service 37472d
#include <string.h>
Packit Service 37472d
#include <time.h>
Packit Service 37472d
Packit Service 37472d
#include "mw_channel.h"
Packit Service 37472d
#include "mw_debug.h"
Packit Service 37472d
#include "mw_error.h"
Packit Service 37472d
#include "mw_message.h"
Packit Service 37472d
#include "mw_service.h"
Packit Service 37472d
#include "mw_session.h"
Packit Service 37472d
#include "mw_srvc_conf.h"
Packit Service 37472d
#include "mw_util.h"
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* This thing needs a re-write. More than anything else, I need to
Packit Service 37472d
   re-examine the conferencing service protocol from more modern
Packit Service 37472d
   clients */
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define PROTOCOL_TYPE   0x00000010
Packit Service 37472d
#define PROTOCOL_VER    0x00000002
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** @see mwMsgChannelSend::type
Packit Service 37472d
    @see recv */
Packit Service 37472d
enum msg_type {
Packit Service 37472d
  msg_WELCOME  = 0x0000,  /**< welcome message */
Packit Service 37472d
  msg_INVITE   = 0x0001,  /**< outgoing invitation */
Packit Service 37472d
  msg_JOIN     = 0x0002,  /**< someone joined */
Packit Service 37472d
  msg_PART     = 0x0003,  /**< someone left */
Packit Service 37472d
  msg_MESSAGE  = 0x0004,  /**< conference message */
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** the conferencing service */
Packit Service 37472d
struct mwServiceConference {
Packit Service 37472d
  struct mwService service;
Packit Service 37472d
Packit Service 37472d
  /** call-back handler for this service */
Packit Service 37472d
  struct mwConferenceHandler *handler;
Packit Service 37472d
Packit Service 37472d
  /** collection of conferences in this service */
Packit Service 37472d
  GList *confs;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** a conference and its members */
Packit Service 37472d
struct mwConference {
Packit Service 37472d
  enum mwConferenceState state;   /**< state of the conference */
Packit Service 37472d
  struct mwServiceConference *service;  /**< owning service */
Packit Service 37472d
  struct mwChannel *channel;      /**< conference's channel */
Packit Service 37472d
Packit Service 37472d
  char *name;   /**< server identifier for the conference */
Packit Service 37472d
  char *title;  /**< topic for the conference */
Packit Service 37472d
Packit Service 37472d
  struct mwLoginInfo owner;  /**< person who created this conference */
Packit Service 37472d
  GHashTable *members;       /**< mapping guint16:mwLoginInfo */
Packit Service 37472d
  struct mw_datum client_data;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define MEMBER_FIND(conf, id) \
Packit Service 37472d
  g_hash_table_lookup(conf->members, GUINT_TO_POINTER((guint) id))
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define MEMBER_ADD(conf, id, member) \
Packit Service 37472d
  g_hash_table_insert(conf->members, GUINT_TO_POINTER((guint) id), member)
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define MEMBER_REM(conf, id) \
Packit Service 37472d
  g_hash_table_remove(conf->members, GUINT_TO_POINTER((guint) id));
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** clear and free a login info block */
Packit Service 37472d
static void login_free(struct mwLoginInfo *li) {
Packit Service 37472d
  mwLoginInfo_clear(li);
Packit Service 37472d
  g_free(li);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** generates a random conference name built around a user name */
Packit Service 37472d
static char *conf_generate_name(const char *user) {
Packit Service 37472d
  guint a, b;
Packit Service 37472d
  char *ret;
Packit Service 37472d
  
Packit Service 37472d
  user = user? user: "";
Packit Service 37472d
Packit Service 37472d
  srand(clock() + rand());
Packit Service 37472d
  a = ((rand() & 0xff) << 8) | (rand() & 0xff);
Packit Service 37472d
  b = time(NULL);
Packit Service 37472d
Packit Service 37472d
  ret = g_strdup_printf("%s(%08x,%04x)", user, b, a);
Packit Service 37472d
  g_debug("generated random conference name: '%s'", ret);
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mwConference *conf_new(struct mwServiceConference *srvc) {
Packit Service 37472d
Packit Service 37472d
  struct mwConference *conf;
Packit Service 37472d
  struct mwSession *session;
Packit Service 37472d
  const char *user;
Packit Service 37472d
Packit Service 37472d
  conf = g_new0(struct mwConference, 1);
Packit Service 37472d
  conf->state = mwConference_NEW;
Packit Service 37472d
  conf->service = srvc;
Packit Service 37472d
  conf->members = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
Packit Service 37472d
					(GDestroyNotify) login_free);
Packit Service 37472d
Packit Service 37472d
  session = mwService_getSession(MW_SERVICE(srvc));
Packit Service 37472d
  user = mwSession_getProperty(session, mwSession_AUTH_USER_ID);
Packit Service 37472d
Packit Service 37472d
  srvc->confs = g_list_prepend(srvc->confs, conf);
Packit Service 37472d
Packit Service 37472d
  return conf;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** clean and free a conference structure */
Packit Service 37472d
static void conf_free(struct mwConference *conf) {
Packit Service 37472d
  struct mwServiceConference *srvc;
Packit Service 37472d
Packit Service 37472d
  /* this shouldn't ever happen, but just to be sure */
Packit Service 37472d
  g_return_if_fail(conf != NULL);
Packit Service 37472d
  
Packit Service 37472d
  srvc = conf->service;
Packit Service 37472d
Packit Service 37472d
  if(conf->members)
Packit Service 37472d
    g_hash_table_destroy(conf->members);
Packit Service 37472d
Packit Service 37472d
  srvc->confs = g_list_remove_all(srvc->confs, conf);
Packit Service 37472d
Packit Service 37472d
  mw_datum_clear(&conf->client_data);
Packit Service 37472d
  
Packit Service 37472d
  g_free(conf->name);
Packit Service 37472d
  g_free(conf->title);
Packit Service 37472d
  g_free(conf);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mwConference *conf_find(struct mwServiceConference *srvc,
Packit Service 37472d
				      struct mwChannel *chan) {
Packit Service 37472d
  GList *l;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit Service 37472d
  g_return_val_if_fail(chan != NULL, NULL);
Packit Service 37472d
  
Packit Service 37472d
  for(l = srvc->confs; l; l = l->next) {
Packit Service 37472d
    struct mwConference *conf = l->data;
Packit Service 37472d
    if(conf->channel == chan) return conf;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return NULL;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *conf_state_str(enum mwConferenceState state) {
Packit Service 37472d
  switch(state) {
Packit Service 37472d
  case mwConference_NEW:      return "new";
Packit Service 37472d
  case mwConference_PENDING:  return "pending";
Packit Service 37472d
  case mwConference_INVITED:  return "invited";
Packit Service 37472d
  case mwConference_OPEN:     return "open";
Packit Service 37472d
  case mwConference_CLOSING:  return "closing";
Packit Service 37472d
  case mwConference_ERROR:    return "error";
Packit Service 37472d
Packit Service 37472d
  case mwConference_UNKNOWN:  /* fall through */
Packit Service 37472d
  default:                    return "UNKNOWN";
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void conf_state(struct mwConference *conf,
Packit Service 37472d
		       enum mwConferenceState state) {
Packit Service 37472d
  g_return_if_fail(conf != NULL);
Packit Service 37472d
Packit Service 37472d
  if(conf->state == state) return;
Packit Service 37472d
Packit Service 37472d
  conf->state = state;
Packit Service 37472d
  g_message("conference %s state: %s",
Packit Service 37472d
	    NSTR(conf->name), conf_state_str(state));
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelCreate(struct mwService *srvc,
Packit Service 37472d
			       struct mwChannel *chan,
Packit Service 37472d
			       struct mwMsgChannelCreate *msg) {
Packit Service 37472d
Packit Service 37472d
  /* - this is how we really receive invitations
Packit Service 37472d
     - create a conference and associate it with the channel
Packit Service 37472d
     - obtain the invite data from the msg addtl info
Packit Service 37472d
     - mark the conference as INVITED
Packit Service 37472d
     - trigger the got_invite event
Packit Service 37472d
  */
Packit Service 37472d
Packit Service 37472d
  struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc;
Packit Service 37472d
  struct mwConference *conf;
Packit Service 37472d
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
Packit Service 37472d
  char *invite = NULL;
Packit Service 37472d
  guint tmp;
Packit Service 37472d
Packit Service 37472d
  conf = conf_new(srvc_conf);
Packit Service 37472d
  conf->channel = chan;
Packit Service 37472d
Packit Service 37472d
  b = mwGetBuffer_wrap(&msg->addtl);
Packit Service 37472d
Packit Service 37472d
  guint32_get(b, &tmp);
Packit Service 37472d
  mwString_get(b, &conf->name);
Packit Service 37472d
  mwString_get(b, &conf->title);
Packit Service 37472d
  guint32_get(b, &tmp);
Packit Service 37472d
  mwLoginInfo_get(b, &conf->owner);
Packit Service 37472d
  guint32_get(b, &tmp);
Packit Service 37472d
  mwString_get(b, &invite);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) {
Packit Service 37472d
    g_warning("failure parsing addtl for conference invite");
Packit Service 37472d
    mwConference_destroy(conf, ERR_FAILURE, NULL);
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    struct mwConferenceHandler *h = srvc_conf->handler;
Packit Service 37472d
    conf_state(conf, mwConference_INVITED);
Packit Service 37472d
    if(h->on_invited)
Packit Service 37472d
      h->on_invited(conf, &conf->owner, invite);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwGetBuffer_free(b);
Packit Service 37472d
  g_free(invite);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelAccept(struct mwService *srvc,
Packit Service 37472d
			       struct mwChannel *chan,
Packit Service 37472d
			       struct mwMsgChannelAccept *msg) {
Packit Service 37472d
Packit Service 37472d
  ;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelDestroy(struct mwService *srvc,
Packit Service 37472d
				struct mwChannel *chan,
Packit Service 37472d
				struct mwMsgChannelDestroy *msg) {
Packit Service 37472d
Packit Service 37472d
  /* - find conference from channel
Packit Service 37472d
     - trigger got_closed
Packit Service 37472d
     - remove conference, dealloc
Packit Service 37472d
  */
Packit Service 37472d
Packit Service 37472d
  struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc;
Packit Service 37472d
  struct mwConference *conf = conf_find(srvc_conf, chan);
Packit Service 37472d
  struct mwConferenceHandler *h = srvc_conf->handler;
Packit Service 37472d
Packit Service 37472d
  /* if there's no such conference, then I guess there's nothing to worry
Packit Service 37472d
     about. Except of course for the fact that we should never receive a
Packit Service 37472d
     channel destroy for a conference that doesn't exist. */
Packit Service 37472d
  if(! conf) return;
Packit Service 37472d
Packit Service 37472d
  conf->channel = NULL;
Packit Service 37472d
Packit Service 37472d
  conf_state(conf, msg->reason? mwConference_ERROR: mwConference_CLOSING);
Packit Service 37472d
Packit Service 37472d
  if(h->conf_closed)
Packit Service 37472d
    h->conf_closed(conf, msg->reason);
Packit Service 37472d
Packit Service 37472d
  mwConference_destroy(conf, ERR_SUCCESS, NULL);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void WELCOME_recv(struct mwServiceConference *srvc,
Packit Service 37472d
			 struct mwConference *conf,
Packit Service 37472d
			 struct mwGetBuffer *b) {
Packit Service 37472d
Packit Service 37472d
  struct mwConferenceHandler *h;
Packit Service 37472d
  guint16 tmp16;
Packit Service 37472d
  guint32 tmp32;
Packit Service 37472d
  guint32 count;
Packit Service 37472d
  GList *l = NULL;
Packit Service 37472d
Packit Service 37472d
  /* re-read name and title */
Packit Service 37472d
  g_free(conf->name);
Packit Service 37472d
  g_free(conf->title);
Packit Service 37472d
  conf->name = NULL;
Packit Service 37472d
  conf->title = NULL;
Packit Service 37472d
  mwString_get(b, &conf->name);
Packit Service 37472d
  mwString_get(b, &conf->title);
Packit Service 37472d
Packit Service 37472d
  /* some numbers we don't care about, then a count of members */
Packit Service 37472d
  guint16_get(b, &tmp16);
Packit Service 37472d
  guint32_get(b, &tmp32);
Packit Service 37472d
  guint32_get(b, &count);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) {
Packit Service 37472d
    g_warning("error parsing welcome message for conference");
Packit Service 37472d
    mwConference_destroy(conf, ERR_FAILURE, NULL);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  while(count--) {
Packit Service 37472d
    guint16 member_id;
Packit Service 37472d
    struct mwLoginInfo *member = g_new0(struct mwLoginInfo, 1);
Packit Service 37472d
Packit Service 37472d
    guint16_get(b, &member_id);
Packit Service 37472d
    mwLoginInfo_get(b, member);
Packit Service 37472d
Packit Service 37472d
    if(mwGetBuffer_error(b)) {
Packit Service 37472d
      login_free(member);
Packit Service 37472d
      break;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    MEMBER_ADD(conf, member_id, member);
Packit Service 37472d
    l = g_list_append(l, member);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  conf_state(conf, mwConference_OPEN);
Packit Service 37472d
Packit Service 37472d
  h = srvc->handler;
Packit Service 37472d
  if(h->conf_opened)
Packit Service 37472d
    h->conf_opened(conf, l);
Packit Service 37472d
Packit Service 37472d
  /* get rid of the GList, but not its contents */
Packit Service 37472d
  g_list_free(l);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void JOIN_recv(struct mwServiceConference *srvc,
Packit Service 37472d
		      struct mwConference *conf,
Packit Service 37472d
		      struct mwGetBuffer *b) {
Packit Service 37472d
Packit Service 37472d
  struct mwConferenceHandler *h;
Packit Service 37472d
  guint16 m_id;
Packit Service 37472d
  struct mwLoginInfo *m;
Packit Service 37472d
  
Packit Service 37472d
  /* for some inane reason, conferences we create will send a join
Packit Service 37472d
     message for ourselves before the welcome message. Since the
Packit Service 37472d
     welcome message will list our ID among those in the channel,
Packit Service 37472d
     we're going to just pretend that these join messages don't
Packit Service 37472d
     exist */
Packit Service 37472d
  if(conf->state == mwConference_PENDING)
Packit Service 37472d
    return;
Packit Service 37472d
Packit Service 37472d
  m = g_new0(struct mwLoginInfo, 1);
Packit Service 37472d
Packit Service 37472d
  guint16_get(b, &m_id);
Packit Service 37472d
  mwLoginInfo_get(b, m);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) {
Packit Service 37472d
    g_warning("failed parsing JOIN message in conference");
Packit Service 37472d
    login_free(m);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  MEMBER_ADD(conf, m_id, m);
Packit Service 37472d
Packit Service 37472d
  h = srvc->handler;
Packit Service 37472d
  if(h->on_peer_joined)
Packit Service 37472d
    h->on_peer_joined(conf, m);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void PART_recv(struct mwServiceConference *srvc,
Packit Service 37472d
		      struct mwConference *conf,
Packit Service 37472d
		      struct mwGetBuffer *b) {
Packit Service 37472d
Packit Service 37472d
  /* - parse who left
Packit Service 37472d
     - look up their membership
Packit Service 37472d
     - remove them from the members list
Packit Service 37472d
     - trigger the event
Packit Service 37472d
  */
Packit Service 37472d
Packit Service 37472d
  struct mwConferenceHandler *h;
Packit Service 37472d
  guint16 id = 0;
Packit Service 37472d
  struct mwLoginInfo *m;
Packit Service 37472d
Packit Service 37472d
  guint16_get(b, &id;;
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) return;
Packit Service 37472d
Packit Service 37472d
  m = MEMBER_FIND(conf, id);
Packit Service 37472d
  if(! m) return;
Packit Service 37472d
Packit Service 37472d
  h = srvc->handler;
Packit Service 37472d
  if(h->on_peer_parted)
Packit Service 37472d
    h->on_peer_parted(conf, m);
Packit Service 37472d
Packit Service 37472d
  MEMBER_REM(conf, id);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void text_recv(struct mwServiceConference *srvc,
Packit Service 37472d
		      struct mwConference *conf,
Packit Service 37472d
		      struct mwLoginInfo *m,
Packit Service 37472d
		      struct mwGetBuffer *b) {
Packit Service 37472d
Packit Service 37472d
  /* this function acts a lot like receiving an IM Text message. The text
Packit Service 37472d
     message contains only a string */
Packit Service 37472d
Packit Service 37472d
  char *text = NULL;
Packit Service 37472d
  struct mwConferenceHandler *h;
Packit Service 37472d
  
Packit Service 37472d
  mwString_get(b, &text);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) {
Packit Service 37472d
    g_warning("failed to parse text message in conference");
Packit Service 37472d
    g_free(text);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  h = srvc->handler;
Packit Service 37472d
  if(text && h->on_text) {
Packit Service 37472d
    h->on_text(conf, m, text);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  g_free(text);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void data_recv(struct mwServiceConference *srvc,
Packit Service 37472d
		      struct mwConference *conf,
Packit Service 37472d
		      struct mwLoginInfo *m,
Packit Service 37472d
		      struct mwGetBuffer *b) {
Packit Service 37472d
Packit Service 37472d
  /* this function acts a lot like receiving an IM Data message. The
Packit Service 37472d
     data message has a type, a subtype, and an opaque. We only
Packit Service 37472d
     support typing notification though. */
Packit Service 37472d
Packit Service 37472d
  /** @todo it's possible that some clients send text in a data
Packit Service 37472d
      message, as we've seen rarely in the IM service. Have to add
Packit Service 37472d
      support for that here */
Packit Service 37472d
Packit Service 37472d
  guint32 type, subtype;
Packit Service 37472d
  struct mwConferenceHandler *h;
Packit Service 37472d
Packit Service 37472d
  guint32_get(b, &type);
Packit Service 37472d
  guint32_get(b, &subtype);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) return;
Packit Service 37472d
Packit Service 37472d
  /* don't know how to deal with any others yet */
Packit Service 37472d
  if(type != 0x01) {
Packit Service 37472d
    g_message("unknown data message type (0x%08x, 0x%08x)", type, subtype);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  h = srvc->handler;
Packit Service 37472d
  if(h->on_typing) {
Packit Service 37472d
    h->on_typing(conf, m, !subtype);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void MESSAGE_recv(struct mwServiceConference *srvc,
Packit Service 37472d
			 struct mwConference *conf,
Packit Service 37472d
			 struct mwGetBuffer *b) {
Packit Service 37472d
Packit Service 37472d
  /* - look up who send the message by their id
Packit Service 37472d
     - trigger the event
Packit Service 37472d
  */
Packit Service 37472d
Packit Service 37472d
  guint16 id;
Packit Service 37472d
  guint32 type;
Packit Service 37472d
  struct mwLoginInfo *m;
Packit Service 37472d
Packit Service 37472d
  /* an empty buffer isn't an error, just ignored */
Packit Service 37472d
  if(! mwGetBuffer_remaining(b)) return;
Packit Service 37472d
Packit Service 37472d
  guint16_get(b, &id;;
Packit Service 37472d
  guint32_get(b, &type); /* reuse type variable */
Packit Service 37472d
  guint32_get(b, &type);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) return;
Packit Service 37472d
Packit Service 37472d
  m = MEMBER_FIND(conf, id);
Packit Service 37472d
  if(! m) {
Packit Service 37472d
    g_warning("received message type 0x%04x from"
Packit Service 37472d
	      " unknown conference member %u", type, id);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  switch(type) {
Packit Service 37472d
  case 0x01:  /* type is text */
Packit Service 37472d
    text_recv(srvc, conf, m, b);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  case 0x02:  /* type is data */
Packit Service 37472d
    data_recv(srvc, conf, m, b);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  default:
Packit Service 37472d
    g_warning("unknown message type 0x%4x received in conference", type);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv(struct mwService *srvc, struct mwChannel *chan,
Packit Service 37472d
		 guint16 type, struct mwOpaque *data) {
Packit Service 37472d
Packit Service 37472d
  struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc;
Packit Service 37472d
  struct mwConference *conf = conf_find(srvc_conf, chan);
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(conf != NULL);
Packit Service 37472d
Packit Service 37472d
  b = mwGetBuffer_wrap(data);
Packit Service 37472d
Packit Service 37472d
  switch(type) {
Packit Service 37472d
  case msg_WELCOME:
Packit Service 37472d
    WELCOME_recv(srvc_conf, conf, b);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  case msg_JOIN:
Packit Service 37472d
    JOIN_recv(srvc_conf, conf, b);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  case msg_PART:
Packit Service 37472d
    PART_recv(srvc_conf, conf, b);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  case msg_MESSAGE:
Packit Service 37472d
    MESSAGE_recv(srvc_conf, conf, b);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  default:
Packit Service 37472d
    ; /* hrm. should log this. TODO */
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void clear(struct mwServiceConference *srvc) {
Packit Service 37472d
  struct mwConferenceHandler *h;
Packit Service 37472d
Packit Service 37472d
  while(srvc->confs)
Packit Service 37472d
    conf_free(srvc->confs->data);
Packit Service 37472d
Packit Service 37472d
  h = srvc->handler;
Packit Service 37472d
  if(h && h->clear)
Packit Service 37472d
    h->clear(srvc);
Packit Service 37472d
  srvc->handler = NULL;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *name(struct mwService *srvc) {
Packit Service 37472d
  return "Basic Conferencing";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *desc(struct mwService *srvc) {
Packit Service 37472d
  return "Multi-user plain-text conferencing";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void start(struct mwService *srvc) {
Packit Service 37472d
  mwService_started(srvc);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void stop(struct mwServiceConference *srvc) {
Packit Service 37472d
  while(srvc->confs)
Packit Service 37472d
    mwConference_destroy(srvc->confs->data, ERR_SUCCESS, NULL);
Packit Service 37472d
Packit Service 37472d
  mwService_stopped(MW_SERVICE(srvc));
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceConference *
Packit Service 37472d
mwServiceConference_new(struct mwSession *session,
Packit Service 37472d
			struct mwConferenceHandler *handler) {
Packit Service 37472d
Packit Service 37472d
  struct mwServiceConference *srvc_conf;
Packit Service 37472d
  struct mwService *srvc;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(session != NULL, NULL);
Packit Service 37472d
  g_return_val_if_fail(handler != NULL, NULL);
Packit Service 37472d
Packit Service 37472d
  srvc_conf = g_new0(struct mwServiceConference, 1);
Packit Service 37472d
  srvc = &srvc_conf->service;
Packit Service 37472d
Packit Service 37472d
  mwService_init(srvc, session, mwService_CONFERENCE);
Packit Service 37472d
  srvc->start = start;
Packit Service 37472d
  srvc->stop = (mwService_funcStop) stop;
Packit Service 37472d
  srvc->recv_create = recv_channelCreate;
Packit Service 37472d
  srvc->recv_accept = recv_channelAccept;
Packit Service 37472d
  srvc->recv_destroy = recv_channelDestroy;
Packit Service 37472d
  srvc->recv = recv;
Packit Service 37472d
  srvc->clear = (mwService_funcClear) clear;
Packit Service 37472d
  srvc->get_name = name;
Packit Service 37472d
  srvc->get_desc = desc;
Packit Service 37472d
Packit Service 37472d
  srvc_conf->handler = handler;
Packit Service 37472d
Packit Service 37472d
  return srvc_conf;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwConference *mwConference_new(struct mwServiceConference *srvc,
Packit Service 37472d
				      const char *title) {
Packit Service 37472d
  struct mwConference *conf;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit Service 37472d
Packit Service 37472d
  conf = conf_new(srvc);
Packit Service 37472d
  conf->title = g_strdup(title);
Packit Service 37472d
Packit Service 37472d
  return conf;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceConference *
Packit Service 37472d
mwConference_getService(struct mwConference *conf) {
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, NULL);
Packit Service 37472d
  return conf->service;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
const char *mwConference_getName(struct mwConference *conf) {
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, NULL);
Packit Service 37472d
  return conf->name;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
const char *mwConference_getTitle(struct mwConference *conf) {
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, NULL);
Packit Service 37472d
  return conf->title;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
GList *mwConference_getMembers(struct mwConference *conf) {
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, NULL);
Packit Service 37472d
  g_return_val_if_fail(conf->members != NULL, NULL);
Packit Service 37472d
Packit Service 37472d
  return map_collect_values(conf->members);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwConference_open(struct mwConference *conf) {
Packit Service 37472d
  struct mwSession *session;
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
  int ret;
Packit Service 37472d
  
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->service != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->state == mwConference_NEW, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->channel == NULL, -1);
Packit Service 37472d
Packit Service 37472d
  session = mwService_getSession(MW_SERVICE(conf->service));
Packit Service 37472d
  g_return_val_if_fail(session != NULL, -1);
Packit Service 37472d
Packit Service 37472d
  if(! conf->name) {
Packit Service 37472d
    char *user = mwSession_getProperty(session, mwSession_AUTH_USER_ID);
Packit Service 37472d
    conf->name = conf_generate_name(user? user: "meanwhile");
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  chan = mwChannel_newOutgoing(mwSession_getChannels(session));
Packit Service 37472d
  mwChannel_setService(chan, MW_SERVICE(conf->service));
Packit Service 37472d
  mwChannel_setProtoType(chan, PROTOCOL_TYPE);
Packit Service 37472d
  mwChannel_setProtoVer(chan, PROTOCOL_VER);
Packit Service 37472d
  
Packit Service 37472d
#if 0
Packit Service 37472d
  /* offer all known ciphers */
Packit Service 37472d
  mwChannel_populateSupportedCipherInstances(chan);
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  mwString_put(b, conf->name);
Packit Service 37472d
  mwString_put(b, conf->title);
Packit Service 37472d
  guint32_put(b, 0x00);
Packit Service 37472d
  mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
Packit Service 37472d
Packit Service 37472d
  ret = mwChannel_create(chan);
Packit Service 37472d
  if(ret) {
Packit Service 37472d
    conf_state(conf, mwConference_ERROR);
Packit Service 37472d
  } else {
Packit Service 37472d
    conf_state(conf, mwConference_PENDING);
Packit Service 37472d
    conf->channel = chan;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwConference_destroy(struct mwConference *conf,
Packit Service 37472d
			 guint32 reason, const char *text) {
Packit Service 37472d
Packit Service 37472d
  struct mwServiceConference *srvc;
Packit Service 37472d
  struct mwOpaque info = { 0, 0 };
Packit Service 37472d
  int ret = 0;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, -1);
Packit Service 37472d
Packit Service 37472d
  srvc = conf->service;
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, -1);
Packit Service 37472d
Packit Service 37472d
  /* remove conference from the service */
Packit Service 37472d
  srvc->confs = g_list_remove_all(srvc->confs, conf);
Packit Service 37472d
Packit Service 37472d
  /* close the channel if applicable */
Packit Service 37472d
  if(conf->channel) {
Packit Service 37472d
    if(text && *text) {
Packit Service 37472d
      info.len = strlen(text);
Packit Service 37472d
      info.data = (guchar *) text;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    ret = mwChannel_destroy(conf->channel, reason, &info;;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  /* free the conference */
Packit Service 37472d
  conf_free(conf);
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwConference_accept(struct mwConference *conf) {
Packit Service 37472d
  /* - if conference is not INVITED, return -1
Packit Service 37472d
     - accept the conference channel
Packit Service 37472d
     - send an empty JOIN message
Packit Service 37472d
  */
Packit Service 37472d
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
  int ret;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->state == mwConference_INVITED, -1);
Packit Service 37472d
Packit Service 37472d
  chan = conf->channel;
Packit Service 37472d
  ret = mwChannel_accept(chan);
Packit Service 37472d
Packit Service 37472d
  if(! ret)
Packit Service 37472d
    ret = mwChannel_sendEncrypted(chan, msg_JOIN, NULL, FALSE);
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwConference_invite(struct mwConference *conf,
Packit Service 37472d
			struct mwIdBlock *who,
Packit Service 37472d
			const char *text) {
Packit Service 37472d
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
  struct mwOpaque o;
Packit Service 37472d
  int ret;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->channel != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(who != NULL, -1);
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
Packit Service 37472d
  mwIdBlock_put(b, who);
Packit Service 37472d
  guint16_put(b, 0x00);
Packit Service 37472d
  guint32_put(b, 0x00);
Packit Service 37472d
  mwString_put(b, text);
Packit Service 37472d
  mwString_put(b, who->user);
Packit Service 37472d
Packit Service 37472d
  mwPutBuffer_finalize(&o, b);
Packit Service 37472d
  ret = mwChannel_sendEncrypted(conf->channel, msg_INVITE, &o, FALSE);
Packit Service 37472d
  mwOpaque_clear(&o);
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwConference_sendText(struct mwConference *conf, const char *text) {
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
  struct mwOpaque o;
Packit Service 37472d
  int ret;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->channel != NULL, -1);
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
Packit Service 37472d
  guint32_put(b, 0x01);
Packit Service 37472d
  mwString_put(b, text);
Packit Service 37472d
Packit Service 37472d
  mwPutBuffer_finalize(&o, b);
Packit Service 37472d
  ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE);
Packit Service 37472d
  mwOpaque_clear(&o);
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwConference_sendTyping(struct mwConference *conf, gboolean typing) {
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
  struct mwOpaque o;
Packit Service 37472d
  int ret;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(conf != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->channel != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(conf->state == mwConference_OPEN, -1);
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
Packit Service 37472d
  guint32_put(b, 0x02);
Packit Service 37472d
  guint32_put(b, 0x01);
Packit Service 37472d
  guint32_put(b, !typing);
Packit Service 37472d
  mwOpaque_put(b, NULL);
Packit Service 37472d
Packit Service 37472d
  mwPutBuffer_finalize(&o, b);
Packit Service 37472d
  ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE);
Packit Service 37472d
  mwOpaque_clear(&o);
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwConference_setClientData(struct mwConference *conference,
Packit Service 37472d
			     gpointer data, GDestroyNotify clear) {
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(conference != NULL);
Packit Service 37472d
  mw_datum_set(&conference->client_data, data, clear);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
gpointer mwConference_getClientData(struct mwConference *conference) {
Packit Service 37472d
  g_return_val_if_fail(conference != NULL, NULL);
Packit Service 37472d
  return mw_datum_get(&conference->client_data);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwConference_removeClientData(struct mwConference *conference) {
Packit Service 37472d
  g_return_if_fail(conference != NULL);
Packit Service 37472d
  mw_datum_clear(&conference->client_data);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwConferenceHandler *
Packit Service 37472d
mwServiceConference_getHandler(struct mwServiceConference *srvc) {
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit Service 37472d
  return srvc->handler;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
GList *mwServiceConference_getConferences(struct mwServiceConference *srvc) {
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit Service 37472d
  return g_list_copy(srvc->confs);
Packit Service 37472d
}
Packit Service 37472d