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