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