|
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 |
#include <glib/ghash.h>
|
|
Packit |
16808d |
#include <glib/glist.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 |
|