# HG changeset patch # User Ethan Blanton # Date 1137716777 0 # Node ID 481560f824682c895816a4e4c87c216e5fc61db3 # Parent 921e17c06a1dd8e1068d53e4b96e82510b4561c4 [gaim-migrate @ 15310] They tell me these should be gone, sorry. committer: Tailor Script diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/.cvsignore --- a/src/protocols/sametime/meanwhile/.cvsignore Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -*.lo -*.la -Makefile -Makefile.in -.deps -.libs diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/Makefile.am --- a/src/protocols/sametime/meanwhile/Makefile.am Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -SUBDIRS = mpi - -noinst_HEADERS = \ - mw_channel.h \ - mw_cipher.h \ - mw_common.h \ - mw_debug.h \ - mw_error.h \ - mw_message.h \ - mw_service.h \ - mw_session.h \ - mw_srvc_aware.h \ - mw_srvc_conf.h \ - mw_srvc_ft.h \ - mw_srvc_im.h \ - mw_srvc_place.h \ - mw_srvc_resolve.h \ - mw_srvc_store.h \ - mw_st_list.h \ - mw_util.h - - -MEANWHILESOURCES = \ - channel.c \ - cipher.c \ - common.c \ - error.c \ - message.c \ - mw_debug.c \ - mw_util.c \ - service.c \ - session.c \ - srvc_aware.c \ - srvc_conf.c \ - srvc_ft.c \ - srvc_im.c \ - srvc_place.c \ - srvc_store.c \ - srvc_resolve.c \ - st_list.c - -AM_CFLAGS = \ - $(GLIB_CFLAGS) \ - $(DEBUG_CFLAGS) \ - -DG_LOG_DOMAIN=\"meanwhile\" - -I$(top_srcdir)/src - -libmeanwhile_la_SOURCES = $(MEANWHILESOURCES) - -libmeanwhile_la_LIBADD = $(GLIB_LIBS) mpi/libmpi.la - -st = -noinst_LTLIBRARIES = libmeanwhile.la - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/channel.c --- a/src/protocols/sametime/meanwhile/channel.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,961 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include - -#include "mw_channel.h" -#include "mw_cipher.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_util.h" - - -/** @todo reorganize this file, stuff is just strewn about */ - - -struct mwChannel { - - /** session this channel belongs to */ - struct mwSession *session; - - enum mwChannelState state; - - /** creator for incoming channel, target for outgoing channel */ - struct mwLoginInfo user; - - /* similar to data from the CreateCnl message in 8.4.1.7 */ - guint32 reserved; /**< special, unknown meaning */ - guint32 id; /**< channel ID */ - guint32 service; /**< service ID */ - guint32 proto_type; /**< service protocol type */ - guint32 proto_ver; /**< service protocol version */ - guint32 options; /**< channel options */ - - struct mwOpaque addtl_create; - struct mwOpaque addtl_accept; - - /** all those supported ciphers */ - GHashTable *supported; - guint16 offered_policy; /**< @see enum mwEncryptPolicy */ - guint16 policy; /**< @see enum mwEncryptPolicy */ - - /** cipher information determined at channel acceptance */ - struct mwCipherInstance *cipher; - - /** statistics table */ - GHashTable *stats; - - GSList *outgoing_queue; /**< queued outgoing messages */ - GSList *incoming_queue; /**< queued incoming messages */ - - struct mw_datum srvc_data; /**< service-specific data */ -}; - - -struct mwChannelSet { - struct mwSession *session; /**< owning session */ - GHashTable *map; /**< map of all channels, by ID */ - guint32 counter; /**< counter for outgoing ID */ -}; - - -static void flush_channel(struct mwChannel *); - - -static const char *state_str(enum mwChannelState state) { - switch(state) { - case mwChannel_NEW: return "new"; - case mwChannel_INIT: return "initializing"; - case mwChannel_WAIT: return "waiting"; - case mwChannel_OPEN: return "open"; - case mwChannel_DESTROY: return "closing"; - case mwChannel_ERROR: return "error"; - - case mwChannel_UNKNOWN: /* fall through */ - default: return "UNKNOWN"; - } -} - - -static void state(struct mwChannel *chan, enum mwChannelState state, - guint32 err_code) { - - g_return_if_fail(chan != NULL); - - if(chan->state == state) return; - - chan->state = state; - - if(err_code) { - g_message("channel 0x%08x state: %s (0x%08x)", - chan->id, state_str(state), err_code); - } else { - g_message("channel 0x%08x state: %s", chan->id, state_str(state)); - } -} - - -static gpointer get_stat(struct mwChannel *chan, - enum mwChannelStatField field) { - - return g_hash_table_lookup(chan->stats, (gpointer) field); -} - - -static void set_stat(struct mwChannel *chan, enum mwChannelStatField field, - gpointer val) { - - g_hash_table_insert(chan->stats, (gpointer) field, val); -} - - -#define incr_stat(chan, field, incr) \ - set_stat(chan, field, get_stat(chan, field) + incr) - - -#define timestamp_stat(chan, field) \ - set_stat(chan, field, (gpointer) time(NULL)) - - -static void sup_free(gpointer a) { - mwCipherInstance_free(a); -} - - -struct mwCipherInstance *get_supported(struct mwChannel *chan, guint16 id) { - guint32 cid = (guint32) id; - return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid)); -} - - -void put_supported(struct mwChannel *chan, struct mwCipherInstance *ci) { - struct mwCipher *cipher = mwCipherInstance_getCipher(ci); - guint32 cid = (guint32) mwCipher_getType(cipher); - g_hash_table_insert(chan->supported, GUINT_TO_POINTER(cid), ci); -} - - -struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *cs, guint32 id) { - struct mwChannel *chan; - - g_return_val_if_fail(cs != NULL, NULL); - g_return_val_if_fail(cs->session != NULL, NULL); - - chan = g_new0(struct mwChannel, 1); - chan->state = mwChannel_NEW; - chan->session = cs->session; - chan->id = id; - - chan->stats = g_hash_table_new(g_direct_hash, g_direct_equal); - - chan->supported = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, sup_free); - - g_hash_table_insert(cs->map, GUINT_TO_POINTER(id), chan); - - state(chan, mwChannel_WAIT, 0); - - return chan; -} - - -struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *cs) { - guint32 id; - struct mwChannel *chan; - - g_return_val_if_fail(cs != NULL, NULL); - g_return_val_if_fail(cs->map != NULL, NULL); - - /* grab the next id, and try to make sure there isn't already a - channel using it */ - do { - id = ++cs->counter; - } while(g_hash_table_lookup(cs->map, GUINT_TO_POINTER(id))); - - chan = mwChannel_newIncoming(cs, id); - state(chan, mwChannel_INIT, 0); - - return chan; -} - - -guint32 mwChannel_getId(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0); - return chan->id; -} - - -struct mwSession *mwChannel_getSession(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return chan->session; -} - - -guint32 mwChannel_getServiceId(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0); - return chan->service; -} - - -struct mwService *mwChannel_getService(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return mwSession_getService(chan->session, chan->service); -} - - -void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc) { - g_return_if_fail(chan != NULL); - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->service = mwService_getType(srvc); -} - - -gpointer mwChannel_getServiceData(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return mw_datum_get(&chan->srvc_data); -} - - -void mwChannel_setServiceData(struct mwChannel *chan, - gpointer data, GDestroyNotify clean) { - - g_return_if_fail(chan != NULL); - mw_datum_set(&chan->srvc_data, data, clean); -} - - -void mwChannel_removeServiceData(struct mwChannel *chan) { - g_return_if_fail(chan != NULL); - mw_datum_clear(&chan->srvc_data); -} - - -guint32 mwChannel_getProtoType(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->proto_type; -} - - -void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type) { - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->proto_type = proto_type; -} - - -guint32 mwChannel_getProtoVer(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->proto_ver; -} - - -void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver) { - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->proto_ver = proto_ver; -} - - -guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->policy; -} - - -guint32 mwChannel_getOptions(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->options; -} - - -void mwChannel_setOptions(struct mwChannel *chan, guint32 options) { - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->options = options; -} - - -struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return &chan->user; -} - - -struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return &chan->addtl_create; -} - - -struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return &chan->addtl_accept; -} - - -struct mwCipherInstance *mwChannel_getCipherInstance(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return chan->cipher; -} - - -enum mwChannelState mwChannel_getState(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, mwChannel_UNKNOWN); - return chan->state; -} - - -gpointer mwChannel_getStatistic(struct mwChannel *chan, - enum mwChannelStatField stat) { - - g_return_val_if_fail(chan != NULL, 0); - g_return_val_if_fail(chan->stats != NULL, 0); - - return get_stat(chan, stat); -} - - -/* send a channel create message */ -int mwChannel_create(struct mwChannel *chan) { - struct mwMsgChannelCreate *msg; - GList *list, *l; - int ret; - - g_return_val_if_fail(chan != NULL, -1); - g_return_val_if_fail(chan->state == mwChannel_INIT, -1); - g_return_val_if_fail(mwChannel_isOutgoing(chan), -1); - - msg = (struct mwMsgChannelCreate *) - mwMessage_new(mwMessage_CHANNEL_CREATE); - - msg->channel = chan->id; - msg->target.user = g_strdup(chan->user.user_id); - msg->target.community = g_strdup(chan->user.community); - msg->service = chan->service; - msg->proto_type = chan->proto_type; - msg->proto_ver = chan->proto_ver; - msg->options = chan->options; - mwOpaque_clone(&msg->addtl, &chan->addtl_create); - - list = mwChannel_getSupportedCipherInstances(chan); - if(list) { - /* offer what we have */ - for(l = list; l; l = l->next) { - struct mwEncryptItem *ei = mwCipherInstance_offer(l->data); - msg->encrypt.items = g_list_append(msg->encrypt.items, ei); - } - - /* we're easy to get along with */ - chan->offered_policy = mwEncrypt_WHATEVER; - g_list_free(list); - - } else { - /* we apparently don't support anything */ - chan->offered_policy = mwEncrypt_NONE; - } - - msg->encrypt.mode = chan->offered_policy; - msg->encrypt.extra = chan->offered_policy; - - ret = mwSession_send(chan->session, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - state(chan, (ret)? mwChannel_ERROR: mwChannel_WAIT, ret); - - return ret; -} - - -static void channel_open(struct mwChannel *chan) { - state(chan, mwChannel_OPEN, 0); - timestamp_stat(chan, mwChannelStat_OPENED_AT); - flush_channel(chan); -} - - -int mwChannel_accept(struct mwChannel *chan) { - struct mwSession *session; - struct mwMsgChannelAccept *msg; - struct mwCipherInstance *ci; - - int ret; - - g_return_val_if_fail(chan != NULL, -1); - g_return_val_if_fail(mwChannel_isIncoming(chan), -1); - g_return_val_if_fail(chan->state == mwChannel_WAIT, -1); - - session = chan->session; - g_return_val_if_fail(session != NULL, -1); - - msg = (struct mwMsgChannelAccept *) - mwMessage_new(mwMessage_CHANNEL_ACCEPT); - - msg->head.channel = chan->id; - msg->service = chan->service; - msg->proto_type = chan->proto_type; - msg->proto_ver = chan->proto_ver; - mwOpaque_clone(&msg->addtl, &chan->addtl_accept); - - ci = chan->cipher; - - if(! ci) { - /* automatically select a cipher if one hasn't been already */ - - switch(chan->offered_policy) { - case mwEncrypt_NONE: - mwChannel_selectCipherInstance(chan, NULL); - break; - - case mwEncrypt_RC2_40: - ci = get_supported(chan, mwCipher_RC2_40); - mwChannel_selectCipherInstance(chan, ci); - break; - - case mwEncrypt_RC2_128: - ci = get_supported(chan, mwCipher_RC2_128); - mwChannel_selectCipherInstance(chan, ci); - break; - - case mwEncrypt_WHATEVER: - case mwEncrypt_ALL: - default: - { - GList *l, *ll; - - l = mwChannel_getSupportedCipherInstances(chan); - if(l) { - /* nobody selected a cipher, so we'll just pick the last in - the list of available ones */ - for(ll = l; ll->next; ll = ll->next); - ci = ll->data; - g_list_free(l); - - mwChannel_selectCipherInstance(chan, ci); - - } else { - /* this may cause breakage, but there's really nothing else - we can do. They want something we can't provide. If they - don't like it, then they'll error the channel out */ - mwChannel_selectCipherInstance(chan, NULL); - } - } - } - } - - msg->encrypt.mode = chan->policy; /* set in selectCipherInstance */ - msg->encrypt.extra = chan->offered_policy; - - if(chan->cipher) { - msg->encrypt.item = mwCipherInstance_accept(chan->cipher); - } - - ret = mwSession_send(session, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - if(ret) { - state(chan, mwChannel_ERROR, ret); - } else { - channel_open(chan); - } - - return ret; -} - - -static void channel_free(struct mwChannel *chan) { - struct mwSession *s; - struct mwMessage *msg; - GSList *l; - - /* maybe no warning in the future */ - g_return_if_fail(chan != NULL); - - s = chan->session; - - mwLoginInfo_clear(&chan->user); - mwOpaque_clear(&chan->addtl_create); - mwOpaque_clear(&chan->addtl_accept); - - if(chan->supported) { - g_hash_table_destroy(chan->supported); - chan->supported = NULL; - } - - if(chan->stats) { - g_hash_table_destroy(chan->stats); - chan->stats = NULL; - } - - mwCipherInstance_free(chan->cipher); - - /* clean up the outgoing queue */ - for(l = chan->outgoing_queue; l; l = l->next) { - msg = (struct mwMessage *) l->data; - l->data = NULL; - mwMessage_free(msg); - } - g_slist_free(chan->outgoing_queue); - - /* clean up the incoming queue */ - for(l = chan->incoming_queue; l; l = l->next) { - msg = (struct mwMessage *) l->data; - l->data = NULL; - mwMessage_free(msg); - } - g_slist_free(chan->incoming_queue); - - g_free(chan); -} - - -int mwChannel_destroy(struct mwChannel *chan, - guint32 reason, struct mwOpaque *info) { - - struct mwMsgChannelDestroy *msg; - struct mwSession *session; - struct mwChannelSet *cs; - int ret; - - /* may make this not a warning in the future */ - g_return_val_if_fail(chan != NULL, 0); - - state(chan, reason? mwChannel_ERROR: mwChannel_DESTROY, reason); - - session = chan->session; - g_return_val_if_fail(session != NULL, -1); - - cs = mwSession_getChannels(session); - g_return_val_if_fail(cs != NULL, -1); - - /* compose the message */ - msg = (struct mwMsgChannelDestroy *) - mwMessage_new(mwMessage_CHANNEL_DESTROY); - msg->head.channel = chan->id; - msg->reason = reason; - if(info) mwOpaque_clone(&msg->data, info); - - /* remove the channel from the channel set */ - g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); - - /* send the message */ - ret = mwSession_send(session, (struct mwMessage *) msg); - mwMessage_free(MW_MESSAGE(msg)); - - return ret; -} - - -static void queue_outgoing(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - g_info("queue_outgoing, channel 0x%08x", chan->id); - chan->outgoing_queue = g_slist_append(chan->outgoing_queue, msg); -} - - -static int channel_send(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - int ret = 0; - - /* if the channel is open, send and free the message. Otherwise, - queue the message to be sent once the channel is finally - opened */ - - if(chan->state == mwChannel_OPEN) { - ret = mwSession_send(chan->session, (struct mwMessage *) msg); - mwMessage_free(MW_MESSAGE(msg)); - - } else { - queue_outgoing(chan, msg); - } - - return ret; -} - - -int mwChannel_sendEncrypted(struct mwChannel *chan, - guint32 type, struct mwOpaque *data, - gboolean encrypt) { - - struct mwMsgChannelSend *msg; - - g_return_val_if_fail(chan != NULL, -1); - - msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND); - msg->head.channel = chan->id; - msg->type = type; - - mwOpaque_clone(&msg->data, data); - - if(encrypt && chan->cipher) { - msg->head.options = mwMessageOption_ENCRYPT; - mwCipherInstance_encrypt(chan->cipher, &msg->data); - } - - return channel_send(chan, msg); -} - - -int mwChannel_send(struct mwChannel *chan, guint32 type, - struct mwOpaque *data) { - - return mwChannel_sendEncrypted(chan, type, data, TRUE); -} - - -static void queue_incoming(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - /* we clone the message, because session_process will clear it once - we return */ - - struct mwMsgChannelSend *m = g_new0(struct mwMsgChannelSend, 1); - m->head.type = msg->head.type; - m->head.options = msg->head.options; - m->head.channel = msg->head.channel; - mwOpaque_clone(&m->head.attribs, &msg->head.attribs); - - m->type = msg->type; - mwOpaque_clone(&m->data, &msg->data); - - g_info("queue_incoming, channel 0x%08x", chan->id); - chan->incoming_queue = g_slist_append(chan->incoming_queue, m); -} - - -static void channel_recv(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - struct mwService *srvc; - srvc = mwChannel_getService(chan); - - incr_stat(chan, mwChannelStat_MSG_RECV, 1); - - if(msg->head.options & mwMessageOption_ENCRYPT) { - struct mwOpaque data = { 0, 0 }; - mwOpaque_clone(&data, &msg->data); - - mwCipherInstance_decrypt(chan->cipher, &data); - mwService_recv(srvc, chan, msg->type, &data); - mwOpaque_clear(&data); - - } else { - mwService_recv(srvc, chan, msg->type, &msg->data); - } -} - - -static void flush_channel(struct mwChannel *chan) { - GSList *l; - - for(l = chan->incoming_queue; l; l = l->next) { - struct mwMsgChannelSend *msg = (struct mwMsgChannelSend *) l->data; - l->data = NULL; - - channel_recv(chan, msg); - mwMessage_free(MW_MESSAGE(msg)); - } - g_slist_free(chan->incoming_queue); - chan->incoming_queue = NULL; - - for(l = chan->outgoing_queue; l; l = l->next) { - struct mwMessage *msg = (struct mwMessage *) l->data; - l->data = NULL; - - mwSession_send(chan->session, msg); - mwMessage_free(msg); - } - g_slist_free(chan->outgoing_queue); - chan->outgoing_queue = NULL; -} - - -void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg) { - if(chan->state == mwChannel_OPEN) { - channel_recv(chan, msg); - - } else { - queue_incoming(chan, msg); - } -} - - -struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan) { - g_return_val_if_fail(cs != NULL, NULL); - g_return_val_if_fail(cs->map != NULL, NULL); - return g_hash_table_lookup(cs->map, GUINT_TO_POINTER(chan)); -} - - -void mwChannelSet_free(struct mwChannelSet *cs) { - if(! cs) return; - if(cs->map) g_hash_table_destroy(cs->map); - g_free(cs); -} - - -struct mwChannelSet *mwChannelSet_new(struct mwSession *s) { - struct mwChannelSet *cs = g_new0(struct mwChannelSet, 1); - cs->session = s; - - /* for some reason, g_int_hash/g_int_equal cause a SIGSEGV */ - cs->map = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) channel_free); - return cs; -} - - -void mwChannel_recvCreate(struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - struct mwSession *session; - GList *list; - struct mwService *srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(chan->id == msg->channel); - - session = chan->session; - g_return_if_fail(session != NULL); - - if(mwChannel_isOutgoing(chan)) { - g_warning("channel 0x%08x not an incoming channel", chan->id); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - chan->offered_policy = msg->encrypt.mode; - g_message("channel offered with encrypt policy 0x%04x", chan->policy); - - for(list = msg->encrypt.items; list; list = list->next) { - struct mwEncryptItem *ei = list->data; - struct mwCipher *cipher; - struct mwCipherInstance *ci; - - g_message("channel offered cipher id 0x%04x", ei->id); - cipher = mwSession_getCipher(session, ei->id); - if(! cipher) { - g_message("no such cipher found in session"); - continue; - } - - ci = mwCipher_newInstance(cipher, chan); - mwCipherInstance_offered(ci, ei); - mwChannel_addSupportedCipherInstance(chan, ci); - } - - mwLoginInfo_clone(&chan->user, &msg->creator); - chan->service = msg->service; - chan->proto_type = msg->proto_type; - chan->proto_ver = msg->proto_ver; - - srvc = mwSession_getService(session, msg->service); - if(srvc) { - mwService_recvCreate(srvc, chan, msg); - - } else { - mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); - } -} - - -void mwChannel_recvAccept(struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - struct mwService *srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(chan->id == msg->head.channel); - - if(mwChannel_isIncoming(chan)) { - g_warning("channel 0x%08x not an outgoing channel", chan->id); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - if(chan->state != mwChannel_WAIT) { - g_warning("channel 0x%08x state not WAIT: %s", - chan->id, state_str(chan->state)); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - mwLoginInfo_clone(&chan->user, &msg->acceptor); - - srvc = mwSession_getService(chan->session, chan->service); - if(! srvc) { - g_warning("no service: 0x%08x", chan->service); - mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); - return; - } - - chan->policy = msg->encrypt.mode; - g_message("channel accepted with encrypt policy 0x%04x", chan->policy); - - if(! msg->encrypt.mode || ! msg->encrypt.item) { - /* no mode or no item means no encryption */ - mwChannel_selectCipherInstance(chan, NULL); - - } else { - guint16 cid = msg->encrypt.item->id; - struct mwCipherInstance *ci = get_supported(chan, cid); - - if(! ci) { - g_warning("not an offered cipher: 0x%04x", cid); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - mwCipherInstance_accepted(ci, msg->encrypt.item); - mwChannel_selectCipherInstance(chan, ci); - } - - /* mark it as open for the service */ - state(chan, mwChannel_OPEN, 0); - - /* let the service know */ - mwService_recvAccept(srvc, chan, msg); - - /* flush it if the service didn't just immediately close it */ - if(mwChannel_isState(chan, mwChannel_OPEN)) { - channel_open(chan); - } -} - - -void mwChannel_recvDestroy(struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - struct mwChannelSet *cs; - struct mwService *srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(chan->id == msg->head.channel); - - state(chan, msg->reason? mwChannel_ERROR: mwChannel_DESTROY, msg->reason); - - srvc = mwChannel_getService(chan); - if(srvc) mwService_recvDestroy(srvc, chan, msg); - - cs = mwSession_getChannels(chan->session); - g_return_if_fail(cs != NULL); - g_return_if_fail(cs->map != NULL); - - g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); -} - - -void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan) { - struct mwSession *session; - GList *list; - - g_return_if_fail(chan != NULL); - - session = chan->session; - g_return_if_fail(session != NULL); - - for(list = mwSession_getCiphers(session); list; list = list->next) { - struct mwCipherInstance *ci = mwCipher_newInstance(list->data, chan); - if(! ci) continue; - put_supported(chan, ci); - } -} - - -void mwChannel_addSupportedCipherInstance(struct mwChannel *chan, - struct mwCipherInstance *ci) { - g_return_if_fail(chan != NULL); - g_message("channel 0x%08x added cipher %s", chan->id, - NSTR(mwCipher_getName(mwCipherInstance_getCipher(ci)))); - put_supported(chan, ci); -} - - -static void collect(gpointer a, gpointer b, gpointer c) { - GList **list = c; - *list = g_list_append(*list, b); -} - - -GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan) { - GList *list = NULL; - - g_return_val_if_fail(chan != NULL, NULL); - g_hash_table_foreach(chan->supported, collect, &list); - - return list; -} - - -void mwChannel_selectCipherInstance(struct mwChannel *chan, - struct mwCipherInstance *ci) { - struct mwCipher *c; - - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->supported != NULL); - - chan->cipher = ci; - if(ci) { - guint cid; - - c = mwCipherInstance_getCipher(ci); - cid = mwCipher_getType(c); - - g_hash_table_steal(chan->supported, GUINT_TO_POINTER(cid)); - - switch(mwCipher_getType(c)) { - case mwCipher_RC2_40: - chan->policy = mwEncrypt_RC2_40; - break; - - case mwCipher_RC2_128: - chan->policy = mwEncrypt_RC2_128; - break; - - default: - /* unsure if this is bad */ - chan->policy = mwEncrypt_WHATEVER; - } - - g_message("channel 0x%08x selected cipher %s", - chan->id, NSTR(mwCipher_getName(c))); - - } else { - - chan->policy = mwEncrypt_NONE; - g_message("channel 0x%08x selected no cipher", chan->id); - } - - g_hash_table_destroy(chan->supported); - chan->supported = NULL; -} - - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/cipher.c --- a/src/protocols/sametime/meanwhile/cipher.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,968 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#include "mpi/mpi.h" - -#include "mw_channel.h" -#include "mw_cipher.h" -#include "mw_debug.h" -#include "mw_session.h" - - -struct mwMpi { - mp_int i; -}; - - -/** From RFC2268 */ -static guchar PT[] = { - 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, - 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, - 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, - 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, - 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, - 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, - 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, - 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, - 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, - 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, - 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, - 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, - 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, - 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, - 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, - 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, - 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, - 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, - 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, - 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, - 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, - 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, - 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, - 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, - 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, - 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, - 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, - 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, - 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, - 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, - 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, - 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD -}; - - -/** prime number used in DH exchange */ -static guchar dh_prime[] = { - 0xCF, 0x84, 0xAF, 0xCE, 0x86, 0xDD, 0xFA, 0x52, - 0x7F, 0x13, 0x6D, 0x10, 0x35, 0x75, 0x28, 0xEE, - 0xFB, 0xA0, 0xAF, 0xEF, 0x80, 0x8F, 0x29, 0x17, - 0x4E, 0x3B, 0x6A, 0x9E, 0x97, 0x00, 0x01, 0x71, - 0x7C, 0x8F, 0x10, 0x6C, 0x41, 0xC1, 0x61, 0xA6, - 0xCE, 0x91, 0x05, 0x7B, 0x34, 0xDA, 0x62, 0xCB, - 0xB8, 0x7B, 0xFD, 0xC1, 0xB3, 0x5C, 0x1B, 0x91, - 0x0F, 0xEA, 0x72, 0x24, 0x9D, 0x56, 0x6B, 0x9F -}; - - -/** base used in DH exchange */ -#define DH_BASE 3 - - -struct mwMpi *mwMpi_new() { - struct mwMpi *i; - i = g_new0(struct mwMpi, 1); - mp_init(&i->i); - return i; -} - - -void mwMpi_free(struct mwMpi *i) { - if(! i) return; - mp_clear(&i->i); - g_free(i); -} - - -static void mwInitDHPrime(mp_int *i) { - mp_init(i); - mp_read_unsigned_bin(i, dh_prime, 64); -} - - -void mwMpi_setDHPrime(struct mwMpi *i) { - g_return_if_fail(i != NULL); - mp_read_unsigned_bin(&i->i, dh_prime, 64); -} - - -static void mwInitDHBase(mp_int *i) { - mp_init(i); - mp_set_int(i, DH_BASE); -} - - -void mwMpi_setDHBase(struct mwMpi *i) { - g_return_if_fail(i != NULL); - mp_set_int(&i->i, DH_BASE); -} - - -static void mp_set_rand(mp_int *i, guint bits) { - size_t len, l; - guchar *buf; - - l = len = (bits / 8) + 1; - buf = g_malloc(len); - - srand(clock()); - while(l--) buf[l] = rand() & 0xff; - - buf[0] &= (0xff >> (8 - (bits % 8))); - - mp_read_unsigned_bin(i, buf, len); - g_free(buf); -} - - -void mwMpi_rand(struct mwMpi *i, guint bits) { - g_return_if_fail(i != NULL); - mp_set_rand(&i->i, bits); -} - - -static void mwDHRandKeypair(mp_int *private, mp_int *public) { - mp_int prime, base; - - mwInitDHPrime(&prime); - mwInitDHBase(&base); - - mp_set_rand(private, 512); - mp_exptmod(&base, private, &prime, public); - - mp_clear(&prime); - mp_clear(&base); -} - - -void mwMpi_randDHKeypair(struct mwMpi *private, struct mwMpi *public) { - g_return_if_fail(private != NULL); - g_return_if_fail(public != NULL); - - mwDHRandKeypair(&private->i, &public->i); -} - - -static void mwDHCalculateShared(mp_int *shared, mp_int *remote, - mp_int *private) { - mp_int prime; - - mwInitDHPrime(&prime); - mp_exptmod(remote, private, &prime, shared); - mp_clear(&prime); -} - - -void mwMpi_calculateDHShared(struct mwMpi *shared, struct mwMpi *remote, - struct mwMpi *private) { - - g_return_if_fail(shared != NULL); - g_return_if_fail(remote != NULL); - g_return_if_fail(private != NULL); - - mwDHCalculateShared(&shared->i, &remote->i, &private->i); -} - - -static void mwDHImportKey(mp_int *key, struct mwOpaque *o) { - mp_read_unsigned_bin(key, o->data, o->len); -} - - -void mwMpi_import(struct mwMpi *i, struct mwOpaque *o) { - g_return_if_fail(i != NULL); - g_return_if_fail(o != NULL); - - mwDHImportKey(&i->i, o); -} - - -static void mwDHExportKey(mp_int *key, struct mwOpaque *o) { - o->len = mp_unsigned_bin_size(key); - o->data = g_malloc0(o->len); - mp_to_unsigned_bin(key, o->data); -} - - -void mwMpi_export(struct mwMpi *i, struct mwOpaque *o) { - g_return_if_fail(i != NULL); - g_return_if_fail(o != NULL); - - mwDHExportKey(&i->i, o); -} - - -void mwKeyRandom(guchar *key, gsize keylen) { - g_return_if_fail(key != NULL); - - srand(clock()); - while(keylen--) key[keylen] = rand() & 0xff; -} - - -void mwIV_init(guchar *iv) { - int i; - static guchar normal_iv[] = { - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef - }; - for(i = 8; i--; iv[i] = normal_iv[i]); - /* memcpy(iv, normal_iv, 8); */ -} - - -/* This does not seem to produce the same results as normal RC2 key - expansion would, but it works, so eh. It might be smart to farm - this out to mozilla or openssl */ -void mwKeyExpand(int *ekey, const guchar *key, gsize keylen) { - guchar tmp[128]; - int i, j; - - g_return_if_fail(keylen > 0); - g_return_if_fail(key != NULL); - - if(keylen > 128) keylen = 128; - - /* fill the first chunk with what key bytes we have */ - for(i = keylen; i--; tmp[i] = key[i]); - /* memcpy(tmp, key, keylen); */ - - /* build the remaining key from the given data */ - for(i = 0; keylen < 128; i++) { - tmp[keylen] = PT[ (tmp[keylen - 1] + tmp[i]) & 0xff ]; - keylen++; - } - - tmp[0] = PT[ tmp[0] & 0xff ]; - - for(i = 0, j = 0; i < 64; i++) { - ekey[i] = (tmp[j] & 0xff) | (tmp[j+1] << 8); - j += 2; - } -} - - -/* normal RC2 encryption given a full 128-byte (as 64 ints) key */ -static void mwEncryptBlock(const int *ekey, guchar *out) { - - int a, b, c, d; - int i, j; - - a = (out[7] << 8) | (out[6] & 0xff); - b = (out[5] << 8) | (out[4] & 0xff); - c = (out[3] << 8) | (out[2] & 0xff); - d = (out[1] << 8) | (out[0] & 0xff); - - for(i = 0; i < 16; i++) { - j = i * 4; - - d += ((c & (a ^ 0xffff)) + (b & a) + ekey[j++]); - d = (d << 1) | (d >> 15 & 0x0001); - - c += ((b & (d ^ 0xffff)) + (a & d) + ekey[j++]); - c = (c << 2) | (c >> 14 & 0x0003); - - b += ((a & (c ^ 0xffff)) + (d & c) + ekey[j++]); - b = (b << 3) | (b >> 13 & 0x0007); - - a += ((d & (b ^ 0xffff)) + (c & b) + ekey[j++]); - a = (a << 5) | (a >> 11 & 0x001f); - - if(i == 4 || i == 10) { - d += ekey[a & 0x003f]; - c += ekey[d & 0x003f]; - b += ekey[c & 0x003f]; - a += ekey[b & 0x003f]; - } - } - - *out++ = d & 0xff; - *out++ = (d >> 8) & 0xff; - *out++ = c & 0xff; - *out++ = (c >> 8) & 0xff; - *out++ = b & 0xff; - *out++ = (b >> 8) & 0xff; - *out++ = a & 0xff; - *out++ = (a >> 8) & 0xff; -} - - -void mwEncryptExpanded(const int *ekey, guchar *iv, - struct mwOpaque *in_data, - struct mwOpaque *out_data) { - - guchar *i = in_data->data; - gsize i_len = in_data->len; - - guchar *o; - gsize o_len; - - int x, y; - - /* pad upwards to a multiple of 8 */ - o_len = (i_len & -8) + 8; - o = g_malloc(o_len); - - out_data->data = o; - out_data->len = o_len; - - /* figure out the amount of padding */ - y = o_len - i_len; - - /* copy in to out, and write padding bytes */ - for(x = i_len; x--; o[x] = i[x]); - for(x = i_len; x < o_len; o[x++] = y); - /* memcpy(o, i, i_len); - memset(o + i_len, y, y); */ - - /* encrypt in blocks */ - for(x = o_len; x > 0; x -= 8) { - for(y = 8; y--; o[y] ^= iv[y]); - mwEncryptBlock(ekey, o); - for(y = 8; y--; iv[y] = o[y]); - /* memcpy(iv, o, 8); */ - o += 8; - } -} - - -void mwEncrypt(const guchar *key, gsize keylen, - guchar *iv, - struct mwOpaque *in, struct mwOpaque *out) { - - int ekey[64]; - mwKeyExpand(ekey, key, keylen); - mwEncryptExpanded(ekey, iv, in, out); -} - - -static void mwDecryptBlock(const int *ekey, guchar *out) { - - int a, b, c, d; - int i, j; - - a = (out[7] << 8) | (out[6] & 0xff); - b = (out[5] << 8) | (out[4] & 0xff); - c = (out[3] << 8) | (out[2] & 0xff); - d = (out[1] << 8) | (out[0] & 0xff); - - for(i = 16; i--; ) { - j = i * 4 + 3; - - a = (a << 11) | (a >> 5 & 0x07ff); - a -= ((d & (b ^ 0xffff)) + (c & b) + ekey[j--]); - - b = (b << 13) | (b >> 3 & 0x1fff); - b -= ((a & (c ^ 0xffff)) + (d & c) + ekey[j--]); - - c = (c << 14) | (c >> 2 & 0x3fff); - c -= ((b & (d ^ 0xffff)) + (a & d) + ekey[j--]); - - d = (d << 15) | (d >> 1 & 0x7fff); - d -= ((c & (a ^ 0xffff)) + (b & a) + ekey[j--]); - - if(i == 5 || i == 11) { - a -= ekey[b & 0x003f]; - b -= ekey[c & 0x003f]; - c -= ekey[d & 0x003f]; - d -= ekey[a & 0x003f]; - } - } - - *out++ = d & 0xff; - *out++ = (d >> 8) & 0xff; - *out++ = c & 0xff; - *out++ = (c >> 8) & 0xff; - *out++ = b & 0xff; - *out++ = (b >> 8) & 0xff; - *out++ = a & 0xff; - *out++ = (a >> 8) & 0xff; -} - - -void mwDecryptExpanded(const int *ekey, guchar *iv, - struct mwOpaque *in_data, - struct mwOpaque *out_data) { - - guchar *i = in_data->data; - gsize i_len = in_data->len; - - guchar *o; - gsize o_len; - - int x, y; - - /* this doesn't check to ensure that in_data->len is a multiple of - 8, which is damn well ought to be. */ - - o = g_malloc(i_len); - o_len = i_len; - for(x = i_len; x--; o[x] = i[x]); - /* memcpy(o, i, i_len); */ - - out_data->data = o; - out_data->len = o_len; - - for(x = o_len; x > 0; x -= 8) { - /* decrypt a block */ - mwDecryptBlock(ekey, o); - - /* modify the initialization vector */ - for(y = 8; y--; o[y] ^= iv[y]); - for(y = 8; y--; iv[y] = i[y]); - /* memcpy(iv, i, 8); */ - i += 8; - o += 8; - } - - /* shorten the length by the value of the filler in the padding - bytes */ - out_data->len -= *(o - 1); -} - - -void mwDecrypt(const guchar *key, gsize keylen, guchar *iv, - struct mwOpaque *in, struct mwOpaque *out) { - - int ekey[64]; - mwKeyExpand(ekey, key, keylen); - mwDecryptExpanded(ekey, iv, in, out); -} - - - -struct mwCipher_RC2_40 { - struct mwCipher cipher; - int session_key[64]; - gboolean ready; -}; - - -struct mwCipherInstance_RC2_40 { - struct mwCipherInstance instance; - int incoming_key[64]; - guchar outgoing_iv[8]; - guchar incoming_iv[8]; -}; - - -static const char *get_name_RC2_40() { - return "RC2/40 Cipher"; -} - - -static const char *get_desc_RC2_40() { - return "RC2, 40-bit effective key"; -} - - -static int encrypt_RC2_40(struct mwCipherInstance *ci, - struct mwOpaque *data) { - - struct mwCipherInstance_RC2_40 *cir; - struct mwCipher_RC2_40 *cr; - struct mwOpaque o = { 0, 0 }; - - cir = (struct mwCipherInstance_RC2_40 *) ci; - cr = (struct mwCipher_RC2_40 *) ci->cipher; - - mwEncryptExpanded(cr->session_key, cir->outgoing_iv, data, &o); - - mwOpaque_clear(data); - data->data = o.data; - data->len = o.len; - - return 0; -} - - -static int decrypt_RC2_40(struct mwCipherInstance *ci, - struct mwOpaque *data) { - - struct mwCipherInstance_RC2_40 *cir; - struct mwCipher_RC2_40 *cr; - struct mwOpaque o = { 0, 0 }; - - cir = (struct mwCipherInstance_RC2_40 *) ci; - cr = (struct mwCipher_RC2_40 *) ci->cipher; - - mwDecryptExpanded(cir->incoming_key, cir->incoming_iv, data, &o); - - mwOpaque_clear(data); - data->data = o.data; - data->len = o.len; - - return 0; -} - - -static struct mwCipherInstance * -new_instance_RC2_40(struct mwCipher *cipher, - struct mwChannel *chan) { - - struct mwCipher_RC2_40 *cr; - struct mwCipherInstance_RC2_40 *cir; - struct mwCipherInstance *ci; - - cr = (struct mwCipher_RC2_40 *) cipher; - - /* a bit of lazy initialization here */ - if(! cr->ready) { - struct mwLoginInfo *info = mwSession_getLoginInfo(cipher->session); - mwKeyExpand(cr->session_key, (guchar *) info->login_id, 5); - cr->ready = TRUE; - } - - cir = g_new0(struct mwCipherInstance_RC2_40, 1); - ci = &cir->instance; - - ci->cipher = cipher; - ci->channel = chan; - - mwIV_init(cir->incoming_iv); - mwIV_init(cir->outgoing_iv); - - return ci; -} - - -static struct mwEncryptItem *new_item_RC2_40(struct mwCipherInstance *ci) { - struct mwEncryptItem *e; - - e = g_new0(struct mwEncryptItem, 1); - e->id = mwCipher_RC2_40; - return e; -} - - -static struct mwEncryptItem * -offer_RC2_40(struct mwCipherInstance *ci) { - return new_item_RC2_40(ci); -} - - -static void accepted_RC2_40(struct mwCipherInstance *ci, - struct mwEncryptItem *item) { - - struct mwCipherInstance_RC2_40 *cir; - struct mwLoginInfo *info; - - cir = (struct mwCipherInstance_RC2_40 *) ci; - info = mwChannel_getUser(ci->channel); - - if(info->login_id) { - mwKeyExpand(cir->incoming_key, (guchar *) info->login_id, 5); - } -} - - -static struct mwEncryptItem * -accept_RC2_40(struct mwCipherInstance *ci) { - - accepted_RC2_40(ci, NULL); - return new_item_RC2_40(ci); -} - - -struct mwCipher *mwCipher_new_RC2_40(struct mwSession *s) { - struct mwCipher_RC2_40 *cr = g_new0(struct mwCipher_RC2_40, 1); - struct mwCipher *c = &cr->cipher; - - c->session = s; - c->type = mwCipher_RC2_40; - c->get_name = get_name_RC2_40; - c->get_desc = get_desc_RC2_40; - c->new_instance = new_instance_RC2_40; - - c->offer = offer_RC2_40; - - c->accepted = accepted_RC2_40; - c->accept = accept_RC2_40; - - c->encrypt = encrypt_RC2_40; - c->decrypt = decrypt_RC2_40; - - return c; -} - - -struct mwCipher_RC2_128 { - struct mwCipher cipher; - mp_int private_key; - struct mwOpaque public_key; -}; - - -struct mwCipherInstance_RC2_128 { - struct mwCipherInstance instance; - int shared[64]; /* shared secret determined via DH exchange */ - guchar outgoing_iv[8]; - guchar incoming_iv[8]; -}; - - -static const char *get_name_RC2_128() { - return "RC2/128 Cipher"; -} - - -static const char *get_desc_RC2_128() { - return "RC2, DH shared secret key"; -} - - -static struct mwCipherInstance * -new_instance_RC2_128(struct mwCipher *cipher, - struct mwChannel *chan) { - - struct mwCipher_RC2_128 *cr; - struct mwCipherInstance_RC2_128 *cir; - struct mwCipherInstance *ci; - - cr = (struct mwCipher_RC2_128 *) cipher; - - cir = g_new0(struct mwCipherInstance_RC2_128, 1); - ci = &cir->instance; - - ci->cipher = cipher; - ci->channel = chan; - - mwIV_init(cir->incoming_iv); - mwIV_init(cir->outgoing_iv); - - return ci; -} - - -static void offered_RC2_128(struct mwCipherInstance *ci, - struct mwEncryptItem *item) { - - mp_int remote_key; - mp_int shared; - struct mwOpaque sho = { 0, 0 }; - - struct mwCipher *c; - struct mwCipher_RC2_128 *cr; - struct mwCipherInstance_RC2_128 *cir; - - c = ci->cipher; - cr = (struct mwCipher_RC2_128 *) c; - cir = (struct mwCipherInstance_RC2_128 *) ci; - - mp_init(&remote_key); - mp_init(&shared); - - mwDHImportKey(&remote_key, &item->info); - mwDHCalculateShared(&shared, &remote_key, &cr->private_key); - mwDHExportKey(&shared, &sho); - - /* key expanded from the last 16 bytes of the DH shared secret. This - took me forever to figure out. 16 bytes is 128 bit. */ - /* the sh_len-16 is important, because the key len could - hypothetically start with 8bits or more unset, meaning the - exported key might be less than 64 bytes in length */ - mwKeyExpand(cir->shared, sho.data+(sho.len-16), 16); - - mp_clear(&remote_key); - mp_clear(&shared); - mwOpaque_clear(&sho); -} - - -static struct mwEncryptItem * -offer_RC2_128(struct mwCipherInstance *ci) { - - struct mwCipher *c; - struct mwCipher_RC2_128 *cr; - struct mwEncryptItem *ei; - - c = ci->cipher; - cr = (struct mwCipher_RC2_128 *) c; - - ei = g_new0(struct mwEncryptItem, 1); - ei->id = mwCipher_RC2_128; - mwOpaque_clone(&ei->info, &cr->public_key); - - return ei; -} - - -static void accepted_RC2_128(struct mwCipherInstance *ci, - struct mwEncryptItem *item) { - - return offered_RC2_128(ci, item); -} - - -static struct mwEncryptItem * -accept_RC2_128(struct mwCipherInstance *ci) { - - return offer_RC2_128(ci); -} - - -static int encrypt_RC2_128(struct mwCipherInstance *ci, - struct mwOpaque *data) { - - struct mwCipherInstance_RC2_128 *cir; - struct mwOpaque o = { 0, 0 }; - - cir = (struct mwCipherInstance_RC2_128 *) ci; - - mwEncryptExpanded(cir->shared, cir->outgoing_iv, data, &o); - - mwOpaque_clear(data); - data->data = o.data; - data->len = o.len; - - return 0; -} - - -static int decrypt_RC2_128(struct mwCipherInstance *ci, - struct mwOpaque *data) { - - struct mwCipherInstance_RC2_128 *cir; - struct mwOpaque o = { 0, 0 }; - - cir = (struct mwCipherInstance_RC2_128 *) ci; - - mwDecryptExpanded(cir->shared, cir->incoming_iv, data, &o); - - mwOpaque_clear(data); - data->data = o.data; - data->len = o.len; - - return 0; -} - - -static void clear_RC2_128(struct mwCipher *c) { - struct mwCipher_RC2_128 *cr; - cr = (struct mwCipher_RC2_128 *) c; - - mp_clear(&cr->private_key); - mwOpaque_clear(&cr->public_key); -} - - -struct mwCipher *mwCipher_new_RC2_128(struct mwSession *s) { - struct mwCipher_RC2_128 *cr; - struct mwCipher *c; - - mp_int pubkey; - - cr = g_new0(struct mwCipher_RC2_128, 1); - c = &cr->cipher; - - c->session = s; - c->type = mwCipher_RC2_128; - c->get_name = get_name_RC2_128; - c->get_desc = get_desc_RC2_128; - c->new_instance = new_instance_RC2_128; - - c->offered = offered_RC2_128; - c->offer = offer_RC2_128; - - c->accepted = accepted_RC2_128; - c->accept = accept_RC2_128; - - c->encrypt = encrypt_RC2_128; - c->decrypt = decrypt_RC2_128; - - c->clear = clear_RC2_128; - - mp_init(&cr->private_key); - mp_init(&pubkey); - mwDHRandKeypair(&cr->private_key, &pubkey); - mwDHExportKey(&pubkey, &cr->public_key); - mp_clear(&pubkey); - - return c; -} - - -struct mwSession *mwCipher_getSession(struct mwCipher *cipher) { - g_return_val_if_fail(cipher != NULL, NULL); - return cipher->session; -} - - -guint16 mwCipher_getType(struct mwCipher *cipher) { - /* oh man, this is a bad failover... who the hell decided to make - zero a real cipher id? */ - g_return_val_if_fail(cipher != NULL, 0xffff); - return cipher->type; -} - - -const char *mwCipher_getName(struct mwCipher *cipher) { - g_return_val_if_fail(cipher != NULL, NULL); - g_return_val_if_fail(cipher->get_name != NULL, NULL); - return cipher->get_name(); -} - - -const char *mwCipher_getDesc(struct mwCipher *cipher) { - g_return_val_if_fail(cipher != NULL, NULL); - g_return_val_if_fail(cipher->get_desc != NULL, NULL); - return cipher->get_desc(); -} - - -void mwCipher_free(struct mwCipher *cipher) { - if(! cipher) return; - - if(cipher->clear) - cipher->clear(cipher); - - g_free(cipher); -} - - -struct mwCipherInstance *mwCipher_newInstance(struct mwCipher *cipher, - struct mwChannel *chan) { - g_return_val_if_fail(cipher != NULL, NULL); - g_return_val_if_fail(chan != NULL, NULL); - g_return_val_if_fail(cipher->new_instance != NULL, NULL); - return cipher->new_instance(cipher, chan); -} - - -struct mwCipher *mwCipherInstance_getCipher(struct mwCipherInstance *ci) { - g_return_val_if_fail(ci != NULL, NULL); - return ci->cipher; -} - - -struct mwChannel *mwCipherInstance_getChannel(struct mwCipherInstance *ci) { - g_return_val_if_fail(ci != NULL, NULL); - return ci->channel; -} - - -void mwCipherInstance_offered(struct mwCipherInstance *ci, - struct mwEncryptItem *item) { - struct mwCipher *cipher; - - g_return_if_fail(ci != NULL); - - cipher = ci->cipher; - g_return_if_fail(cipher != NULL); - - if(cipher->offered) cipher->offered(ci, item); -} - - -struct mwEncryptItem * -mwCipherInstance_offer(struct mwCipherInstance *ci) { - struct mwCipher *cipher; - - g_return_val_if_fail(ci != NULL, NULL); - - cipher = ci->cipher; - g_return_val_if_fail(cipher != NULL, NULL); - - return cipher->offer(ci); -} - - -void mwCipherInstance_accepted(struct mwCipherInstance *ci, - struct mwEncryptItem *item) { - struct mwCipher *cipher; - - g_return_if_fail(ci != NULL); - - cipher = ci->cipher; - g_return_if_fail(cipher != NULL); - - if(cipher->accepted) cipher->accepted(ci, item); -} - - -struct mwEncryptItem * -mwCipherInstance_accept(struct mwCipherInstance *ci) { - struct mwCipher *cipher; - - g_return_val_if_fail(ci != NULL, NULL); - - cipher = ci->cipher; - g_return_val_if_fail(cipher != NULL, NULL); - - return cipher->accept(ci); -} - - -int mwCipherInstance_encrypt(struct mwCipherInstance *ci, - struct mwOpaque *data) { - struct mwCipher *cipher; - - g_return_val_if_fail(data != NULL, 0); - - if(! ci) return 0; - cipher = ci->cipher; - - g_return_val_if_fail(cipher != NULL, -1); - - return (cipher->encrypt)? - cipher->encrypt(ci, data): 0; -} - - -int mwCipherInstance_decrypt(struct mwCipherInstance *ci, - struct mwOpaque *data) { - struct mwCipher *cipher; - - g_return_val_if_fail(data != NULL, 0); - - if(! ci) return 0; - cipher = ci->cipher; - - g_return_val_if_fail(cipher != NULL, -1); - - return (cipher->decrypt)? - cipher->decrypt(ci, data): 0; -} - - -void mwCipherInstance_free(struct mwCipherInstance *ci) { - struct mwCipher *cipher; - - if(! ci) return; - - cipher = ci->cipher; - - if(cipher && cipher->clear_instance) - cipher->clear_instance(ci); - - g_free(ci); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/common.c --- a/src/protocols/sametime/meanwhile/common.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,927 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#include "mw_common.h" - - -/** @todo the *_get functions should make sure to clear their - structures in the event of failure, to prevent memory leaks */ - - -#define MW16_PUT(b, val) \ - *(b)++ = ((val) >> 0x08) & 0xff; \ - *(b)++ = (val) & 0xff; - - -#define MW16_GET(b, val) \ - val = (*(b)++ & 0xff) << 8; \ - val = val | (*(b)++ & 0xff); - - -#define MW32_PUT(b, val) \ - *(b)++ = ((val) >> 0x18) & 0xff; \ - *(b)++ = ((val) >> 0x10) & 0xff; \ - *(b)++ = ((val) >> 0x08) & 0xff; \ - *(b)++ = (val) & 0xff; - - -#define MW32_GET(b, val) \ - val = (*(b)++ & 0xff) << 0x18; \ - val = val | (*(b)++ & 0xff) << 0x10; \ - val = val | (*(b)++ & 0xff) << 0x08; \ - val = val | (*(b)++ & 0xff); - - -struct mwPutBuffer { - guchar *buf; /**< head of buffer */ - gsize len; /**< length of buffer */ - - guchar *ptr; /**< offset to first unused byte */ - gsize rem; /**< count of unused bytes remaining */ -}; - - -struct mwGetBuffer { - guchar *buf; /**< head of buffer */ - gsize len; /**< length of buffer */ - - guchar *ptr; /**< offset to first unused byte */ - gsize rem; /**< count of unused bytes remaining */ - - gboolean wrap; /**< TRUE to indicate buf shouldn't be freed */ - gboolean error; /**< TRUE to indicate an error */ -}; - - -#define BUFFER_USED(buffer) \ - ((buffer)->len - (buffer)->rem) - - -/** ensure that there's at least enough space remaining in the put - buffer to fit needed. */ -static void ensure_buffer(struct mwPutBuffer *b, gsize needed) { - if(b->rem < needed) { - gsize len = b->len, use = BUFFER_USED(b); - guchar *buf; - - /* newly created buffers are empty until written to, and then they - have 1024 available */ - if(! len) len = 1024; - - /* double len until it's large enough to fit needed */ - while( (len - use) < needed ) len = len << 1; - - /* create the new buffer. if there was anything in the old buffer, - copy it into the new buffer and free the old copy */ - buf = g_malloc(len); - if(b->buf) { - memcpy(buf, b->buf, use); - g_free(b->buf); - } - - /* put the new buffer into b */ - b->buf = buf; - b->len = len; - b->ptr = buf + use; - b->rem = len - use; - } -} - - -/** determine if there are at least needed bytes available in the - buffer. sets the error flag if there's not at least needed bytes - left in the buffer - - @returns true if there's enough data, false if not */ -static gboolean check_buffer(struct mwGetBuffer *b, gsize needed) { - if(! b->error) b->error = (b->rem < needed); - return ! b->error; -} - - -struct mwPutBuffer *mwPutBuffer_new() { - return g_new0(struct mwPutBuffer, 1); -} - - -void mwPutBuffer_write(struct mwPutBuffer *b, gpointer data, gsize len) { - g_return_if_fail(b != NULL); - g_return_if_fail(data != NULL); - - if(! len) return; - - ensure_buffer(b, len); - memcpy(b->ptr, data, len); - b->ptr += len; - b->rem -= len; -} - - -void mwPutBuffer_free(struct mwPutBuffer *b) { - if(! b) return; - g_free(b->buf); - g_free(b); -} - - -void mwPutBuffer_finalize(struct mwOpaque *to, struct mwPutBuffer *from) { - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - to->len = BUFFER_USED(from); - to->data = from->buf; - - g_free(from); -} - - -struct mwGetBuffer *mwGetBuffer_new(struct mwOpaque *o) { - struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1); - - if(o && o->len) { - b->buf = b->ptr = g_memdup(o->data, o->len); - b->len = b->rem = o->len; - } - - return b; -} - - -struct mwGetBuffer *mwGetBuffer_wrap(const struct mwOpaque *o) { - struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1); - - if(o && o->len) { - b->buf = b->ptr = o->data; - b->len = b->rem = o->len; - } - b->wrap = TRUE; - - return b; -} - - -gsize mwGetBuffer_read(struct mwGetBuffer *b, gpointer data, gsize len) { - g_return_val_if_fail(b != NULL, 0); - g_return_val_if_fail(data != NULL, 0); - - if(b->error) return 0; - if(! len) return 0; - - if(b->rem < len) - len = b->rem; - - memcpy(data, b->ptr, len); - b->ptr += len; - b->rem -= len; - - return len; -} - - -gsize mwGetBuffer_advance(struct mwGetBuffer *b, gsize len) { - g_return_val_if_fail(b != NULL, 0); - - if(b->error) return 0; - if(! len) return 0; - - if(b->rem < len) - len = b->rem; - - b->ptr += len; - b->rem -= len; - - return len; -} - - -void mwGetBuffer_reset(struct mwGetBuffer *b) { - g_return_if_fail(b != NULL); - - b->rem = b->len; - b->ptr = b->buf; - b->error = FALSE; -} - - -gsize mwGetBuffer_remaining(struct mwGetBuffer *b) { - g_return_val_if_fail(b != NULL, 0); - return b->rem; -} - - -gboolean mwGetBuffer_error(struct mwGetBuffer *b) { - g_return_val_if_fail(b != NULL, TRUE); - return b->error; -} - - -void mwGetBuffer_free(struct mwGetBuffer *b) { - if(! b) return; - if(! b->wrap) g_free(b->buf); - g_free(b); -} - - -#define guint16_buflen() 2 - - -void guint16_put(struct mwPutBuffer *b, guint16 val) { - g_return_if_fail(b != NULL); - - ensure_buffer(b, guint16_buflen()); - MW16_PUT(b->ptr, val); - b->rem -= guint16_buflen(); -} - - -void guint16_get(struct mwGetBuffer *b, guint16 *val) { - g_return_if_fail(b != NULL); - - if(b->error) return; - g_return_if_fail(check_buffer(b, guint16_buflen())); - - MW16_GET(b->ptr, *val); - b->rem -= guint16_buflen(); -} - - -guint16 guint16_peek(struct mwGetBuffer *b) { - guchar *buf = b->buf; - guint16 r = 0; - - if(b->rem >= guint16_buflen()) - MW16_GET(buf, r); - - return r; -} - - -#define guint32_buflen() 4 - - -void guint32_put(struct mwPutBuffer *b, guint32 val) { - g_return_if_fail(b != NULL); - - ensure_buffer(b, guint32_buflen()); - MW32_PUT(b->ptr, val); - b->rem -= guint32_buflen(); -} - - -void guint32_get(struct mwGetBuffer *b, guint32 *val) { - g_return_if_fail(b != NULL); - - if(b->error) return; - g_return_if_fail(check_buffer(b, guint32_buflen())); - - MW32_GET(b->ptr, *val); - b->rem -= guint32_buflen(); -} - - -guint32 guint32_peek(struct mwGetBuffer *b) { - guchar *buf = b->buf; - guint32 r = 0; - - if(b->rem >= guint32_buflen()) - MW32_GET(buf, r); - - return r; -} - - -#define gboolean_buflen() 1 - - -void gboolean_put(struct mwPutBuffer *b, gboolean val) { - g_return_if_fail(b != NULL); - - ensure_buffer(b, gboolean_buflen()); - *(b->ptr) = !! val; - b->ptr++; - b->rem--; -} - - -void gboolean_get(struct mwGetBuffer *b, gboolean *val) { - g_return_if_fail(b != NULL); - - if(b->error) return; - g_return_if_fail(check_buffer(b, gboolean_buflen())); - - *val = !! *(b->ptr); - b->ptr++; - b->rem--; -} - - -gboolean gboolean_peek(struct mwGetBuffer *b) { - gboolean v = FALSE; - - if(b->rem >= gboolean_buflen()) - v = !! *(b->ptr); - - return v; -} - - -gboolean mw_streq(const char *a, const char *b) { - return (a == b) || (a && b && !strcmp(a, b)); -} - - -void mwString_put(struct mwPutBuffer *b, const char *val) { - gsize len = 0; - - g_return_if_fail(b != NULL); - - if(val) len = strlen(val); - - guint16_put(b, (guint16) len); - - if(len) { - ensure_buffer(b, len); - memcpy(b->ptr, val, len); - b->ptr += len; - b->rem -= len; - } -} - - -void mwString_get(struct mwGetBuffer *b, char **val) { - guint16 len = 0; - - g_return_if_fail(b != NULL); - g_return_if_fail(val != NULL); - - *val = NULL; - - if(b->error) return; - guint16_get(b, &len); - - g_return_if_fail(check_buffer(b, (gsize) len)); - - if(len) { - *val = g_malloc0(len + 1); - memcpy(*val, b->ptr, len); - b->ptr += len; - b->rem -= len; - } -} - - -void mwOpaque_put(struct mwPutBuffer *b, const struct mwOpaque *o) { - gsize len; - - g_return_if_fail(b != NULL); - - if(! o) { - guint32_put(b, 0x00); - return; - } - - len = o->len; - if(len) - g_return_if_fail(o->data != NULL); - - guint32_put(b, (guint32) len); - - if(len) { - ensure_buffer(b, len); - memcpy(b->ptr, o->data, len); - b->ptr += len; - b->rem -= len; - } -} - - -void mwOpaque_get(struct mwGetBuffer *b, struct mwOpaque *o) { - guint32 tmp = 0; - - g_return_if_fail(b != NULL); - g_return_if_fail(o != NULL); - - o->len = 0; - o->data = NULL; - - if(b->error) return; - guint32_get(b, &tmp); - - g_return_if_fail(check_buffer(b, (gsize) tmp)); - - o->len = (gsize) tmp; - if(tmp > 0) { - o->data = g_memdup(b->ptr, tmp); - b->ptr += tmp; - b->rem -= tmp; - } -} - - -void mwOpaque_clear(struct mwOpaque *o) { - if(! o) return; - g_free(o->data); - o->data = NULL; - o->len = 0; -} - - -void mwOpaque_free(struct mwOpaque *o) { - if(! o) return; - g_free(o->data); - g_free(o); -} - - -void mwOpaque_clone(struct mwOpaque *to, const struct mwOpaque *from) { - g_return_if_fail(to != NULL); - - to->len = 0; - to->data = NULL; - - if(from) { - to->len = from->len; - if(to->len) - to->data = g_memdup(from->data, to->len); - } -} - - -/* 8.2 Common Structures */ -/* 8.2.1 Login Info block */ - - -void mwLoginInfo_put(struct mwPutBuffer *b, const struct mwLoginInfo *login) { - g_return_if_fail(b != NULL); - g_return_if_fail(login != NULL); - - mwString_put(b, login->login_id); - guint16_put(b, login->type); - mwString_put(b, login->user_id); - mwString_put(b, login->user_name); - mwString_put(b, login->community); - gboolean_put(b, login->full); - - if(login->full) { - mwString_put(b, login->desc); - guint32_put(b, login->ip_addr); - mwString_put(b, login->server_id); - } -} - - -void mwLoginInfo_get(struct mwGetBuffer *b, struct mwLoginInfo *login) { - g_return_if_fail(b != NULL); - g_return_if_fail(login != NULL); - - if(b->error) return; - - mwString_get(b, &login->login_id); - guint16_get(b, &login->type); - mwString_get(b, &login->user_id); - mwString_get(b, &login->user_name); - mwString_get(b, &login->community); - gboolean_get(b, &login->full); - - if(login->full) { - mwString_get(b, &login->desc); - guint32_get(b, &login->ip_addr); - mwString_get(b, &login->server_id); - } -} - - -void mwLoginInfo_clear(struct mwLoginInfo *login) { - if(! login) return; - - g_free(login->login_id); - g_free(login->user_id); - g_free(login->user_name); - g_free(login->community); - g_free(login->desc); - g_free(login->server_id); - - memset(login, 0x00, sizeof(struct mwLoginInfo)); -} - - -void mwLoginInfo_clone(struct mwLoginInfo *to, - const struct mwLoginInfo *from) { - - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - to->login_id= g_strdup(from->login_id); - to->type = from->type; - to->user_id = g_strdup(from->user_id); - to->user_name = g_strdup(from->user_name); - to->community = g_strdup(from->community); - - if( (to->full = from->full) ) { - to->desc = g_strdup(from->desc); - to->ip_addr = from->ip_addr; - to->server_id = g_strdup(from->server_id); - } -} - - -/* 8.2.2 Private Info Block */ - - -void mwUserItem_put(struct mwPutBuffer *b, const struct mwUserItem *user) { - g_return_if_fail(b != NULL); - g_return_if_fail(user != NULL); - - gboolean_put(b, user->full); - mwString_put(b, user->id); - mwString_put(b, user->community); - - if(user->full) - mwString_put(b, user->name); -} - - -void mwUserItem_get(struct mwGetBuffer *b, struct mwUserItem *user) { - g_return_if_fail(b != NULL); - g_return_if_fail(user != NULL); - - if(b->error) return; - - gboolean_get(b, &user->full); - mwString_get(b, &user->id); - mwString_get(b, &user->community); - - if(user->full) - mwString_get(b, &user->name); -} - - -void mwUserItem_clear(struct mwUserItem *user) { - if(! user) return; - - g_free(user->id); - g_free(user->community); - g_free(user->name); - - memset(user, 0x00, sizeof(struct mwUserItem)); -} - - -void mwUserItem_clone(struct mwUserItem *to, - const struct mwUserItem *from) { - - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - to->full = from->full; - to->id = g_strdup(from->id); - to->community = g_strdup(from->community); - to->name = (to->full)? g_strdup(from->name): NULL; -} - - -void mwPrivacyInfo_put(struct mwPutBuffer *b, - const struct mwPrivacyInfo *info) { - guint32 c; - - g_return_if_fail(b != NULL); - g_return_if_fail(info != NULL); - - gboolean_put(b, info->deny); - guint32_put(b, info->count); - - for(c = info->count; c--; ) mwUserItem_put(b, info->users + c); -} - - -void mwPrivacyInfo_get(struct mwGetBuffer *b, struct mwPrivacyInfo *info) { - g_return_if_fail(b != NULL); - g_return_if_fail(info != NULL); - - if(b->error) return; - - gboolean_get(b, &info->deny); - guint32_get(b, &info->count); - - if(info->count) { - guint32 c = info->count; - info->users = g_new0(struct mwUserItem, c); - while(c--) mwUserItem_get(b, info->users + c); - } -} - - -void mwPrivacyInfo_clone(struct mwPrivacyInfo *to, - const struct mwPrivacyInfo *from) { - - guint32 c; - - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - to->deny = from->deny; - c = to->count = from->count; - - to->users = g_new0(struct mwUserItem, c); - while(c--) mwUserItem_clone(to->users+c, from->users+c); -} - - -void mwPrivacyInfo_clear(struct mwPrivacyInfo *info) { - struct mwUserItem *u; - guint32 c; - - g_return_if_fail(info != NULL); - - u = info->users; - c = info->count; - - while(c--) mwUserItem_clear(u + c); - g_free(u); - - info->count = 0; - info->users = NULL; -} - - -/* 8.2.3 User Status Block */ - - -void mwUserStatus_put(struct mwPutBuffer *b, - const struct mwUserStatus *stat) { - - g_return_if_fail(b != NULL); - g_return_if_fail(stat != NULL); - - guint16_put(b, stat->status); - guint32_put(b, stat->time); - mwString_put(b, stat->desc); -} - - -void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat) { - g_return_if_fail(b != NULL); - g_return_if_fail(stat != NULL); - - if(b->error) return; - - guint16_get(b, &stat->status); - guint32_get(b, &stat->time); - mwString_get(b, &stat->desc); -} - - -void mwUserStatus_clear(struct mwUserStatus *stat) { - if(! stat) return; - g_free(stat->desc); - memset(stat, 0x00, sizeof(struct mwUserStatus)); -} - - -void mwUserStatus_clone(struct mwUserStatus *to, - const struct mwUserStatus *from) { - - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - to->status = from->status; - to->time = from->time; - to->desc = g_strdup(from->desc); -} - - -/* 8.2.4 ID Block */ - - -void mwIdBlock_put(struct mwPutBuffer *b, const struct mwIdBlock *id) { - g_return_if_fail(b != NULL); - g_return_if_fail(id != NULL); - - mwString_put(b, id->user); - mwString_put(b, id->community); -} - - -void mwIdBlock_get(struct mwGetBuffer *b, struct mwIdBlock *id) { - g_return_if_fail(b != NULL); - g_return_if_fail(id != NULL); - - if(b->error) return; - - mwString_get(b, &id->user); - mwString_get(b, &id->community); -} - - -void mwIdBlock_clear(struct mwIdBlock *id) { - if(! id) return; - - g_free(id->user); - id->user = NULL; - - g_free(id->community); - id->community = NULL; -} - - -void mwIdBlock_clone(struct mwIdBlock *to, const struct mwIdBlock *from) { - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - to->user = g_strdup(from->user); - to->community = g_strdup(from->community); -} - - -guint mwIdBlock_hash(const struct mwIdBlock *idb) { - return (idb)? g_str_hash(idb->user): 0; -} - - -gboolean mwIdBlock_equal(const struct mwIdBlock *a, - const struct mwIdBlock *b) { - - g_return_val_if_fail(a != NULL, FALSE); - g_return_val_if_fail(b != NULL, FALSE); - - return ( mw_streq(a->user, b->user) && - mw_streq(a->community, b->community) ); -} - - -/* 8.2.5 Encryption Block */ - -/** @todo I think this can be put into cipher */ - -void mwEncryptItem_put(struct mwPutBuffer *b, - const struct mwEncryptItem *ei) { - - g_return_if_fail(b != NULL); - g_return_if_fail(ei != NULL); - - guint16_put(b, ei->id); - mwOpaque_put(b, &ei->info); - -} - - -void mwEncryptItem_get(struct mwGetBuffer *b, struct mwEncryptItem *ei) { - g_return_if_fail(b != NULL); - g_return_if_fail(ei != NULL); - - if(b->error) return; - - guint16_get(b, &ei->id); - mwOpaque_get(b, &ei->info); -} - - -void mwEncryptItem_clear(struct mwEncryptItem *ei) { - if(! ei) return; - ei->id = 0x0000; - mwOpaque_clear(&ei->info); -} - - -void mwEncryptItem_free(struct mwEncryptItem *ei) { - mwEncryptItem_clear(ei); - g_free(ei); -} - - -/* 8.4.2.1 Awareness ID Block */ - - -/** @todo move this into srvc_aware */ - -void mwAwareIdBlock_put(struct mwPutBuffer *b, - const struct mwAwareIdBlock *idb) { - - g_return_if_fail(b != NULL); - g_return_if_fail(idb != NULL); - - guint16_put(b, idb->type); - mwString_put(b, idb->user); - mwString_put(b, idb->community); -} - - -void mwAwareIdBlock_get(struct mwGetBuffer *b, struct mwAwareIdBlock *idb) { - g_return_if_fail(b != NULL); - g_return_if_fail(idb != NULL); - - if(b->error) return; - - guint16_get(b, &idb->type); - mwString_get(b, &idb->user); - mwString_get(b, &idb->community); -} - - -void mwAwareIdBlock_clone(struct mwAwareIdBlock *to, - const struct mwAwareIdBlock *from) { - - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - to->type = from->type; - to->user = g_strdup(from->user); - to->community = g_strdup(from->community); -} - - -void mwAwareIdBlock_clear(struct mwAwareIdBlock *idb) { - if(! idb) return; - g_free(idb->user); - g_free(idb->community); - memset(idb, 0x00, sizeof(struct mwAwareIdBlock)); -} - - -guint mwAwareIdBlock_hash(const struct mwAwareIdBlock *a) { - return (a)? g_str_hash(a->user): 0; -} - - -gboolean mwAwareIdBlock_equal(const struct mwAwareIdBlock *a, - const struct mwAwareIdBlock *b) { - - g_return_val_if_fail(a != NULL, FALSE); - g_return_val_if_fail(b != NULL, FALSE); - - return ( (a->type == b->type) && - mw_streq(a->user, b->user) && - mw_streq(a->community, b->community) ); -} - - -/* 8.4.2.4 Snapshot */ - -void mwAwareSnapshot_get(struct mwGetBuffer *b, struct mwAwareSnapshot *idb) { - guint32 junk; - char *empty = NULL; - - g_return_if_fail(b != NULL); - g_return_if_fail(idb != NULL); - - guint32_get(b, &junk); - mwAwareIdBlock_get(b, &idb->id); - mwString_get(b, &idb->group); - gboolean_get(b, &idb->online); - - g_free(empty); - - if(idb->online) { - mwString_get(b, &idb->alt_id); - mwUserStatus_get(b, &idb->status); - mwString_get(b, &idb->name); - } -} - - -void mwAwareSnapshot_clone(struct mwAwareSnapshot *to, - const struct mwAwareSnapshot *from) { - - g_return_if_fail(to != NULL); - g_return_if_fail(from != NULL); - - mwAwareIdBlock_clone(&to->id, &from->id); - if( (to->online = from->online) ) { - to->alt_id = g_strdup(from->alt_id); - mwUserStatus_clone(&to->status, &from->status); - to->name = g_strdup(from->name); - to->group = g_strdup(from->group); - } -} - - -void mwAwareSnapshot_clear(struct mwAwareSnapshot *idb) { - if(! idb) return; - mwAwareIdBlock_clear(&idb->id); - mwUserStatus_clear(&idb->status); - g_free(idb->alt_id); - g_free(idb->name); - g_free(idb->group); - memset(idb, 0x00, sizeof(struct mwAwareSnapshot)); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/error.c --- a/src/protocols/sametime/meanwhile/error.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#include "mw_error.h" - - -static char *err_to_str(guint32 code) { - static char b[11]; /* 0x12345678 + NULL terminator */ - sprintf((char *) b, "0x%08x", code); - b[10] = '\0'; - return b; -} - - -#define CASE(val, str) \ -case val: \ - m = str; \ - break; - - -char* mwError(guint32 code) { - const char *m; - - switch(code) { - - /* 8.3.1.1 General error/success codes */ - CASE(ERR_SUCCESS, "Success"); - CASE(ERR_FAILURE, "General failure"); - CASE(ERR_REQUEST_DELAY, "Request delayed"); - CASE(ERR_REQUEST_INVALID, "Request is invalid"); - CASE(ERR_NOT_AUTHORIZED, "Not authorized"); - CASE(ERR_NO_USER, "User is not online"); - CASE(ERR_CHANNEL_NO_SUPPORT, "Requested channel is not supported"); - CASE(ERR_CHANNEL_EXISTS, "Requested channel already exists"); - CASE(ERR_SERVICE_NO_SUPPORT, "Requested service is not supported"); - CASE(ERR_PROTOCOL_NO_SUPPORT, "Requested protocol is not supported"); - CASE(ERR_VERSION_NO_SUPPORT, "Version is not supported"); - CASE(ERR_USER_SKETCHY, "User is invalid or not trusted"); - CASE(ERR_ALREADY_INITIALIZED, "Already initialized"); - CASE(ERR_ENCRYPT_NO_SUPPORT, "Encryption method not supported"); - CASE(ERR_NO_COMMON_ENCRYPT, "No common encryption method"); - - /* 8.3.1.2 Connection/disconnection errors */ - CASE(VERSION_MISMATCH, "Version mismatch"); - CASE(FAT_MESSAGE, "Message is too large"); - CASE(CONNECTION_BROKEN, "Connection broken"); - CASE(CONNECTION_ABORTED, "Connection aborted"); - CASE(CONNECTION_REFUSED, "Connection refused"); - CASE(CONNECTION_RESET, "Connection reset"); - CASE(CONNECTION_TIMED, "Connection timed out"); - CASE(CONNECTION_CLOSED, "Connection closed"); - CASE(INCORRECT_LOGIN, "Incorrect Username/Password"); - CASE(VERIFICATION_DOWN, "Login verification down or unavailable"); - CASE(GUEST_IN_USE, "The guest name is currently being used"); - CASE(MULTI_SERVER_LOGIN, "Login to two different servers concurrently"); - CASE(MULTI_SERVER_LOGIN2, "Login to two different servers concurrently"); - CASE(SERVER_BROKEN, "Server misconfiguration"); - - /* 8.3.1.3 Client error codes */ - CASE(ERR_CLIENT_USER_GONE, "User is not online"); - CASE(ERR_CLIENT_USER_DND, "User is in Do Not Disturb mode"); - CASE(ERR_CLIENT_USER_ELSEWHERE, "Already logged in elsewhere"); - - /* 8.3.1.4 IM error codes */ - CASE(ERR_IM_COULDNT_REGISTER, "Cannot register a reserved type"); - CASE(ERR_IM_ALREADY_REGISTERED, "Requested type is already registered"); - CASE(ERR_IM_NOT_REGISTERED, "Requested type is not registered"); - - default: - m = err_to_str(code); - } - - return g_strdup(m); -} - - -#undef CASE diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/message.c --- a/src/protocols/sametime/meanwhile/message.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,853 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -#include "mw_debug.h" -#include "mw_message.h" - - -/* 7.1 Layering and message encapsulation */ -/* 7.1.1 The Sametime Message Header */ - - -static void mwMessageHead_put(struct mwPutBuffer *b, struct mwMessage *msg) { - guint16_put(b, msg->type); - guint16_put(b, msg->options); - guint32_put(b, msg->channel); - - if(msg->options & mwMessageOption_HAS_ATTRIBS) - mwOpaque_put(b, &msg->attribs); -} - - -static void mwMessageHead_get(struct mwGetBuffer *b, struct mwMessage *msg) { - - if(mwGetBuffer_error(b)) return; - - guint16_get(b, &msg->type); - guint16_get(b, &msg->options); - guint32_get(b, &msg->channel); - - if(msg->options & mwMessageOption_HAS_ATTRIBS) - mwOpaque_get(b, &msg->attribs); -} - - -static void mwMessageHead_clone(struct mwMessage *to, - struct mwMessage *from) { - - to->type = from->type; - to->options = from->options; - to->channel = from->channel; - mwOpaque_clone(&to->attribs, &from->attribs); -} - - -static void mwMessageHead_clear(struct mwMessage *msg) { - mwOpaque_clear(&msg->attribs); -} - - -/* 8.4 Messages */ -/* 8.4.1 Basic Community Messages */ -/* 8.4.1.1 Handshake */ - - -static void HANDSHAKE_put(struct mwPutBuffer *b, struct mwMsgHandshake *msg) { - guint16_put(b, msg->major); - guint16_put(b, msg->minor); - guint32_put(b, msg->head.channel); - guint32_put(b, msg->srvrcalc_addr); - guint16_put(b, msg->login_type); - guint32_put(b, msg->loclcalc_addr); - - if(msg->major >= 0x001e && msg->minor >= 0x001d) { - guint16_put(b, msg->unknown_a); - guint32_put(b, msg->unknown_b); - mwString_put(b, msg->local_host); - } -} - - -static void HANDSHAKE_get(struct mwGetBuffer *b, struct mwMsgHandshake *msg) { - if(mwGetBuffer_error(b)) return; - - guint16_get(b, &msg->major); - guint16_get(b, &msg->minor); - guint32_get(b, &msg->head.channel); - guint32_get(b, &msg->srvrcalc_addr); - guint16_get(b, &msg->login_type); - guint32_get(b, &msg->loclcalc_addr); - - if(msg->major >= 0x001e && msg->minor >= 0x001d) { - guint16_get(b, &msg->unknown_a); - guint32_get(b, &msg->unknown_b); - mwString_get(b, &msg->local_host); - } -} - - -static void HANDSHAKE_clear(struct mwMsgHandshake *msg) { - ; /* nothing to clean up */ -} - - -/* 8.4.1.2 HandshakeAck */ - - -static void HANDSHAKE_ACK_get(struct mwGetBuffer *b, - struct mwMsgHandshakeAck *msg) { - - if(mwGetBuffer_error(b)) return; - - guint16_get(b, &msg->major); - guint16_get(b, &msg->minor); - guint32_get(b, &msg->srvrcalc_addr); - - /** @todo: get a better handle on what versions support what parts - of this message. eg: minor version 0x0018 doesn't send the - following */ - if(msg->major >= 0x1e && msg->minor > 0x18) { - guint32_get(b, &msg->magic); - mwOpaque_get(b, &msg->data); - } -} - - -static void HANDSHAKE_ACK_put(struct mwPutBuffer *b, - struct mwMsgHandshakeAck *msg) { - - guint16_put(b, msg->major); - guint16_put(b, msg->minor); - guint32_put(b, msg->srvrcalc_addr); - - if(msg->major >= 0x1e && msg->minor > 0x18) { - guint32_put(b, msg->magic); - mwOpaque_put(b, &msg->data); - } -} - - -static void HANDSHAKE_ACK_clear(struct mwMsgHandshakeAck *msg) { - mwOpaque_clear(&msg->data); -} - - -/* 8.4.1.3 Login */ - - -static void LOGIN_put(struct mwPutBuffer *b, struct mwMsgLogin *msg) { - guint16_put(b, msg->login_type); - mwString_put(b, msg->name); - - /* ordering reversed from houri draft?? */ - mwOpaque_put(b, &msg->auth_data); - guint16_put(b, msg->auth_type); - - guint16_put(b, 0x0000); /* unknown */ -} - - -static void LOGIN_get(struct mwGetBuffer *b, struct mwMsgLogin *msg) { - if(mwGetBuffer_error(b)) return; - - guint16_get(b, &msg->login_type); - mwString_get(b, &msg->name); - mwOpaque_get(b, &msg->auth_data); - guint16_get(b, &msg->auth_type); -} - - -static void LOGIN_clear(struct mwMsgLogin *msg) { - g_free(msg->name); msg->name = NULL; - mwOpaque_clear(&msg->auth_data); -} - - -/* 8.4.1.4 LoginAck */ - - -static void LOGIN_ACK_get(struct mwGetBuffer *b, struct mwMsgLoginAck *msg) { - guint16 junk; - - if(mwGetBuffer_error(b)) return; - - mwLoginInfo_get(b, &msg->login); - guint16_get(b, &junk); - mwPrivacyInfo_get(b, &msg->privacy); - mwUserStatus_get(b, &msg->status); -} - - -static void LOGIN_ACK_clear(struct mwMsgLoginAck *msg) { - mwLoginInfo_clear(&msg->login); - mwPrivacyInfo_clear(&msg->privacy); - mwUserStatus_clear(&msg->status); -} - - -/* 8.4.1.5 LoginCont */ - - -static void LOGIN_CONTINUE_put(struct mwPutBuffer *b, - struct mwMsgLoginContinue *msg) { - - ; /* nothing but a message header */ -} - - -static void LOGIN_CONTINUE_get(struct mwGetBuffer *b, - struct mwMsgLoginContinue *msg) { - - ; /* nothing but a message header */ -} - - -static void LOGIN_CONTINUE_clear(struct mwMsgLoginContinue *msg) { - ; /* this is a very simple message */ -} - - -/* 8.4.1.6 AuthPassed */ - - -static void LOGIN_REDIRECT_get(struct mwGetBuffer *b, - struct mwMsgLoginRedirect *msg) { - - if(mwGetBuffer_error(b)) return; - mwString_get(b, &msg->host); - mwString_get(b, &msg->server_id); -} - - -static void LOGIN_REDIRECT_put(struct mwPutBuffer *b, - struct mwMsgLoginRedirect *msg) { - mwString_put(b, msg->host); - mwString_put(b, msg->server_id); -} - - -static void LOGIN_REDIRECT_clear(struct mwMsgLoginRedirect *msg) { - g_free(msg->host); - msg->host = NULL; - - g_free(msg->server_id); - msg->server_id = NULL; -} - - -/* 8.4.1.7 CreateCnl */ - - -static void enc_offer_put(struct mwPutBuffer *b, struct mwEncryptOffer *enc) { - guint16_put(b, enc->mode); - - if(enc->items) { - guint32 count; - struct mwPutBuffer *p; - struct mwOpaque o; - GList *list; - - /* write the count, items, extra, and flag into a tmp buffer, - render that buffer into an opaque, and write it into b */ - - count = g_list_length(enc->items); - p = mwPutBuffer_new(); - - guint32_put(p, count); - for(list = enc->items; list; list = list->next) { - mwEncryptItem_put(p, list->data); - } - - guint16_put(p, enc->extra); - gboolean_put(p, enc->flag); - - mwPutBuffer_finalize(&o, p); - mwOpaque_put(b, &o); - mwOpaque_clear(&o); - } -} - - -static void CHANNEL_CREATE_put(struct mwPutBuffer *b, - struct mwMsgChannelCreate *msg) { - - guint32_put(b, msg->reserved); - guint32_put(b, msg->channel); - mwIdBlock_put(b, &msg->target); - guint32_put(b, msg->service); - guint32_put(b, msg->proto_type); - guint32_put(b, msg->proto_ver); - guint32_put(b, msg->options); - mwOpaque_put(b, &msg->addtl); - gboolean_put(b, msg->creator_flag); - - if(msg->creator_flag) - mwLoginInfo_put(b, &msg->creator); - - enc_offer_put(b, &msg->encrypt); - - guint32_put(b, 0x00); - guint32_put(b, 0x00); - guint16_put(b, 0x07); -} - - -static void enc_offer_get(struct mwGetBuffer *b, - struct mwEncryptOffer *enc) { - guint32 skip; - - if(mwGetBuffer_error(b)) return; - - guint16_get(b, &enc->mode); - guint32_get(b, &skip); - - if(skip >= 7) { - guint32 count; - - guint32_get(b, &count); - - while(count-- && (! mwGetBuffer_error(b))) { - struct mwEncryptItem *ei = g_new0(struct mwEncryptItem, 1); - mwEncryptItem_get(b, ei); - enc->items = g_list_append(enc->items, ei); - } - - guint16_get(b, &enc->extra); - gboolean_get(b, &enc->flag); - } -} - - -static void CHANNEL_CREATE_get(struct mwGetBuffer *b, - struct mwMsgChannelCreate *msg) { - - if(mwGetBuffer_error(b)) return; - - guint32_get(b, &msg->reserved); - guint32_get(b, &msg->channel); - mwIdBlock_get(b, &msg->target); - guint32_get(b, &msg->service); - guint32_get(b, &msg->proto_type); - guint32_get(b, &msg->proto_ver); - guint32_get(b, &msg->options); - mwOpaque_get(b, &msg->addtl); - gboolean_get(b, &msg->creator_flag); - - if(msg->creator_flag) - mwLoginInfo_get(b, &msg->creator); - - enc_offer_get(b, &msg->encrypt); -} - - -static void CHANNEL_CREATE_clear(struct mwMsgChannelCreate *msg) { - GList *list; - - mwIdBlock_clear(&msg->target); - mwOpaque_clear(&msg->addtl); - mwLoginInfo_clear(&msg->creator); - - for(list = msg->encrypt.items; list; list = list->next) { - mwEncryptItem_clear(list->data); - g_free(list->data); - } - g_list_free(msg->encrypt.items); -} - - -/* 8.4.1.8 AcceptCnl */ - - -static void enc_accept_put(struct mwPutBuffer *b, - struct mwEncryptAccept *enc) { - - guint16_put(b, enc->mode); - - if(enc->item) { - struct mwPutBuffer *p; - struct mwOpaque o; - - p = mwPutBuffer_new(); - - mwEncryptItem_put(p, enc->item); - guint16_put(p, enc->extra); - gboolean_put(p, enc->flag); - - mwPutBuffer_finalize(&o, p); - mwOpaque_put(b, &o); - mwOpaque_clear(&o); - } -} - - -static void CHANNEL_ACCEPT_put(struct mwPutBuffer *b, - struct mwMsgChannelAccept *msg) { - - guint32_put(b, msg->service); - guint32_put(b, msg->proto_type); - guint32_put(b, msg->proto_ver); - mwOpaque_put(b, &msg->addtl); - gboolean_put(b, msg->acceptor_flag); - - if(msg->acceptor_flag) - mwLoginInfo_put(b, &msg->acceptor); - - enc_accept_put(b, &msg->encrypt); - - guint32_put(b, 0x00); - guint32_put(b, 0x00); - guint16_put(b, 0x07); -} - - -static void enc_accept_get(struct mwGetBuffer *b, - struct mwEncryptAccept *enc) { - guint32 skip; - - if(mwGetBuffer_error(b)) return; - - guint16_get(b, &enc->mode); - guint32_get(b, &skip); - - if(skip >= 6) { - enc->item = g_new0(struct mwEncryptItem, 1); - mwEncryptItem_get(b, enc->item); - } - - if(skip >= 9) { - guint16_get(b, &enc->extra); - gboolean_get(b, &enc->flag); - } -} - - -static void CHANNEL_ACCEPT_get(struct mwGetBuffer *b, - struct mwMsgChannelAccept *msg) { - - if(mwGetBuffer_error(b)) return; - - guint32_get(b, &msg->service); - guint32_get(b, &msg->proto_type); - guint32_get(b, &msg->proto_ver); - mwOpaque_get(b, &msg->addtl); - gboolean_get(b, &msg->acceptor_flag); - - if(msg->acceptor_flag) - mwLoginInfo_get(b, &msg->acceptor); - - enc_accept_get(b, &msg->encrypt); -} - - -static void CHANNEL_ACCEPT_clear(struct mwMsgChannelAccept *msg) { - mwOpaque_clear(&msg->addtl); - mwLoginInfo_clear(&msg->acceptor); - - if(msg->encrypt.item) { - mwEncryptItem_clear(msg->encrypt.item); - g_free(msg->encrypt.item); - } -} - - -/* 8.4.1.9 SendOnCnl */ - - -static void CHANNEL_SEND_put(struct mwPutBuffer *b, - struct mwMsgChannelSend *msg) { - - guint16_put(b, msg->type); - mwOpaque_put(b, &msg->data); -} - - -static void CHANNEL_SEND_get(struct mwGetBuffer *b, - struct mwMsgChannelSend *msg) { - - if(mwGetBuffer_error(b)) return; - - guint16_get(b, &msg->type); - mwOpaque_get(b, &msg->data); -} - - -static void CHANNEL_SEND_clear(struct mwMsgChannelSend *msg) { - mwOpaque_clear(&msg->data); -} - - -/* 8.4.1.10 DestroyCnl */ - - -static void CHANNEL_DESTROY_put(struct mwPutBuffer *b, - struct mwMsgChannelDestroy *msg) { - guint32_put(b, msg->reason); - mwOpaque_put(b, &msg->data); -} - - -static void CHANNEL_DESTROY_get(struct mwGetBuffer *b, - struct mwMsgChannelDestroy *msg) { - - if(mwGetBuffer_error(b)) return; - - guint32_get(b, &msg->reason); - mwOpaque_get(b, &msg->data); -} - - -static void CHANNEL_DESTROY_clear(struct mwMsgChannelDestroy *msg) { - mwOpaque_clear(&msg->data); -} - - -/* 8.4.1.11 SetUserStatus */ - - -static void SET_USER_STATUS_put(struct mwPutBuffer *b, - struct mwMsgSetUserStatus *msg) { - mwUserStatus_put(b, &msg->status); -} - - -static void SET_USER_STATUS_get(struct mwGetBuffer *b, - struct mwMsgSetUserStatus *msg) { - - if(mwGetBuffer_error(b)) return; - mwUserStatus_get(b, &msg->status); -} - - -static void SET_USER_STATUS_clear(struct mwMsgSetUserStatus *msg) { - mwUserStatus_clear(&msg->status); -} - - -/* 8.4.1.12 SetPrivacyList */ - - -static void SET_PRIVACY_LIST_put(struct mwPutBuffer *b, - struct mwMsgSetPrivacyList *msg) { - mwPrivacyInfo_put(b, &msg->privacy); -} - - -static void SET_PRIVACY_LIST_get(struct mwGetBuffer *b, - struct mwMsgSetPrivacyList *msg) { - - if(mwGetBuffer_error(b)) return; - mwPrivacyInfo_get(b, &msg->privacy); -} - - -static void SET_PRIVACY_LIST_clear(struct mwMsgSetPrivacyList *msg) { - mwPrivacyInfo_clear(&msg->privacy); -} - - -/* Sense Service messages */ - - -static void SENSE_SERVICE_put(struct mwPutBuffer *b, - struct mwMsgSenseService *msg) { - guint32_put(b, msg->service); -} - - -static void SENSE_SERVICE_get(struct mwGetBuffer *b, - struct mwMsgSenseService *msg) { - - if(mwGetBuffer_error(b)) return; - guint32_get(b, &msg->service); -} - - -static void SENSE_SERVICE_clear(struct mwMsgSenseService *msg) { - ; -} - - -/* Admin messages */ - - -static void ADMIN_get(struct mwGetBuffer *b, struct mwMsgAdmin *msg) { - mwString_get(b, &msg->text); -} - - -static void ADMIN_clear(struct mwMsgAdmin *msg) { - g_free(msg->text); - msg->text = NULL; -} - - -/* Announcement messages */ - - -static void ANNOUNCE_get(struct mwGetBuffer *b, struct mwMsgAnnounce *msg) { - struct mwOpaque o = { 0, 0 }; - struct mwGetBuffer *gb; - guint32 count; - - gboolean_get(b, &msg->sender_present); - if(msg->sender_present) - mwLoginInfo_get(b, &msg->sender); - guint16_get(b, &msg->unknown_a); - - mwOpaque_get(b, &o); - gb = mwGetBuffer_wrap(&o); - - gboolean_get(gb, &msg->may_reply); - mwString_get(gb, &msg->text); - - mwGetBuffer_free(gb); - mwOpaque_clear(&o); - - guint32_get(b, &count); - while(count--) { - char *r = NULL; - mwString_get(b, &r); - msg->recipients = g_list_prepend(msg->recipients, r); - } -} - - -static void ANNOUNCE_put(struct mwPutBuffer *b, struct mwMsgAnnounce *msg) { - struct mwOpaque o = { 0, 0 }; - struct mwPutBuffer *pb; - GList *l; - - gboolean_put(b, msg->sender_present); - if(msg->sender_present) - mwLoginInfo_put(b, &msg->sender); - guint16_put(b, msg->unknown_a); - - pb = mwPutBuffer_new(); - - gboolean_put(pb, msg->may_reply); - mwString_put(pb, msg->text); - - mwPutBuffer_finalize(&o, pb); - mwOpaque_put(b, &o); - mwOpaque_clear(&o); - - guint32_put(b, g_list_length(msg->recipients)); - for(l = msg->recipients; l; l = l->next) { - mwString_put(b, l->data); - } -} - - -static void ANNOUNCE_clear(struct mwMsgAnnounce *msg) { - mwLoginInfo_clear(&msg->sender); - - g_free(msg->text); - msg->text = NULL; - - while(msg->recipients) { - g_free(msg->recipients->data); - msg->recipients = g_list_delete_link(msg->recipients, msg->recipients); - } -} - - -/* general functions */ - - -#define CASE(v, t) \ -case mwMessage_ ## v: \ - msg = (struct mwMessage *) g_new0(struct t, 1); \ - msg->type = type; \ - break; - - -struct mwMessage *mwMessage_new(enum mwMessageType type) { - struct mwMessage *msg = NULL; - - switch(type) { - CASE(HANDSHAKE, mwMsgHandshake); - CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); - CASE(LOGIN, mwMsgLogin); - CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); - CASE(LOGIN_CONTINUE, mwMsgLoginContinue); - CASE(LOGIN_ACK, mwMsgLoginAck); - CASE(CHANNEL_CREATE, mwMsgChannelCreate); - CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); - CASE(CHANNEL_SEND, mwMsgChannelSend); - CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); - CASE(SET_USER_STATUS, mwMsgSetUserStatus); - CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); - CASE(SENSE_SERVICE, mwMsgSenseService); - CASE(ADMIN, mwMsgAdmin); - CASE(ANNOUNCE, mwMsgAnnounce); - - default: - g_warning("unknown message type 0x%02x\n", type); - } - - return msg; -} - - -#undef CASE - - -/* each type needs to be passed to a specially named _get functions, - and cast to a specific subclass of mwMessage. */ -#define CASE(v, t) \ -case mwMessage_ ## v: \ - msg = (struct mwMessage *) g_new0(struct t, 1); \ - mwMessageHead_clone(msg, &head); \ - v ## _get(b, (struct t *) msg); \ - break; - - -struct mwMessage *mwMessage_get(struct mwGetBuffer *b) { - struct mwMessage *msg = NULL; - struct mwMessage head; - - g_return_val_if_fail(b != NULL, NULL); - - head.attribs.len = 0; - head.attribs.data = NULL; - - /* attempt to read the header first */ - mwMessageHead_get(b, &head); - - if(mwGetBuffer_error(b)) { - mwMessageHead_clear(&head); - g_warning("problem parsing message head from buffer"); - return NULL; - } - - /* load the rest of the message depending on the header type */ - switch(head.type) { - CASE(HANDSHAKE, mwMsgHandshake); - CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); - CASE(LOGIN, mwMsgLogin); - CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); - CASE(LOGIN_CONTINUE, mwMsgLoginContinue); - CASE(LOGIN_ACK, mwMsgLoginAck); - CASE(CHANNEL_CREATE, mwMsgChannelCreate); - CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); - CASE(CHANNEL_SEND, mwMsgChannelSend); - CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); - CASE(SET_USER_STATUS, mwMsgSetUserStatus); - CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); - CASE(SENSE_SERVICE, mwMsgSenseService); - CASE(ADMIN, mwMsgAdmin); - CASE(ANNOUNCE, mwMsgAnnounce); - - default: - g_warning("unknown message type 0x%02x, no parse handler", head.type); - } - - if(mwGetBuffer_error(b)) { - g_warning("problem parsing message type 0x%02x, not enough data", - head.type); - } - - mwMessageHead_clear(&head); - - return msg; -} - - -#undef CASE - - -#define CASE(v, t) \ -case mwMessage_ ## v: \ - v ## _put(b, (struct t *) msg); \ - break; - - -void mwMessage_put(struct mwPutBuffer *b, struct mwMessage *msg) { - - g_return_if_fail(b != NULL); - g_return_if_fail(msg != NULL); - - mwMessageHead_put(b, msg); - - switch(msg->type) { - CASE(HANDSHAKE, mwMsgHandshake); - CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); - CASE(LOGIN, mwMsgLogin); - CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); - CASE(LOGIN_CONTINUE, mwMsgLoginContinue); - CASE(CHANNEL_CREATE, mwMsgChannelCreate); - CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); - CASE(CHANNEL_SEND, mwMsgChannelSend); - CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); - CASE(SET_USER_STATUS, mwMsgSetUserStatus); - CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); - CASE(SENSE_SERVICE, mwMsgSenseService); - CASE(ANNOUNCE, mwMsgAnnounce); - - default: - ; /* hrm. */ - } -} - - -#undef CASE - - -#define CASE(v, t) \ -case mwMessage_ ## v: \ - v ## _clear((struct t *) msg); \ - break; - - -void mwMessage_free(struct mwMessage *msg) { - if(! msg) return; - - mwMessageHead_clear(msg); - - switch(msg->type) { - CASE(HANDSHAKE, mwMsgHandshake); - CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); - CASE(LOGIN, mwMsgLogin); - CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); - CASE(LOGIN_CONTINUE, mwMsgLoginContinue); - CASE(LOGIN_ACK, mwMsgLoginAck); - CASE(CHANNEL_CREATE, mwMsgChannelCreate); - CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); - CASE(CHANNEL_SEND, mwMsgChannelSend); - CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); - CASE(SET_USER_STATUS, mwMsgSetUserStatus); - CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); - CASE(SENSE_SERVICE, mwMsgSenseService); - CASE(ADMIN, mwMsgAdmin); - CASE(ANNOUNCE, mwMsgAnnounce); - - default: - ; /* hrm. */ - } - - g_free(msg); -} - - -#undef CASE - - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mpi/.cvsignore --- a/src/protocols/sametime/meanwhile/mpi/.cvsignore Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -Makefile -Makefile.in -.deps -.libs -*.la -*.lo diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mpi/Makefile.am --- a/src/protocols/sametime/meanwhile/mpi/Makefile.am Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ - -noinst_LTLIBRARIES = libmpi.la - -libmpi_la_SOURCES = mpi.c - -noinst_HEADERS = logtab.h mpi-config.h mpi.h mpi-types.h - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mpi/logtab.h --- a/src/protocols/sametime/meanwhile/mpi/logtab.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -const double s_logv_2[] = { - 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ - 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ - 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ - 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ - 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ - 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ - 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ - 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ - 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ - 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ - 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ - 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ - 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ - 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ - 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ - 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ - 0.166666667 -}; - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mpi/mpi-config.h --- a/src/protocols/sametime/meanwhile/mpi/mpi-config.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* Default configuration for MPI library */ -/* $Id: mpi-config.h 14563 2005-11-29 23:31:40Z taliesein $ */ - -#ifndef MPI_CONFIG_H_ -#define MPI_CONFIG_H_ - -/* - For boolean options, - 0 = no - 1 = yes - - Other options are documented individually. - - */ - -#ifndef MP_IOFUNC -#define MP_IOFUNC 0 /* include mp_print() ? */ -#endif - -#ifndef MP_MODARITH -#define MP_MODARITH 1 /* include modular arithmetic ? */ -#endif - -#ifndef MP_NUMTH -#define MP_NUMTH 1 /* include number theoretic functions? */ -#endif - -#ifndef MP_LOGTAB -#define MP_LOGTAB 1 /* use table of logs instead of log()? */ -#endif - -#ifndef MP_MEMSET -#define MP_MEMSET 1 /* use memset() to zero buffers? */ -#endif - -#ifndef MP_MEMCPY -#define MP_MEMCPY 1 /* use memcpy() to copy buffers? */ -#endif - -#ifndef MP_CRYPTO -#define MP_CRYPTO 0 /* erase memory on free? */ -#endif - -#ifndef MP_ARGCHK -/* - 0 = no parameter checks - 1 = runtime checks, continue execution and return an error to caller - 2 = assertions; dump core on parameter errors - */ -#define MP_ARGCHK 2 /* how to check input arguments */ -#endif - -#ifndef MP_DEBUG -#define MP_DEBUG 0 /* print diagnostic output? */ -#endif - -#ifndef MP_DEFPREC -#define MP_DEFPREC 16 /* default precision, in digits */ -#endif - -#ifndef MP_MACRO -#define MP_MACRO 1 /* use macros for frequent calls? */ -#endif - -#ifndef MP_SQUARE -#define MP_SQUARE 1 /* use separate squaring code? */ -#endif - -#ifndef MP_PTAB_SIZE -/* - When building mpprime.c, we build in a table of small prime - values to use for primality testing. The more you include, - the more space they take up. See primes.c for the possible - values (currently 16, 32, 64, 128, 256, and 6542) - */ -#define MP_PTAB_SIZE 128 /* how many built-in primes? */ -#endif - -#ifndef MP_COMPAT_MACROS -#define MP_COMPAT_MACROS 0 /* define compatibility macros? */ -#endif - -#endif /* ifndef MPI_CONFIG_H_ */ - - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mpi/mpi-types.h --- a/src/protocols/sametime/meanwhile/mpi/mpi-types.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -/* Type definitions generated by 'types.pl' */ - -typedef char mp_sign; -typedef unsigned short mp_digit; /* 2 byte type */ -typedef unsigned int mp_word; /* 4 byte type */ -typedef unsigned int mp_size; -typedef int mp_err; - -#define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit)) -#define MP_DIGIT_MAX USHRT_MAX -#define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word)) -#define MP_WORD_MAX UINT_MAX - -#define RADIX (MP_DIGIT_MAX+1) - -#define MP_DIGIT_SIZE 2 -#define DIGIT_FMT "%04X" diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mpi/mpi.c --- a/src/protocols/sametime/meanwhile/mpi/mpi.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4001 +0,0 @@ -/* - mpi.c - - by Michael J. Fromberger - Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved - - Arbitrary precision integer arithmetic library - - $Id: mpi.c 14563 2005-11-29 23:31:40Z taliesein $ - */ - -#include "mpi.h" -#include -#include -#include - -#if MP_DEBUG -#include - -#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);} -#else -#define DIAG(T,V) -#endif - -/* - If MP_LOGTAB is not defined, use the math library to compute the - logarithms on the fly. Otherwise, use the static table below. - Pick which works best for your system. - */ -#if MP_LOGTAB - -/* {{{ s_logv_2[] - log table for 2 in various bases */ - -/* - A table of the logs of 2 for various bases (the 0 and 1 entries of - this table are meaningless and should not be referenced). - - This table is used to compute output lengths for the mp_toradix() - function. Since a number n in radix r takes up about log_r(n) - digits, we estimate the output size by taking the least integer - greater than log_r(n), where: - - log_r(n) = log_2(n) * log_r(2) - - This table, therefore, is a table of log_r(2) for 2 <= r <= 36, - which are the output bases supported. - */ - -#include "logtab.h" - -/* }}} */ -#define LOG_V_2(R) s_logv_2[(R)] - -#else - -#include -#define LOG_V_2(R) (log(2.0)/log(R)) - -#endif - -/* Default precision for newly created mp_int's */ -static unsigned int s_mp_defprec = MP_DEFPREC; - -/* {{{ Digit arithmetic macros */ - -/* - When adding and multiplying digits, the results can be larger than - can be contained in an mp_digit. Thus, an mp_word is used. These - macros mask off the upper and lower digits of the mp_word (the - mp_word may be more than 2 mp_digits wide, but we only concern - ourselves with the low-order 2 mp_digits) - - If your mp_word DOES have more than 2 mp_digits, you need to - uncomment the first line, and comment out the second. - */ - -/* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */ -#define CARRYOUT(W) ((W)>>DIGIT_BIT) -#define ACCUM(W) ((W)&MP_DIGIT_MAX) - -/* }}} */ - -/* {{{ Comparison constants */ - -#define MP_LT -1 -#define MP_EQ 0 -#define MP_GT 1 - -/* }}} */ - -/* {{{ Constant strings */ - -/* Constant strings returned by mp_strerror() */ -static const char *mp_err_string[] = { - "unknown result code", /* say what? */ - "boolean true", /* MP_OKAY, MP_YES */ - "boolean false", /* MP_NO */ - "out of memory", /* MP_MEM */ - "argument out of range", /* MP_RANGE */ - "invalid input parameter", /* MP_BADARG */ - "result is undefined" /* MP_UNDEF */ -}; - -/* Value to digit maps for radix conversion */ - -/* s_dmap_1 - standard digits and letters */ -static const char *s_dmap_1 = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; - -#if 0 -/* s_dmap_2 - base64 ordering for digits */ -static const char *s_dmap_2 = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -#endif - -/* }}} */ - -/* {{{ Static function declarations */ - -/* - If MP_MACRO is false, these will be defined as actual functions; - otherwise, suitable macro definitions will be used. This works - around the fact that ANSI C89 doesn't support an 'inline' keyword - (although I hear C9x will ... about bloody time). At present, the - macro definitions are identical to the function bodies, but they'll - expand in place, instead of generating a function call. - - I chose these particular functions to be made into macros because - some profiling showed they are called a lot on a typical workload, - and yet they are primarily housekeeping. - */ -#if MP_MACRO == 0 - void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */ - void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */ - void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */ - void s_mp_free(void *ptr); /* general free function */ -#else - - /* Even if these are defined as macros, we need to respect the settings - of the MP_MEMSET and MP_MEMCPY configuration options... - */ - #if MP_MEMSET == 0 - #define s_mp_setz(dp, count) \ - {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} - #else - #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit)) - #endif /* MP_MEMSET */ - - #if MP_MEMCPY == 0 - #define s_mp_copy(sp, dp, count) \ - {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} - #else - #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) - #endif /* MP_MEMCPY */ - - #define s_mp_alloc(nb, ni) calloc(nb, ni) - #define s_mp_free(ptr) {if(ptr) free(ptr);} -#endif /* MP_MACRO */ - -mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */ -mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */ - -void s_mp_clamp(mp_int *mp); /* clip leading zeroes */ - -void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */ - -mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */ -void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */ -void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */ -void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */ -mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/ -void s_mp_div_2(mp_int *mp); /* divide by 2 in place */ -mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */ -mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */ -mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */ -mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */ -mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */ -mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r); - /* unsigned digit divide */ -mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu); - /* Barrett reduction */ -mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */ -mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */ -mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */ -#if 0 -void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len); - /* multiply buffers in place */ -#endif -#if MP_SQUARE -mp_err s_mp_sqr(mp_int *a); /* magnitude square */ -#else -#define s_mp_sqr(a) s_mp_mul(a, a) -#endif -mp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */ -mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */ -int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */ -int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */ -int s_mp_ispow2(mp_int *v); /* is v a power of 2? */ -int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */ - -int s_mp_tovalue(char ch, int r); /* convert ch to value */ -char s_mp_todigit(int val, int r, int low); /* convert val to digit */ -int s_mp_outlen(int bits, int r); /* output length in bytes */ - -/* }}} */ - -/* {{{ Default precision manipulation */ - -unsigned int mp_get_prec(void) -{ - return s_mp_defprec; - -} /* end mp_get_prec() */ - -void mp_set_prec(unsigned int prec) -{ - if(prec == 0) - s_mp_defprec = MP_DEFPREC; - else - s_mp_defprec = prec; - -} /* end mp_set_prec() */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ mp_init(mp) */ - -/* - mp_init(mp) - - Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, - MP_MEM if memory could not be allocated for the structure. - */ - -mp_err mp_init(mp_int *mp) -{ - return mp_init_size(mp, s_mp_defprec); - -} /* end mp_init() */ - -/* }}} */ - -/* {{{ mp_init_array(mp[], count) */ - -mp_err mp_init_array(mp_int mp[], int count) -{ - mp_err res; - int pos; - - ARGCHK(mp !=NULL && count > 0, MP_BADARG); - - for(pos = 0; pos < count; ++pos) { - if((res = mp_init(&mp[pos])) != MP_OKAY) - goto CLEANUP; - } - - return MP_OKAY; - - CLEANUP: - while(--pos >= 0) - mp_clear(&mp[pos]); - - return res; - -} /* end mp_init_array() */ - -/* }}} */ - -/* {{{ mp_init_size(mp, prec) */ - -/* - mp_init_size(mp, prec) - - Initialize a new zero-valued mp_int with at least the given - precision; returns MP_OKAY if successful, or MP_MEM if memory could - not be allocated for the structure. - */ - -mp_err mp_init_size(mp_int *mp, mp_size prec) -{ - ARGCHK(mp != NULL && prec > 0, MP_BADARG); - - if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) - return MP_MEM; - - SIGN(mp) = MP_ZPOS; - USED(mp) = 1; - ALLOC(mp) = prec; - - return MP_OKAY; - -} /* end mp_init_size() */ - -/* }}} */ - -/* {{{ mp_init_copy(mp, from) */ - -/* - mp_init_copy(mp, from) - - Initialize mp as an exact copy of from. Returns MP_OKAY if - successful, MP_MEM if memory could not be allocated for the new - structure. - */ - -mp_err mp_init_copy(mp_int *mp, mp_int *from) -{ - ARGCHK(mp != NULL && from != NULL, MP_BADARG); - - if(mp == from) - return MP_OKAY; - - if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); - USED(mp) = USED(from); - ALLOC(mp) = USED(from); - SIGN(mp) = SIGN(from); - - return MP_OKAY; - -} /* end mp_init_copy() */ - -/* }}} */ - -/* {{{ mp_copy(from, to) */ - -/* - mp_copy(from, to) - - Copies the mp_int 'from' to the mp_int 'to'. It is presumed that - 'to' has already been initialized (if not, use mp_init_copy() - instead). If 'from' and 'to' are identical, nothing happens. - */ - -mp_err mp_copy(mp_int *from, mp_int *to) -{ - ARGCHK(from != NULL && to != NULL, MP_BADARG); - - if(from == to) - return MP_OKAY; - - { /* copy */ - mp_digit *tmp; - - /* - If the allocated buffer in 'to' already has enough space to hold - all the used digits of 'from', we'll re-use it to avoid hitting - the memory allocater more than necessary; otherwise, we'd have - to grow anyway, so we just allocate a hunk and make the copy as - usual - */ - if(ALLOC(to) >= USED(from)) { - s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); - s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); - - } else { - if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(from), tmp, USED(from)); - - if(DIGITS(to) != NULL) { -#if MP_CRYPTO - s_mp_setz(DIGITS(to), ALLOC(to)); -#endif - s_mp_free(DIGITS(to)); - } - - DIGITS(to) = tmp; - ALLOC(to) = USED(from); - } - - /* Copy the precision and sign from the original */ - USED(to) = USED(from); - SIGN(to) = SIGN(from); - } /* end copy */ - - return MP_OKAY; - -} /* end mp_copy() */ - -/* }}} */ - -/* {{{ mp_exch(mp1, mp2) */ - -/* - mp_exch(mp1, mp2) - - Exchange mp1 and mp2 without allocating any intermediate memory - (well, unless you count the stack space needed for this call and the - locals it creates...). This cannot fail. - */ - -void mp_exch(mp_int *mp1, mp_int *mp2) -{ -#if MP_ARGCHK == 2 - assert(mp1 != NULL && mp2 != NULL); -#else - if(mp1 == NULL || mp2 == NULL) - return; -#endif - - s_mp_exch(mp1, mp2); - -} /* end mp_exch() */ - -/* }}} */ - -/* {{{ mp_clear(mp) */ - -/* - mp_clear(mp) - - Release the storage used by an mp_int, and void its fields so that - if someone calls mp_clear() again for the same int later, we won't - get tollchocked. - */ - -void mp_clear(mp_int *mp) -{ - if(mp == NULL) - return; - - if(DIGITS(mp) != NULL) { -#if MP_CRYPTO - s_mp_setz(DIGITS(mp), ALLOC(mp)); -#endif - s_mp_free(DIGITS(mp)); - DIGITS(mp) = NULL; - } - - USED(mp) = 0; - ALLOC(mp) = 0; - -} /* end mp_clear() */ - -/* }}} */ - -/* {{{ mp_clear_array(mp[], count) */ - -void mp_clear_array(mp_int mp[], int count) -{ - ARGCHK(mp != NULL && count > 0, MP_BADARG); - - while(--count >= 0) - mp_clear(&mp[count]); - -} /* end mp_clear_array() */ - -/* }}} */ - -/* {{{ mp_zero(mp) */ - -/* - mp_zero(mp) - - Set mp to zero. Does not change the allocated size of the structure, - and therefore cannot fail (except on a bad argument, which we ignore) - */ -void mp_zero(mp_int *mp) -{ - if(mp == NULL) - return; - - s_mp_setz(DIGITS(mp), ALLOC(mp)); - USED(mp) = 1; - SIGN(mp) = MP_ZPOS; - -} /* end mp_zero() */ - -/* }}} */ - -/* {{{ mp_set(mp, d) */ - -void mp_set(mp_int *mp, mp_digit d) -{ - if(mp == NULL) - return; - - mp_zero(mp); - DIGIT(mp, 0) = d; - -} /* end mp_set() */ - -/* }}} */ - -/* {{{ mp_set_int(mp, z) */ - -mp_err mp_set_int(mp_int *mp, long z) -{ - int ix; - unsigned long v = abs(z); - mp_err res; - - ARGCHK(mp != NULL, MP_BADARG); - - mp_zero(mp); - if(z == 0) - return MP_OKAY; /* shortcut for zero */ - - for(ix = sizeof(long) - 1; ix >= 0; ix--) { - - if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) - return res; - - res = s_mp_add_d(mp, - (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); - if(res != MP_OKAY) - return res; - - } - - if(z < 0) - SIGN(mp) = MP_NEG; - - return MP_OKAY; - -} /* end mp_set_int() */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Digit arithmetic */ - -/* {{{ mp_add_d(a, d, b) */ - -/* - mp_add_d(a, d, b) - - Compute the sum b = a + d, for a single digit d. Respects the sign of - its primary addend (single digits are unsigned anyway). - */ - -mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res = MP_OKAY; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(SIGN(b) == MP_ZPOS) { - res = s_mp_add_d(b, d); - } else if(s_mp_cmp_d(b, d) >= 0) { - res = s_mp_sub_d(b, d); - } else { - SIGN(b) = MP_ZPOS; - - DIGIT(b, 0) = d - DIGIT(b, 0); - } - - return res; - -} /* end mp_add_d() */ - -/* }}} */ - -/* {{{ mp_sub_d(a, d, b) */ - -/* - mp_sub_d(a, d, b) - - Compute the difference b = a - d, for a single digit d. Respects the - sign of its subtrahend (single digits are unsigned anyway). - */ - -mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(SIGN(b) == MP_NEG) { - if((res = s_mp_add_d(b, d)) != MP_OKAY) - return res; - - } else if(s_mp_cmp_d(b, d) >= 0) { - if((res = s_mp_sub_d(b, d)) != MP_OKAY) - return res; - - } else { - mp_neg(b, b); - - DIGIT(b, 0) = d - DIGIT(b, 0); - SIGN(b) = MP_NEG; - } - - if(s_mp_cmp_d(b, 0) == 0) - SIGN(b) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_sub_d() */ - -/* }}} */ - -/* {{{ mp_mul_d(a, d, b) */ - -/* - mp_mul_d(a, d, b) - - Compute the product b = a * d, for a single digit d. Respects the sign - of its multiplicand (single digits are unsigned anyway) - */ - -mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if(d == 0) { - mp_zero(b); - return MP_OKAY; - } - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - res = s_mp_mul_d(b, d); - - return res; - -} /* end mp_mul_d() */ - -/* }}} */ - -/* {{{ mp_mul_2(a, c) */ - -mp_err mp_mul_2(mp_int *a, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - return s_mp_mul_2(c); - -} /* end mp_mul_2() */ - -/* }}} */ - -/* {{{ mp_div_d(a, d, q, r) */ - -/* - mp_div_d(a, d, q, r) - - Compute the quotient q = a / d and remainder r = a mod d, for a - single digit d. Respects the sign of its divisor (single digits are - unsigned anyway). - */ - -mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r) -{ - mp_err res; - mp_digit rem; - int pow; - - ARGCHK(a != NULL, MP_BADARG); - - if(d == 0) - return MP_RANGE; - - /* Shortcut for powers of two ... */ - if((pow = s_mp_ispow2d(d)) >= 0) { - mp_digit mask; - - mask = (1 << pow) - 1; - rem = DIGIT(a, 0) & mask; - - if(q) { - mp_copy(a, q); - s_mp_div_2d(q, pow); - } - - if(r) - *r = rem; - - return MP_OKAY; - } - - /* - If the quotient is actually going to be returned, we'll try to - avoid hitting the memory allocator by copying the dividend into it - and doing the division there. This can't be any _worse_ than - always copying, and will sometimes be better (since it won't make - another copy) - - If it's not going to be returned, we need to allocate a temporary - to hold the quotient, which will just be discarded. - */ - if(q) { - if((res = mp_copy(a, q)) != MP_OKAY) - return res; - - res = s_mp_div_d(q, d, &rem); - if(s_mp_cmp_d(q, 0) == MP_EQ) - SIGN(q) = MP_ZPOS; - - } else { - mp_int qp; - - if((res = mp_init_copy(&qp, a)) != MP_OKAY) - return res; - - res = s_mp_div_d(&qp, d, &rem); - if(s_mp_cmp_d(&qp, 0) == 0) - SIGN(&qp) = MP_ZPOS; - - mp_clear(&qp); - } - - if(r) - *r = rem; - - return res; - -} /* end mp_div_d() */ - -/* }}} */ - -/* {{{ mp_div_2(a, c) */ - -/* - mp_div_2(a, c) - - Compute c = a / 2, disregarding the remainder. - */ - -mp_err mp_div_2(mp_int *a, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - s_mp_div_2(c); - - return MP_OKAY; - -} /* end mp_div_2() */ - -/* }}} */ - -/* {{{ mp_expt_d(a, d, b) */ - -mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c) -{ - mp_int s, x; - mp_err res; - mp_sign cs = MP_ZPOS; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_init(&s)) != MP_OKAY) - return res; - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - DIGIT(&s, 0) = 1; - - if((d % 2) == 1) - cs = SIGN(a); - - while(d != 0) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - - SIGN(&s) = cs; - - s_mp_exch(&s, c); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); - - return res; - -} /* end mp_expt_d() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Full arithmetic */ - -/* {{{ mp_abs(a, b) */ - -/* - mp_abs(a, b) - - Compute b = |a|. 'a' and 'b' may be identical. - */ - -mp_err mp_abs(mp_int *a, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - SIGN(b) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_abs() */ - -/* }}} */ - -/* {{{ mp_neg(a, b) */ - -/* - mp_neg(a, b) - - Compute b = -a. 'a' and 'b' may be identical. - */ - -mp_err mp_neg(mp_int *a, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(s_mp_cmp_d(b, 0) == MP_EQ) - SIGN(b) = MP_ZPOS; - else - SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; - - return MP_OKAY; - -} /* end mp_neg() */ - -/* }}} */ - -/* {{{ mp_add(a, b, c) */ - -/* - mp_add(a, b, c) - - Compute c = a + b. All parameters may be identical. - */ - -mp_err mp_add(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - int cmp; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ - - /* Commutativity of addition lets us do this in either order, - so we avoid having to use a temporary even if the result - is supposed to replace the output - */ - if(c == b) { - if((res = s_mp_add(c, a)) != MP_OKAY) - return res; - } else { - if(c != a && (res = mp_copy(a, c)) != MP_OKAY) - return res; - - if((res = s_mp_add(c, b)) != MP_OKAY) - return res; - } - - } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */ - - /* If the output is going to be clobbered, we will use a temporary - variable; otherwise, we'll do it without touching the memory - allocator at all, if possible - */ - if(c == b) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, a)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - - if(c != a && (res = mp_copy(a, c)) != MP_OKAY) - return res; - if((res = s_mp_sub(c, b)) != MP_OKAY) - return res; - - } - - } else if(cmp == 0) { /* different sign, a == b */ - - mp_zero(c); - return MP_OKAY; - - } else { /* different sign: a < b */ - - /* See above... */ - if(c == a) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, b)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - - if(c != b && (res = mp_copy(b, c)) != MP_OKAY) - return res; - if((res = s_mp_sub(c, a)) != MP_OKAY) - return res; - - } - } - - if(USED(c) == 1 && DIGIT(c, 0) == 0) - SIGN(c) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_add() */ - -/* }}} */ - -/* {{{ mp_sub(a, b, c) */ - -/* - mp_sub(a, b, c) - - Compute c = a - b. All parameters may be identical. - */ - -mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - int cmp; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(SIGN(a) != SIGN(b)) { - if(c == a) { - if((res = s_mp_add(c, b)) != MP_OKAY) - return res; - } else { - if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) - return res; - if((res = s_mp_add(c, a)) != MP_OKAY) - return res; - SIGN(c) = SIGN(a); - } - - } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ - if(c == b) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, a)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - if(c != a && ((res = mp_copy(a, c)) != MP_OKAY)) - return res; - - if((res = s_mp_sub(c, b)) != MP_OKAY) - return res; - } - - } else if(cmp == 0) { /* Same sign, equal magnitude */ - mp_zero(c); - return MP_OKAY; - - } else { /* Same sign, b > a */ - if(c == a) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, b)) != MP_OKAY) - return res; - - if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) - return res; - - if((res = s_mp_sub(c, a)) != MP_OKAY) - return res; - } - - SIGN(c) = !SIGN(b); - } - - if(USED(c) == 1 && DIGIT(c, 0) == 0) - SIGN(c) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_sub() */ - -/* }}} */ - -/* {{{ mp_mul(a, b, c) */ - -/* - mp_mul(a, b, c) - - Compute c = a * b. All parameters may be identical. - */ - -mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - mp_sign sgn; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; - - if(c == b) { - if((res = s_mp_mul(c, a)) != MP_OKAY) - return res; - - } else { - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - if((res = s_mp_mul(c, b)) != MP_OKAY) - return res; - } - - if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ) - SIGN(c) = MP_ZPOS; - else - SIGN(c) = sgn; - - return MP_OKAY; - -} /* end mp_mul() */ - -/* }}} */ - -/* {{{ mp_mul_2d(a, d, c) */ - -/* - mp_mul_2d(a, d, c) - - Compute c = a * 2^d. a may be the same as c. - */ - -mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - if(d == 0) - return MP_OKAY; - - return s_mp_mul_2d(c, d); - -} /* end mp_mul() */ - -/* }}} */ - -/* {{{ mp_sqr(a, b) */ - -#if MP_SQUARE -mp_err mp_sqr(mp_int *a, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if((res = s_mp_sqr(b)) != MP_OKAY) - return res; - - SIGN(b) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_sqr() */ -#endif - -/* }}} */ - -/* {{{ mp_div(a, b, q, r) */ - -/* - mp_div(a, b, q, r) - - Compute q = a / b and r = a mod b. Input parameters may be re-used - as output parameters. If q or r is NULL, that portion of the - computation will be discarded (although it will still be computed) - - Pay no attention to the hacker behind the curtain. - */ - -mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r) -{ - mp_err res; - mp_int qtmp, rtmp; - int cmp; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if(mp_cmp_z(b) == MP_EQ) - return MP_RANGE; - - /* If a <= b, we can compute the solution without division, and - avoid any memory allocation - */ - if((cmp = s_mp_cmp(a, b)) < 0) { - if(r) { - if((res = mp_copy(a, r)) != MP_OKAY) - return res; - } - - if(q) - mp_zero(q); - - return MP_OKAY; - - } else if(cmp == 0) { - - /* Set quotient to 1, with appropriate sign */ - if(q) { - int qneg = (SIGN(a) != SIGN(b)); - - mp_set(q, 1); - if(qneg) - SIGN(q) = MP_NEG; - } - - if(r) - mp_zero(r); - - return MP_OKAY; - } - - /* If we get here, it means we actually have to do some division */ - - /* Set up some temporaries... */ - if((res = mp_init_copy(&qtmp, a)) != MP_OKAY) - return res; - if((res = mp_init_copy(&rtmp, b)) != MP_OKAY) - goto CLEANUP; - - if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY) - goto CLEANUP; - - /* Compute the signs for the output */ - SIGN(&rtmp) = SIGN(a); /* Sr = Sa */ - if(SIGN(a) == SIGN(b)) - SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */ - else - SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */ - - if(s_mp_cmp_d(&qtmp, 0) == MP_EQ) - SIGN(&qtmp) = MP_ZPOS; - if(s_mp_cmp_d(&rtmp, 0) == MP_EQ) - SIGN(&rtmp) = MP_ZPOS; - - /* Copy output, if it is needed */ - if(q) - s_mp_exch(&qtmp, q); - - if(r) - s_mp_exch(&rtmp, r); - -CLEANUP: - mp_clear(&rtmp); - mp_clear(&qtmp); - - return res; - -} /* end mp_div() */ - -/* }}} */ - -/* {{{ mp_div_2d(a, d, q, r) */ - -mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r) -{ - mp_err res; - - ARGCHK(a != NULL, MP_BADARG); - - if(q) { - if((res = mp_copy(a, q)) != MP_OKAY) - return res; - - s_mp_div_2d(q, d); - } - - if(r) { - if((res = mp_copy(a, r)) != MP_OKAY) - return res; - - s_mp_mod_2d(r, d); - } - - return MP_OKAY; - -} /* end mp_div_2d() */ - -/* }}} */ - -/* {{{ mp_expt(a, b, c) */ - -/* - mp_expt(a, b, c) - - Compute c = a ** b, that is, raise a to the b power. Uses a - standard iterative square-and-multiply technique. - */ - -mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c) -{ - mp_int s, x; - mp_err res; - mp_digit d; - int dig, bit; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(mp_cmp_z(b) < 0) - return MP_RANGE; - - if((res = mp_init(&s)) != MP_OKAY) - return res; - - mp_set(&s, 1); - - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - /* Loop over low-order digits in ascending order */ - for(dig = 0; dig < (USED(b) - 1); dig++) { - d = DIGIT(b, dig); - - /* Loop over bits of each non-maximal digit */ - for(bit = 0; bit < DIGIT_BIT; bit++) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - } - - /* Consider now the last digit... */ - d = DIGIT(b, dig); - - while(d) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - - if(mp_iseven(b)) - SIGN(&s) = SIGN(a); - - res = mp_copy(&s, c); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); - - return res; - -} /* end mp_expt() */ - -/* }}} */ - -/* {{{ mp_2expt(a, k) */ - -/* Compute a = 2^k */ - -mp_err mp_2expt(mp_int *a, mp_digit k) -{ - ARGCHK(a != NULL, MP_BADARG); - - return s_mp_2expt(a, k); - -} /* end mp_2expt() */ - -/* }}} */ - -/* {{{ mp_mod(a, m, c) */ - -/* - mp_mod(a, m, c) - - Compute c = a (mod m). Result will always be 0 <= c < m. - */ - -mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_err res; - int mag; - - ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); - - if(SIGN(m) == MP_NEG) - return MP_RANGE; - - /* - If |a| > m, we need to divide to get the remainder and take the - absolute value. - - If |a| < m, we don't need to do any division, just copy and adjust - the sign (if a is negative). - - If |a| == m, we can simply set the result to zero. - - This order is intended to minimize the average path length of the - comparison chain on common workloads -- the most frequent cases are - that |a| != m, so we do those first. - */ - if((mag = s_mp_cmp(a, m)) > 0) { - if((res = mp_div(a, m, NULL, c)) != MP_OKAY) - return res; - - if(SIGN(c) == MP_NEG) { - if((res = mp_add(c, m, c)) != MP_OKAY) - return res; - } - - } else if(mag < 0) { - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - if(mp_cmp_z(a) < 0) { - if((res = mp_add(c, m, c)) != MP_OKAY) - return res; - - } - - } else { - mp_zero(c); - - } - - return MP_OKAY; - -} /* end mp_mod() */ - -/* }}} */ - -/* {{{ mp_mod_d(a, d, c) */ - -/* - mp_mod_d(a, d, c) - - Compute c = a (mod d). Result will always be 0 <= c < d - */ -mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c) -{ - mp_err res; - mp_digit rem; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if(s_mp_cmp_d(a, d) > 0) { - if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) - return res; - - } else { - if(SIGN(a) == MP_NEG) - rem = d - DIGIT(a, 0); - else - rem = DIGIT(a, 0); - } - - if(c) - *c = rem; - - return MP_OKAY; - -} /* end mp_mod_d() */ - -/* }}} */ - -/* {{{ mp_sqrt(a, b) */ - -/* - mp_sqrt(a, b) - - Compute the integer square root of a, and store the result in b. - Uses an integer-arithmetic version of Newton's iterative linear - approximation technique to determine this value; the result has the - following two properties: - - b^2 <= a - (b+1)^2 >= a - - It is a range error to pass a negative value. - */ -mp_err mp_sqrt(mp_int *a, mp_int *b) -{ - mp_int x, t; - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - /* Cannot take square root of a negative value */ - if(SIGN(a) == MP_NEG) - return MP_RANGE; - - /* Special cases for zero and one, trivial */ - if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) - return mp_copy(a, b); - - /* Initialize the temporaries we'll use below */ - if((res = mp_init_size(&t, USED(a))) != MP_OKAY) - return res; - - /* Compute an initial guess for the iteration as a itself */ - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - for(;;) { - /* t = (x * x) - a */ - mp_copy(&x, &t); /* can't fail, t is big enough for original x */ - if((res = mp_sqr(&t, &t)) != MP_OKAY || - (res = mp_sub(&t, a, &t)) != MP_OKAY) - goto CLEANUP; - - /* t = t / 2x */ - s_mp_mul_2(&x); - if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) - goto CLEANUP; - s_mp_div_2(&x); - - /* Terminate the loop, if the quotient is zero */ - if(mp_cmp_z(&t) == MP_EQ) - break; - - /* x = x - t */ - if((res = mp_sub(&x, &t, &x)) != MP_OKAY) - goto CLEANUP; - - } - - /* Copy result to output parameter */ - mp_sub_d(&x, 1, &x); - s_mp_exch(&x, b); - - CLEANUP: - mp_clear(&x); - X: - mp_clear(&t); - - return res; - -} /* end mp_sqrt() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Modular arithmetic */ - -#if MP_MODARITH -/* {{{ mp_addmod(a, b, m, c) */ - -/* - mp_addmod(a, b, m, c) - - Compute c = (a + b) mod m - */ - -mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_add(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_submod(a, b, m, c) */ - -/* - mp_submod(a, b, m, c) - - Compute c = (a - b) mod m - */ - -mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_sub(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_mulmod(a, b, m, c) */ - -/* - mp_mulmod(a, b, m, c) - - Compute c = (a * b) mod m - */ - -mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_mul(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_sqrmod(a, m, c) */ - -#if MP_SQUARE -mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_sqr(a, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} /* end mp_sqrmod() */ -#endif - -/* }}} */ - -/* {{{ mp_exptmod(a, b, m, c) */ - -/* - mp_exptmod(a, b, m, c) - - Compute c = (a ** b) mod m. Uses a standard square-and-multiply - method with modular reductions at each step. (This is basically the - same code as mp_expt(), except for the addition of the reductions) - - The modular reductions are done using Barrett's algorithm (see - s_mp_reduce() below for details) - */ - -mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_int s, x, mu; - mp_err res; - mp_digit d, *db = DIGITS(b); - mp_size ub = USED(b); - int dig, bit; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0) - return MP_RANGE; - - if((res = mp_init(&s)) != MP_OKAY) - return res; - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - if((res = mp_mod(&x, m, &x)) != MP_OKAY || - (res = mp_init(&mu)) != MP_OKAY) - goto MU; - - mp_set(&s, 1); - - /* mu = b^2k / m */ - s_mp_add_d(&mu, 1); - s_mp_lshd(&mu, 2 * USED(m)); - if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY) - goto CLEANUP; - - /* Loop over digits of b in ascending order, except highest order */ - for(dig = 0; dig < (ub - 1); dig++) { - d = *db++; - - /* Loop over the bits of the lower-order digits */ - for(bit = 0; bit < DIGIT_BIT; bit++) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - } - - /* Now do the last digit... */ - d = *db; - - while(d) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - - s_mp_exch(&s, c); - - CLEANUP: - mp_clear(&mu); - MU: - mp_clear(&x); - X: - mp_clear(&s); - - return res; - -} /* end mp_exptmod() */ - -/* }}} */ - -/* {{{ mp_exptmod_d(a, d, m, c) */ - -mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c) -{ - mp_int s, x; - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_init(&s)) != MP_OKAY) - return res; - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - mp_set(&s, 1); - - while(d != 0) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY || - (res = mp_mod(&s, m, &s)) != MP_OKAY) - goto CLEANUP; - } - - d /= 2; - - if((res = s_mp_sqr(&x)) != MP_OKAY || - (res = mp_mod(&x, m, &x)) != MP_OKAY) - goto CLEANUP; - } - - s_mp_exch(&s, c); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); - - return res; - -} /* end mp_exptmod_d() */ - -/* }}} */ -#endif /* if MP_MODARITH */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Comparison functions */ - -/* {{{ mp_cmp_z(a) */ - -/* - mp_cmp_z(a) - - Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. - */ - -int mp_cmp_z(mp_int *a) -{ - if(SIGN(a) == MP_NEG) - return MP_LT; - else if(USED(a) == 1 && DIGIT(a, 0) == 0) - return MP_EQ; - else - return MP_GT; - -} /* end mp_cmp_z() */ - -/* }}} */ - -/* {{{ mp_cmp_d(a, d) */ - -/* - mp_cmp_d(a, d) - - Compare a <=> d. Returns <0 if a0 if a>d - */ - -int mp_cmp_d(mp_int *a, mp_digit d) -{ - ARGCHK(a != NULL, MP_EQ); - - if(SIGN(a) == MP_NEG) - return MP_LT; - - return s_mp_cmp_d(a, d); - -} /* end mp_cmp_d() */ - -/* }}} */ - -/* {{{ mp_cmp(a, b) */ - -int mp_cmp(mp_int *a, mp_int *b) -{ - ARGCHK(a != NULL && b != NULL, MP_EQ); - - if(SIGN(a) == SIGN(b)) { - int mag; - - if((mag = s_mp_cmp(a, b)) == MP_EQ) - return MP_EQ; - - if(SIGN(a) == MP_ZPOS) - return mag; - else - return -mag; - - } else if(SIGN(a) == MP_ZPOS) { - return MP_GT; - } else { - return MP_LT; - } - -} /* end mp_cmp() */ - -/* }}} */ - -/* {{{ mp_cmp_mag(a, b) */ - -/* - mp_cmp_mag(a, b) - - Compares |a| <=> |b|, and returns an appropriate comparison result - */ - -int mp_cmp_mag(mp_int *a, mp_int *b) -{ - ARGCHK(a != NULL && b != NULL, MP_EQ); - - return s_mp_cmp(a, b); - -} /* end mp_cmp_mag() */ - -/* }}} */ - -/* {{{ mp_cmp_int(a, z) */ - -/* - This just converts z to an mp_int, and uses the existing comparison - routines. This is sort of inefficient, but it's not clear to me how - frequently this wil get used anyway. For small positive constants, - you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). - */ -int mp_cmp_int(mp_int *a, long z) -{ - mp_int tmp; - int out; - - ARGCHK(a != NULL, MP_EQ); - - mp_init(&tmp); mp_set_int(&tmp, z); - out = mp_cmp(a, &tmp); - mp_clear(&tmp); - - return out; - -} /* end mp_cmp_int() */ - -/* }}} */ - -/* {{{ mp_isodd(a) */ - -/* - mp_isodd(a) - - Returns a true (non-zero) value if a is odd, false (zero) otherwise. - */ -int mp_isodd(mp_int *a) -{ - ARGCHK(a != NULL, 0); - - return (DIGIT(a, 0) & 1); - -} /* end mp_isodd() */ - -/* }}} */ - -/* {{{ mp_iseven(a) */ - -int mp_iseven(mp_int *a) -{ - return !mp_isodd(a); - -} /* end mp_iseven() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Number theoretic functions */ - -#if MP_NUMTH -/* {{{ mp_gcd(a, b, c) */ - -/* - Like the old mp_gcd() function, except computes the GCD using the - binary algorithm due to Josef Stein in 1961 (via Knuth). - */ -mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - mp_int u, v, t; - mp_size k = 0; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) - return MP_RANGE; - if(mp_cmp_z(a) == MP_EQ) { - if((res = mp_copy(b, c)) != MP_OKAY) - return res; - SIGN(c) = MP_ZPOS; return MP_OKAY; - } else if(mp_cmp_z(b) == MP_EQ) { - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - SIGN(c) = MP_ZPOS; return MP_OKAY; - } - - if((res = mp_init(&t)) != MP_OKAY) - return res; - if((res = mp_init_copy(&u, a)) != MP_OKAY) - goto U; - if((res = mp_init_copy(&v, b)) != MP_OKAY) - goto V; - - SIGN(&u) = MP_ZPOS; - SIGN(&v) = MP_ZPOS; - - /* Divide out common factors of 2 until at least 1 of a, b is even */ - while(mp_iseven(&u) && mp_iseven(&v)) { - s_mp_div_2(&u); - s_mp_div_2(&v); - ++k; - } - - /* Initialize t */ - if(mp_isodd(&u)) { - if((res = mp_copy(&v, &t)) != MP_OKAY) - goto CLEANUP; - - /* t = -v */ - if(SIGN(&v) == MP_ZPOS) - SIGN(&t) = MP_NEG; - else - SIGN(&t) = MP_ZPOS; - - } else { - if((res = mp_copy(&u, &t)) != MP_OKAY) - goto CLEANUP; - - } - - for(;;) { - while(mp_iseven(&t)) { - s_mp_div_2(&t); - } - - if(mp_cmp_z(&t) == MP_GT) { - if((res = mp_copy(&t, &u)) != MP_OKAY) - goto CLEANUP; - - } else { - if((res = mp_copy(&t, &v)) != MP_OKAY) - goto CLEANUP; - - /* v = -t */ - if(SIGN(&t) == MP_ZPOS) - SIGN(&v) = MP_NEG; - else - SIGN(&v) = MP_ZPOS; - } - - if((res = mp_sub(&u, &v, &t)) != MP_OKAY) - goto CLEANUP; - - if(s_mp_cmp_d(&t, 0) == MP_EQ) - break; - } - - s_mp_2expt(&v, k); /* v = 2^k */ - res = mp_mul(&u, &v, c); /* c = u * v */ - - CLEANUP: - mp_clear(&v); - V: - mp_clear(&u); - U: - mp_clear(&t); - - return res; - -} /* end mp_bgcd() */ - -/* }}} */ - -/* {{{ mp_lcm(a, b, c) */ - -/* We compute the least common multiple using the rule: - - ab = [a, b](a, b) - - ... by computing the product, and dividing out the gcd. - */ - -mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c) -{ - mp_int gcd, prod; - mp_err res; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - /* Set up temporaries */ - if((res = mp_init(&gcd)) != MP_OKAY) - return res; - if((res = mp_init(&prod)) != MP_OKAY) - goto GCD; - - if((res = mp_mul(a, b, &prod)) != MP_OKAY) - goto CLEANUP; - if((res = mp_gcd(a, b, &gcd)) != MP_OKAY) - goto CLEANUP; - - res = mp_div(&prod, &gcd, c, NULL); - - CLEANUP: - mp_clear(&prod); - GCD: - mp_clear(&gcd); - - return res; - -} /* end mp_lcm() */ - -/* }}} */ - -/* {{{ mp_xgcd(a, b, g, x, y) */ - -/* - mp_xgcd(a, b, g, x, y) - - Compute g = (a, b) and values x and y satisfying Bezout's identity - (that is, ax + by = g). This uses the extended binary GCD algorithm - based on the Stein algorithm used for mp_gcd() - */ - -mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y) -{ - mp_int gx, xc, yc, u, v, A, B, C, D; - mp_int *clean[9]; - mp_err res; - int last = -1; - - if(mp_cmp_z(b) == 0) - return MP_RANGE; - - /* Initialize all these variables we need */ - if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP; - clean[++last] = &u; - if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP; - clean[++last] = &v; - if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP; - clean[++last] = &gx; - if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP; - clean[++last] = &A; - if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP; - clean[++last] = &B; - if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP; - clean[++last] = &C; - if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP; - clean[++last] = &D; - if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; - clean[++last] = &xc; - mp_abs(&xc, &xc); - if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; - clean[++last] = &yc; - mp_abs(&yc, &yc); - - mp_set(&gx, 1); - - /* Divide by two until at least one of them is even */ - while(mp_iseven(&xc) && mp_iseven(&yc)) { - s_mp_div_2(&xc); - s_mp_div_2(&yc); - if((res = s_mp_mul_2(&gx)) != MP_OKAY) - goto CLEANUP; - } - - mp_copy(&xc, &u); - mp_copy(&yc, &v); - mp_set(&A, 1); mp_set(&D, 1); - - /* Loop through binary GCD algorithm */ - for(;;) { - while(mp_iseven(&u)) { - s_mp_div_2(&u); - - if(mp_iseven(&A) && mp_iseven(&B)) { - s_mp_div_2(&A); s_mp_div_2(&B); - } else { - if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&A); - if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&B); - } - } - - while(mp_iseven(&v)) { - s_mp_div_2(&v); - - if(mp_iseven(&C) && mp_iseven(&D)) { - s_mp_div_2(&C); s_mp_div_2(&D); - } else { - if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&C); - if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&D); - } - } - - if(mp_cmp(&u, &v) >= 0) { - if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; - - } else { - if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; - - } - - /* If we're done, copy results to output */ - if(mp_cmp_z(&u) == 0) { - if(x) - if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; - - if(y) - if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; - - if(g) - if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; - - break; - } - } - - CLEANUP: - while(last >= 0) - mp_clear(clean[last--]); - - return res; - -} /* end mp_xgcd() */ - -/* }}} */ - -/* {{{ mp_invmod(a, m, c) */ - -/* - mp_invmod(a, m, c) - - Compute c = a^-1 (mod m), if there is an inverse for a (mod m). - This is equivalent to the question of whether (a, m) = 1. If not, - MP_UNDEF is returned, and there is no inverse. - */ - -mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_int g, x; - mp_sign sa; - mp_err res; - - ARGCHK(a && m && c, MP_BADARG); - - if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) - return MP_RANGE; - - sa = SIGN(a); - - if((res = mp_init(&g)) != MP_OKAY) - return res; - if((res = mp_init(&x)) != MP_OKAY) - goto X; - - if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) - goto CLEANUP; - - if(mp_cmp_d(&g, 1) != MP_EQ) { - res = MP_UNDEF; - goto CLEANUP; - } - - res = mp_mod(&x, m, c); - SIGN(c) = sa; - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&g); - - return res; - -} /* end mp_invmod() */ - -/* }}} */ -#endif /* if MP_NUMTH */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ mp_print(mp, ofp) */ - -#if MP_IOFUNC -/* - mp_print(mp, ofp) - - Print a textual representation of the given mp_int on the output - stream 'ofp'. Output is generated using the internal radix. - */ - -void mp_print(mp_int *mp, FILE *ofp) -{ - int ix; - - if(mp == NULL || ofp == NULL) - return; - - fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); - - for(ix = USED(mp) - 1; ix >= 0; ix--) { - fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); - } - -} /* end mp_print() */ - -#endif /* if MP_IOFUNC */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ More I/O Functions */ - -/* {{{ mp_read_signed_bin(mp, str, len) */ - -/* - mp_read_signed_bin(mp, str, len) - - Read in a raw value (base 256) into the given mp_int - */ - -mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len) -{ - mp_err res; - - ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); - - if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) { - /* Get sign from first byte */ - if(str[0]) - SIGN(mp) = MP_NEG; - else - SIGN(mp) = MP_ZPOS; - } - - return res; - -} /* end mp_read_signed_bin() */ - -/* }}} */ - -/* {{{ mp_signed_bin_size(mp) */ - -int mp_signed_bin_size(mp_int *mp) -{ - ARGCHK(mp != NULL, 0); - - return mp_unsigned_bin_size(mp) + 1; - -} /* end mp_signed_bin_size() */ - -/* }}} */ - -/* {{{ mp_to_signed_bin(mp, str) */ - -mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str) -{ - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - - /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */ - str[0] = (char)SIGN(mp); - - return mp_to_unsigned_bin(mp, str + 1); - -} /* end mp_to_signed_bin() */ - -/* }}} */ - -/* {{{ mp_read_unsigned_bin(mp, str, len) */ - -/* - mp_read_unsigned_bin(mp, str, len) - - Read in an unsigned value (base 256) into the given mp_int - */ - -mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len) -{ - int ix; - mp_err res; - - ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); - - mp_zero(mp); - - for(ix = 0; ix < len; ix++) { - if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) - return res; - - if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY) - return res; - } - - return MP_OKAY; - -} /* end mp_read_unsigned_bin() */ - -/* }}} */ - -/* {{{ mp_unsigned_bin_size(mp) */ - -int mp_unsigned_bin_size(mp_int *mp) -{ - mp_digit topdig; - int count; - - ARGCHK(mp != NULL, 0); - - /* Special case for the value zero */ - if(USED(mp) == 1 && DIGIT(mp, 0) == 0) - return 1; - - count = (USED(mp) - 1) * sizeof(mp_digit); - topdig = DIGIT(mp, USED(mp) - 1); - - while(topdig != 0) { - ++count; - topdig >>= CHAR_BIT; - } - - return count; - -} /* end mp_unsigned_bin_size() */ - -/* }}} */ - -/* {{{ mp_to_unsigned_bin(mp, str) */ - -mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str) -{ - mp_digit *dp, *end, d; - unsigned char *spos; - - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - - dp = DIGITS(mp); - end = dp + USED(mp) - 1; - spos = str; - - /* Special case for zero, quick test */ - if(dp == end && *dp == 0) { - *str = '\0'; - return MP_OKAY; - } - - /* Generate digits in reverse order */ - while(dp < end) { - int ix; - - d = *dp; - for(ix = 0; ix < sizeof(mp_digit); ++ix) { - *spos = d & UCHAR_MAX; - d >>= CHAR_BIT; - ++spos; - } - - ++dp; - } - - /* Now handle last digit specially, high order zeroes are not written */ - d = *end; - while(d != 0) { - *spos = d & UCHAR_MAX; - d >>= CHAR_BIT; - ++spos; - } - - /* Reverse everything to get digits in the correct order */ - while(--spos > str) { - unsigned char t = *str; - *str = *spos; - *spos = t; - - ++str; - } - - return MP_OKAY; - -} /* end mp_to_unsigned_bin() */ - -/* }}} */ - -/* {{{ mp_count_bits(mp) */ - -int mp_count_bits(mp_int *mp) -{ - int len; - mp_digit d; - - ARGCHK(mp != NULL, MP_BADARG); - - len = DIGIT_BIT * (USED(mp) - 1); - d = DIGIT(mp, USED(mp) - 1); - - while(d != 0) { - ++len; - d >>= 1; - } - - return len; - -} /* end mp_count_bits() */ - -/* }}} */ - -/* {{{ mp_read_radix(mp, str, radix) */ - -/* - mp_read_radix(mp, str, radix) - - Read an integer from the given string, and set mp to the resulting - value. The input is presumed to be in base 10. Leading non-digit - characters are ignored, and the function reads until a non-digit - character or the end of the string. - */ - -mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix) -{ - int ix = 0, val = 0; - mp_err res; - mp_sign sig = MP_ZPOS; - - ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, - MP_BADARG); - - mp_zero(mp); - - /* Skip leading non-digit characters until a digit or '-' or '+' */ - while(str[ix] && - (s_mp_tovalue(str[ix], radix) < 0) && - str[ix] != '-' && - str[ix] != '+') { - ++ix; - } - - if(str[ix] == '-') { - sig = MP_NEG; - ++ix; - } else if(str[ix] == '+') { - sig = MP_ZPOS; /* this is the default anyway... */ - ++ix; - } - - while((val = s_mp_tovalue(str[ix], radix)) >= 0) { - if((res = s_mp_mul_d(mp, radix)) != MP_OKAY) - return res; - if((res = s_mp_add_d(mp, val)) != MP_OKAY) - return res; - ++ix; - } - - if(s_mp_cmp_d(mp, 0) == MP_EQ) - SIGN(mp) = MP_ZPOS; - else - SIGN(mp) = sig; - - return MP_OKAY; - -} /* end mp_read_radix() */ - -/* }}} */ - -/* {{{ mp_radix_size(mp, radix) */ - -int mp_radix_size(mp_int *mp, int radix) -{ - int len; - ARGCHK(mp != NULL, 0); - - len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */ - - if(mp_cmp_z(mp) < 0) - ++len; /* for sign */ - - return len; - -} /* end mp_radix_size() */ - -/* }}} */ - -/* {{{ mp_value_radix_size(num, qty, radix) */ - -/* num = number of digits - qty = number of bits per digit - radix = target base - - Return the number of digits in the specified radix that would be - needed to express 'num' digits of 'qty' bits each. - */ -int mp_value_radix_size(int num, int qty, int radix) -{ - ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); - - return s_mp_outlen(num * qty, radix); - -} /* end mp_value_radix_size() */ - -/* }}} */ - -/* {{{ mp_toradix(mp, str, radix) */ - -mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix) -{ - int ix, pos = 0; - - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); - - if(mp_cmp_z(mp) == MP_EQ) { - str[0] = '0'; - str[1] = '\0'; - } else { - mp_err res; - mp_int tmp; - mp_sign sgn; - mp_digit rem, rdx = (mp_digit)radix; - char ch; - - if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) - return res; - - /* Save sign for later, and take absolute value */ - sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; - - /* Generate output digits in reverse order */ - while(mp_cmp_z(&tmp) != 0) { - if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - /* Generate digits, use capital letters */ - ch = s_mp_todigit(rem, radix, 0); - - str[pos++] = ch; - } - - /* Add - sign if original value was negative */ - if(sgn == MP_NEG) - str[pos++] = '-'; - - /* Add trailing NUL to end the string */ - str[pos--] = '\0'; - - /* Reverse the digits and sign indicator */ - ix = 0; - while(ix < pos) { - char tmp = str[ix]; - - str[ix] = str[pos]; - str[pos] = tmp; - ++ix; - --pos; - } - - mp_clear(&tmp); - } - - return MP_OKAY; - -} /* end mp_toradix() */ - -/* }}} */ - -/* {{{ mp_char2value(ch, r) */ - -int mp_char2value(char ch, int r) -{ - return s_mp_tovalue(ch, r); - -} /* end mp_tovalue() */ - -/* }}} */ - -/* }}} */ - -/* {{{ mp_strerror(ec) */ - -/* - mp_strerror(ec) - - Return a string describing the meaning of error code 'ec'. The - string returned is allocated in static memory, so the caller should - not attempt to modify or free the memory associated with this - string. - */ -const char *mp_strerror(mp_err ec) -{ - int aec = (ec < 0) ? -ec : ec; - - /* Code values are negative, so the senses of these comparisons - are accurate */ - if(ec < MP_LAST_CODE || ec > MP_OKAY) { - return mp_err_string[0]; /* unknown error code */ - } else { - return mp_err_string[aec + 1]; - } - -} /* end mp_strerror() */ - -/* }}} */ - -/*========================================================================*/ -/*------------------------------------------------------------------------*/ -/* Static function definitions (internal use only) */ - -/* {{{ Memory management */ - -/* {{{ s_mp_grow(mp, min) */ - -/* Make sure there are at least 'min' digits allocated to mp */ -mp_err s_mp_grow(mp_int *mp, mp_size min) -{ - if(min > ALLOC(mp)) { - mp_digit *tmp; - - /* Set min to next nearest default precision block size */ - min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; - - if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(mp), tmp, USED(mp)); - -#if MP_CRYPTO - s_mp_setz(DIGITS(mp), ALLOC(mp)); -#endif - s_mp_free(DIGITS(mp)); - DIGITS(mp) = tmp; - ALLOC(mp) = min; - } - - return MP_OKAY; - -} /* end s_mp_grow() */ - -/* }}} */ - -/* {{{ s_mp_pad(mp, min) */ - -/* Make sure the used size of mp is at least 'min', growing if needed */ -mp_err s_mp_pad(mp_int *mp, mp_size min) -{ - if(min > USED(mp)) { - mp_err res; - - /* Make sure there is room to increase precision */ - if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY) - return res; - - /* Increase precision; should already be 0-filled */ - USED(mp) = min; - } - - return MP_OKAY; - -} /* end s_mp_pad() */ - -/* }}} */ - -/* {{{ s_mp_setz(dp, count) */ - -#if MP_MACRO == 0 -/* Set 'count' digits pointed to by dp to be zeroes */ -void s_mp_setz(mp_digit *dp, mp_size count) -{ -#if MP_MEMSET == 0 - int ix; - - for(ix = 0; ix < count; ix++) - dp[ix] = 0; -#else - memset(dp, 0, count * sizeof(mp_digit)); -#endif - -} /* end s_mp_setz() */ -#endif - -/* }}} */ - -/* {{{ s_mp_copy(sp, dp, count) */ - -#if MP_MACRO == 0 -/* Copy 'count' digits from sp to dp */ -void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count) -{ -#if MP_MEMCPY == 0 - int ix; - - for(ix = 0; ix < count; ix++) - dp[ix] = sp[ix]; -#else - memcpy(dp, sp, count * sizeof(mp_digit)); -#endif - -} /* end s_mp_copy() */ -#endif - -/* }}} */ - -/* {{{ s_mp_alloc(nb, ni) */ - -#if MP_MACRO == 0 -/* Allocate ni records of nb bytes each, and return a pointer to that */ -void *s_mp_alloc(size_t nb, size_t ni) -{ - return calloc(nb, ni); - -} /* end s_mp_alloc() */ -#endif - -/* }}} */ - -/* {{{ s_mp_free(ptr) */ - -#if MP_MACRO == 0 -/* Free the memory pointed to by ptr */ -void s_mp_free(void *ptr) -{ - if(ptr) - free(ptr); - -} /* end s_mp_free() */ -#endif - -/* }}} */ - -/* {{{ s_mp_clamp(mp) */ - -/* Remove leading zeroes from the given value */ -void s_mp_clamp(mp_int *mp) -{ - mp_size du = USED(mp); - mp_digit *zp = DIGITS(mp) + du - 1; - - while(du > 1 && !*zp--) - --du; - - if(du == 1 && *zp == 0) - SIGN(mp) = MP_ZPOS; - - USED(mp) = du; - -} /* end s_mp_clamp() */ - - -/* }}} */ - -/* {{{ s_mp_exch(a, b) */ - -/* Exchange the data for a and b; (b, a) = (a, b) */ -void s_mp_exch(mp_int *a, mp_int *b) -{ - mp_int tmp; - - tmp = *a; - *a = *b; - *b = tmp; - -} /* end s_mp_exch() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Arithmetic helpers */ - -/* {{{ s_mp_lshd(mp, p) */ - -/* - Shift mp leftward by p digits, growing if needed, and zero-filling - the in-shifted digits at the right end. This is a convenient - alternative to multiplication by powers of the radix - */ - -mp_err s_mp_lshd(mp_int *mp, mp_size p) -{ - mp_err res; - mp_size pos; - mp_digit *dp; - int ix; - - if(p == 0) - return MP_OKAY; - - if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) - return res; - - pos = USED(mp) - 1; - dp = DIGITS(mp); - - /* Shift all the significant figures over as needed */ - for(ix = pos - p; ix >= 0; ix--) - dp[ix + p] = dp[ix]; - - /* Fill the bottom digits with zeroes */ - for(ix = 0; ix < p; ix++) - dp[ix] = 0; - - return MP_OKAY; - -} /* end s_mp_lshd() */ - -/* }}} */ - -/* {{{ s_mp_rshd(mp, p) */ - -/* - Shift mp rightward by p digits. Maintains the invariant that - digits above the precision are all zero. Digits shifted off the - end are lost. Cannot fail. - */ - -void s_mp_rshd(mp_int *mp, mp_size p) -{ - mp_size ix; - mp_digit *dp; - - if(p == 0) - return; - - /* Shortcut when all digits are to be shifted off */ - if(p >= USED(mp)) { - s_mp_setz(DIGITS(mp), ALLOC(mp)); - USED(mp) = 1; - SIGN(mp) = MP_ZPOS; - return; - } - - /* Shift all the significant figures over as needed */ - dp = DIGITS(mp); - for(ix = p; ix < USED(mp); ix++) - dp[ix - p] = dp[ix]; - - /* Fill the top digits with zeroes */ - ix -= p; - while(ix < USED(mp)) - dp[ix++] = 0; - - /* Strip off any leading zeroes */ - s_mp_clamp(mp); - -} /* end s_mp_rshd() */ - -/* }}} */ - -/* {{{ s_mp_div_2(mp) */ - -/* Divide by two -- take advantage of radix properties to do it fast */ -void s_mp_div_2(mp_int *mp) -{ - s_mp_div_2d(mp, 1); - -} /* end s_mp_div_2() */ - -/* }}} */ - -/* {{{ s_mp_mul_2(mp) */ - -mp_err s_mp_mul_2(mp_int *mp) -{ - int ix; - mp_digit kin = 0, kout, *dp = DIGITS(mp); - mp_err res; - - /* Shift digits leftward by 1 bit */ - for(ix = 0; ix < USED(mp); ix++) { - kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; - dp[ix] = (dp[ix] << 1) | kin; - - kin = kout; - } - - /* Deal with rollover from last digit */ - if(kin) { - if(ix >= ALLOC(mp)) { - if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) - return res; - dp = DIGITS(mp); - } - - dp[ix] = kin; - USED(mp) += 1; - } - - return MP_OKAY; - -} /* end s_mp_mul_2() */ - -/* }}} */ - -/* {{{ s_mp_mod_2d(mp, d) */ - -/* - Remainder the integer by 2^d, where d is a number of bits. This - amounts to a bitwise AND of the value, and does not require the full - division code - */ -void s_mp_mod_2d(mp_int *mp, mp_digit d) -{ - unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); - unsigned int ix; - mp_digit dmask, *dp = DIGITS(mp); - - if(ndig >= USED(mp)) - return; - - /* Flush all the bits above 2^d in its digit */ - dmask = (1 << nbit) - 1; - dp[ndig] &= dmask; - - /* Flush all digits above the one with 2^d in it */ - for(ix = ndig + 1; ix < USED(mp); ix++) - dp[ix] = 0; - - s_mp_clamp(mp); - -} /* end s_mp_mod_2d() */ - -/* }}} */ - -/* {{{ s_mp_mul_2d(mp, d) */ - -/* - Multiply by the integer 2^d, where d is a number of bits. This - amounts to a bitwise shift of the value, and does not require the - full multiplication code. - */ -mp_err s_mp_mul_2d(mp_int *mp, mp_digit d) -{ - mp_err res; - mp_digit save, next, mask, *dp; - mp_size used; - int ix; - - if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) - return res; - - dp = DIGITS(mp); used = USED(mp); - d %= DIGIT_BIT; - - mask = (1 << d) - 1; - - /* If the shift requires another digit, make sure we've got one to - work with */ - if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { - if((res = s_mp_grow(mp, used + 1)) != MP_OKAY) - return res; - dp = DIGITS(mp); - } - - /* Do the shifting... */ - save = 0; - for(ix = 0; ix < used; ix++) { - next = (dp[ix] >> (DIGIT_BIT - d)) & mask; - dp[ix] = (dp[ix] << d) | save; - save = next; - } - - /* If, at this point, we have a nonzero carryout into the next - digit, we'll increase the size by one digit, and store it... - */ - if(save) { - dp[used] = save; - USED(mp) += 1; - } - - s_mp_clamp(mp); - return MP_OKAY; - -} /* end s_mp_mul_2d() */ - -/* }}} */ - -/* {{{ s_mp_div_2d(mp, d) */ - -/* - Divide the integer by 2^d, where d is a number of bits. This - amounts to a bitwise shift of the value, and does not require the - full division code (used in Barrett reduction, see below) - */ -void s_mp_div_2d(mp_int *mp, mp_digit d) -{ - int ix; - mp_digit save, next, mask, *dp = DIGITS(mp); - - s_mp_rshd(mp, d / DIGIT_BIT); - d %= DIGIT_BIT; - - mask = (1 << d) - 1; - - save = 0; - for(ix = USED(mp) - 1; ix >= 0; ix--) { - next = dp[ix] & mask; - dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); - save = next; - } - - s_mp_clamp(mp); - -} /* end s_mp_div_2d() */ - -/* }}} */ - -/* {{{ s_mp_norm(a, b) */ - -/* - s_mp_norm(a, b) - - Normalize a and b for division, where b is the divisor. In order - that we might make good guesses for quotient digits, we want the - leading digit of b to be at least half the radix, which we - accomplish by multiplying a and b by a constant. This constant is - returned (so that it can be divided back out of the remainder at the - end of the division process). - - We multiply by the smallest power of 2 that gives us a leading digit - at least half the radix. By choosing a power of 2, we simplify the - multiplication and division steps to simple shifts. - */ -mp_digit s_mp_norm(mp_int *a, mp_int *b) -{ - mp_digit t, d = 0; - - t = DIGIT(b, USED(b) - 1); - while(t < (RADIX / 2)) { - t <<= 1; - ++d; - } - - if(d != 0) { - s_mp_mul_2d(a, d); - s_mp_mul_2d(b, d); - } - - return d; - -} /* end s_mp_norm() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive digit arithmetic */ - -/* {{{ s_mp_add_d(mp, d) */ - -/* Add d to |mp| in place */ -mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */ -{ - mp_word w, k = 0; - mp_size ix = 1, used = USED(mp); - mp_digit *dp = DIGITS(mp); - - w = dp[0] + d; - dp[0] = ACCUM(w); - k = CARRYOUT(w); - - while(ix < used && k) { - w = dp[ix] + k; - dp[ix] = ACCUM(w); - k = CARRYOUT(w); - ++ix; - } - - if(k != 0) { - mp_err res; - - if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) - return res; - - DIGIT(mp, ix) = k; - } - - return MP_OKAY; - -} /* end s_mp_add_d() */ - -/* }}} */ - -/* {{{ s_mp_sub_d(mp, d) */ - -/* Subtract d from |mp| in place, assumes |mp| > d */ -mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */ -{ - mp_word w, b = 0; - mp_size ix = 1, used = USED(mp); - mp_digit *dp = DIGITS(mp); - - /* Compute initial subtraction */ - w = (RADIX + dp[0]) - d; - b = CARRYOUT(w) ? 0 : 1; - dp[0] = ACCUM(w); - - /* Propagate borrows leftward */ - while(b && ix < used) { - w = (RADIX + dp[ix]) - b; - b = CARRYOUT(w) ? 0 : 1; - dp[ix] = ACCUM(w); - ++ix; - } - - /* Remove leading zeroes */ - s_mp_clamp(mp); - - /* If we have a borrow out, it's a violation of the input invariant */ - if(b) - return MP_RANGE; - else - return MP_OKAY; - -} /* end s_mp_sub_d() */ - -/* }}} */ - -/* {{{ s_mp_mul_d(a, d) */ - -/* Compute a = a * d, single digit multiplication */ -mp_err s_mp_mul_d(mp_int *a, mp_digit d) -{ - mp_word w, k = 0; - mp_size ix, max; - mp_err res; - mp_digit *dp = DIGITS(a); - - /* - Single-digit multiplication will increase the precision of the - output by at most one digit. However, we can detect when this - will happen -- if the high-order digit of a, times d, gives a - two-digit result, then the precision of the result will increase; - otherwise it won't. We use this fact to avoid calling s_mp_pad() - unless absolutely necessary. - */ - max = USED(a); - w = dp[max - 1] * d; - if(CARRYOUT(w) != 0) { - if((res = s_mp_pad(a, max + 1)) != MP_OKAY) - return res; - dp = DIGITS(a); - } - - for(ix = 0; ix < max; ix++) { - w = (dp[ix] * d) + k; - dp[ix] = ACCUM(w); - k = CARRYOUT(w); - } - - /* If there is a precision increase, take care of it here; the above - test guarantees we have enough storage to do this safely. - */ - if(k) { - dp[max] = k; - USED(a) = max + 1; - } - - s_mp_clamp(a); - - return MP_OKAY; - -} /* end s_mp_mul_d() */ - -/* }}} */ - -/* {{{ s_mp_div_d(mp, d, r) */ - -/* - s_mp_div_d(mp, d, r) - - Compute the quotient mp = mp / d and remainder r = mp mod d, for a - single digit d. If r is null, the remainder will be discarded. - */ - -mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r) -{ - mp_word w = 0, t; - mp_int quot; - mp_err res; - mp_digit *dp = DIGITS(mp), *qp; - int ix; - - if(d == 0) - return MP_RANGE; - - /* Make room for the quotient */ - if((res = mp_init_size(", USED(mp))) != MP_OKAY) - return res; - - USED(") = USED(mp); /* so clamping will work below */ - qp = DIGITS("); - - /* Divide without subtraction */ - for(ix = USED(mp) - 1; ix >= 0; ix--) { - w = (w << DIGIT_BIT) | dp[ix]; - - if(w >= d) { - t = w / d; - w = w % d; - } else { - t = 0; - } - - qp[ix] = t; - } - - /* Deliver the remainder, if desired */ - if(r) - *r = w; - - s_mp_clamp("); - mp_exch(", mp); - mp_clear("); - - return MP_OKAY; - -} /* end s_mp_div_d() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive full arithmetic */ - -/* {{{ s_mp_add(a, b) */ - -/* Compute a = |a| + |b| */ -mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */ -{ - mp_word w = 0; - mp_digit *pa, *pb; - mp_size ix, used = USED(b); - mp_err res; - - /* Make sure a has enough precision for the output value */ - if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY) - return res; - - /* - Add up all digits up to the precision of b. If b had initially - the same precision as a, or greater, we took care of it by the - padding step above, so there is no problem. If b had initially - less precision, we'll have to make sure the carry out is duly - propagated upward among the higher-order digits of the sum. - */ - pa = DIGITS(a); - pb = DIGITS(b); - for(ix = 0; ix < used; ++ix) { - w += *pa + *pb++; - *pa++ = ACCUM(w); - w = CARRYOUT(w); - } - - /* If we run out of 'b' digits before we're actually done, make - sure the carries get propagated upward... - */ - used = USED(a); - while(w && ix < used) { - w += *pa; - *pa++ = ACCUM(w); - w = CARRYOUT(w); - ++ix; - } - - /* If there's an overall carry out, increase precision and include - it. We could have done this initially, but why touch the memory - allocator unless we're sure we have to? - */ - if(w) { - if((res = s_mp_pad(a, used + 1)) != MP_OKAY) - return res; - - DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */ - } - - return MP_OKAY; - -} /* end s_mp_add() */ - -/* }}} */ - -/* {{{ s_mp_sub(a, b) */ - -/* Compute a = |a| - |b|, assumes |a| >= |b| */ -mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */ -{ - mp_word w = 0; - mp_digit *pa, *pb; - mp_size ix, used = USED(b); - - /* - Subtract and propagate borrow. Up to the precision of b, this - accounts for the digits of b; after that, we just make sure the - carries get to the right place. This saves having to pad b out to - the precision of a just to make the loops work right... - */ - pa = DIGITS(a); - pb = DIGITS(b); - - for(ix = 0; ix < used; ++ix) { - w = (RADIX + *pa) - w - *pb++; - *pa++ = ACCUM(w); - w = CARRYOUT(w) ? 0 : 1; - } - - used = USED(a); - while(ix < used) { - w = RADIX + *pa - w; - *pa++ = ACCUM(w); - w = CARRYOUT(w) ? 0 : 1; - ++ix; - } - - /* Clobber any leading zeroes we created */ - s_mp_clamp(a); - - /* - If there was a borrow out, then |b| > |a| in violation - of our input invariant. We've already done the work, - but we'll at least complain about it... - */ - if(w) - return MP_RANGE; - else - return MP_OKAY; - -} /* end s_mp_sub() */ - -/* }}} */ - -/* {{{ s_mp_mul(a, b) */ - -/* Compute a = |a| * |b| */ -mp_err s_mp_mul(mp_int *a, mp_int *b) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, ua = USED(a), ub = USED(b); - mp_digit *pa, *pb, *pt, *pbt; - - if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY) - return res; - - /* This has the effect of left-padding with zeroes... */ - USED(&tmp) = ua + ub; - - /* We're going to need the base value each iteration */ - pbt = DIGITS(&tmp); - - /* Outer loop: Digits of b */ - - pb = DIGITS(b); - for(ix = 0; ix < ub; ++ix, ++pb) { - if(*pb == 0) - continue; - - /* Inner product: Digits of a */ - pa = DIGITS(a); - for(jx = 0; jx < ua; ++jx, ++pa) { - pt = pbt + ix + jx; - w = *pb * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); - } - - pbt[ix + jx] = k; - k = 0; - } - - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_mul() */ - -/* }}} */ - -/* {{{ s_mp_kmul(a, b, out, len) */ - -#if 0 -void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len) -{ - mp_word w, k = 0; - mp_size ix, jx; - mp_digit *pa, *pt; - - for(ix = 0; ix < len; ++ix, ++b) { - if(*b == 0) - continue; - - pa = a; - for(jx = 0; jx < len; ++jx, ++pa) { - pt = out + ix + jx; - w = *b * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); - } - - out[ix + jx] = k; - k = 0; - } - -} /* end s_mp_kmul() */ -#endif - -/* }}} */ - -/* {{{ s_mp_sqr(a) */ - -/* - Computes the square of a, in place. This can be done more - efficiently than a general multiplication, because many of the - computation steps are redundant when squaring. The inner product - step is a bit more complicated, but we save a fair number of - iterations of the multiplication loop. - */ -#if MP_SQUARE -mp_err s_mp_sqr(mp_int *a) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, kx, used = USED(a); - mp_digit *pa1, *pa2, *pt, *pbt; - - if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY) - return res; - - /* Left-pad with zeroes */ - USED(&tmp) = 2 * used; - - /* We need the base value each time through the loop */ - pbt = DIGITS(&tmp); - - pa1 = DIGITS(a); - for(ix = 0; ix < used; ++ix, ++pa1) { - if(*pa1 == 0) - continue; - - w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1); - - pbt[ix + ix] = ACCUM(w); - k = CARRYOUT(w); - - /* - The inner product is computed as: - - (C, S) = t[i,j] + 2 a[i] a[j] + C - - This can overflow what can be represented in an mp_word, and - since C arithmetic does not provide any way to check for - overflow, we have to check explicitly for overflow conditions - before they happen. - */ - for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) { - mp_word u = 0, v; - - /* Store this in a temporary to avoid indirections later */ - pt = pbt + ix + jx; - - /* Compute the multiplicative step */ - w = *pa1 * *pa2; - - /* If w is more than half MP_WORD_MAX, the doubling will - overflow, and we need to record a carry out into the next - word */ - u = (w >> (MP_WORD_BIT - 1)) & 1; - - /* Double what we've got, overflow will be ignored as defined - for C arithmetic (we've already noted if it is to occur) - */ - w *= 2; - - /* Compute the additive step */ - v = *pt + k; - - /* If we do not already have an overflow carry, check to see - if the addition will cause one, and set the carry out if so - */ - u |= ((MP_WORD_MAX - v) < w); - - /* Add in the rest, again ignoring overflow */ - w += v; - - /* Set the i,j digit of the output */ - *pt = ACCUM(w); - - /* Save carry information for the next iteration of the loop. - This is why k must be an mp_word, instead of an mp_digit */ - k = CARRYOUT(w) | (u << DIGIT_BIT); - - } /* for(jx ...) */ - - /* Set the last digit in the cycle and reset the carry */ - k = DIGIT(&tmp, ix + jx) + k; - pbt[ix + jx] = ACCUM(k); - k = CARRYOUT(k); - - /* If we are carrying out, propagate the carry to the next digit - in the output. This may cascade, so we have to be somewhat - circumspect -- but we will have enough precision in the output - that we won't overflow - */ - kx = 1; - while(k) { - k = pbt[ix + jx + kx] + 1; - pbt[ix + jx + kx] = ACCUM(k); - k = CARRYOUT(k); - ++kx; - } - } /* for(ix ...) */ - - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_sqr() */ -#endif - -/* }}} */ - -/* {{{ s_mp_div(a, b) */ - -/* - s_mp_div(a, b) - - Compute a = a / b and b = a mod b. Assumes b > a. - */ - -mp_err s_mp_div(mp_int *a, mp_int *b) -{ - mp_int quot, rem, t; - mp_word q; - mp_err res; - mp_digit d; - int ix; - - if(mp_cmp_z(b) == 0) - return MP_RANGE; - - /* Shortcut if b is power of two */ - if((ix = s_mp_ispow2(b)) >= 0) { - mp_copy(a, b); /* need this for remainder */ - s_mp_div_2d(a, (mp_digit)ix); - s_mp_mod_2d(b, (mp_digit)ix); - - return MP_OKAY; - } - - /* Allocate space to store the quotient */ - if((res = mp_init_size(", USED(a))) != MP_OKAY) - return res; - - /* A working temporary for division */ - if((res = mp_init_size(&t, USED(a))) != MP_OKAY) - goto T; - - /* Allocate space for the remainder */ - if((res = mp_init_size(&rem, USED(a))) != MP_OKAY) - goto REM; - - /* Normalize to optimize guessing */ - d = s_mp_norm(a, b); - - /* Perform the division itself...woo! */ - ix = USED(a) - 1; - - while(ix >= 0) { - /* Find a partial substring of a which is at least b */ - while(s_mp_cmp(&rem, b) < 0 && ix >= 0) { - if((res = s_mp_lshd(&rem, 1)) != MP_OKAY) - goto CLEANUP; - - if((res = s_mp_lshd(", 1)) != MP_OKAY) - goto CLEANUP; - - DIGIT(&rem, 0) = DIGIT(a, ix); - s_mp_clamp(&rem); - --ix; - } - - /* If we didn't find one, we're finished dividing */ - if(s_mp_cmp(&rem, b) < 0) - break; - - /* Compute a guess for the next quotient digit */ - q = DIGIT(&rem, USED(&rem) - 1); - if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1) - q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2); - - q /= DIGIT(b, USED(b) - 1); - - /* The guess can be as much as RADIX + 1 */ - if(q >= RADIX) - q = RADIX - 1; - - /* See what that multiplies out to */ - mp_copy(b, &t); - if((res = s_mp_mul_d(&t, q)) != MP_OKAY) - goto CLEANUP; - - /* - If it's too big, back it off. We should not have to do this - more than once, or, in rare cases, twice. Knuth describes a - method by which this could be reduced to a maximum of once, but - I didn't implement that here. - */ - while(s_mp_cmp(&t, &rem) > 0) { - --q; - s_mp_sub(&t, b); - } - - /* At this point, q should be the right next digit */ - if((res = s_mp_sub(&rem, &t)) != MP_OKAY) - goto CLEANUP; - - /* - Include the digit in the quotient. We allocated enough memory - for any quotient we could ever possibly get, so we should not - have to check for failures here - */ - DIGIT(", 0) = q; - } - - /* Denormalize remainder */ - if(d != 0) - s_mp_div_2d(&rem, d); - - s_mp_clamp("); - s_mp_clamp(&rem); - - /* Copy quotient back to output */ - s_mp_exch(", a); - - /* Copy remainder back to output */ - s_mp_exch(&rem, b); - -CLEANUP: - mp_clear(&rem); -REM: - mp_clear(&t); -T: - mp_clear("); - - return res; - -} /* end s_mp_div() */ - -/* }}} */ - -/* {{{ s_mp_2expt(a, k) */ - -mp_err s_mp_2expt(mp_int *a, mp_digit k) -{ - mp_err res; - mp_size dig, bit; - - dig = k / DIGIT_BIT; - bit = k % DIGIT_BIT; - - mp_zero(a); - if((res = s_mp_pad(a, dig + 1)) != MP_OKAY) - return res; - - DIGIT(a, dig) |= (1 << bit); - - return MP_OKAY; - -} /* end s_mp_2expt() */ - -/* }}} */ - -/* {{{ s_mp_reduce(x, m, mu) */ - -/* - Compute Barrett reduction, x (mod m), given a precomputed value for - mu = b^2k / m, where b = RADIX and k = #digits(m). This should be - faster than straight division, when many reductions by the same - value of m are required (such as in modular exponentiation). This - can nearly halve the time required to do modular exponentiation, - as compared to using the full integer divide to reduce. - - This algorithm was derived from the _Handbook of Applied - Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14, - pp. 603-604. - */ - -mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu) -{ - mp_int q; - mp_err res; - mp_size um = USED(m); - - if((res = mp_init_copy(&q, x)) != MP_OKAY) - return res; - - s_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */ - s_mp_mul(&q, mu); /* q2 = q1 * mu */ - s_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */ - - /* x = x mod b^(k+1), quick (no division) */ - s_mp_mod_2d(x, DIGIT_BIT * (um + 1)); - - /* q = q * m mod b^(k+1), quick (no division) */ - s_mp_mul(&q, m); - s_mp_mod_2d(&q, DIGIT_BIT * (um + 1)); - - /* x = x - q */ - if((res = mp_sub(x, &q, x)) != MP_OKAY) - goto CLEANUP; - - /* If x < 0, add b^(k+1) to it */ - if(mp_cmp_z(x) < 0) { - mp_set(&q, 1); - if((res = s_mp_lshd(&q, um + 1)) != MP_OKAY) - goto CLEANUP; - if((res = mp_add(x, &q, x)) != MP_OKAY) - goto CLEANUP; - } - - /* Back off if it's too big */ - while(mp_cmp(x, m) >= 0) { - if((res = s_mp_sub(x, m)) != MP_OKAY) - break; - } - - CLEANUP: - mp_clear(&q); - - return res; - -} /* end s_mp_reduce() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive comparisons */ - -/* {{{ s_mp_cmp(a, b) */ - -/* Compare |a| <=> |b|, return 0 if equal, <0 if a0 if a>b */ -int s_mp_cmp(mp_int *a, mp_int *b) -{ - mp_size ua = USED(a), ub = USED(b); - - if(ua > ub) - return MP_GT; - else if(ua < ub) - return MP_LT; - else { - int ix = ua - 1; - mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix; - - while(ix >= 0) { - if(*ap > *bp) - return MP_GT; - else if(*ap < *bp) - return MP_LT; - - --ap; --bp; --ix; - } - - return MP_EQ; - } - -} /* end s_mp_cmp() */ - -/* }}} */ - -/* {{{ s_mp_cmp_d(a, d) */ - -/* Compare |a| <=> d, return 0 if equal, <0 if a0 if a>d */ -int s_mp_cmp_d(mp_int *a, mp_digit d) -{ - mp_size ua = USED(a); - mp_digit *ap = DIGITS(a); - - if(ua > 1) - return MP_GT; - - if(*ap < d) - return MP_LT; - else if(*ap > d) - return MP_GT; - else - return MP_EQ; - -} /* end s_mp_cmp_d() */ - -/* }}} */ - -/* {{{ s_mp_ispow2(v) */ - -/* - Returns -1 if the value is not a power of two; otherwise, it returns - k such that v = 2^k, i.e. lg(v). - */ -int s_mp_ispow2(mp_int *v) -{ - mp_digit d, *dp; - mp_size uv = USED(v); - int extra = 0, ix; - - d = DIGIT(v, uv - 1); /* most significant digit of v */ - - while(d && ((d & 1) == 0)) { - d >>= 1; - ++extra; - } - - if(d == 1) { - ix = uv - 2; - dp = DIGITS(v) + ix; - - while(ix >= 0) { - if(*dp) - return -1; /* not a power of two */ - - --dp; --ix; - } - - return ((uv - 1) * DIGIT_BIT) + extra; - } - - return -1; - -} /* end s_mp_ispow2() */ - -/* }}} */ - -/* {{{ s_mp_ispow2d(d) */ - -int s_mp_ispow2d(mp_digit d) -{ - int pow = 0; - - while((d & 1) == 0) { - ++pow; d >>= 1; - } - - if(d == 1) - return pow; - - return -1; - -} /* end s_mp_ispow2d() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive I/O helpers */ - -/* {{{ s_mp_tovalue(ch, r) */ - -/* - Convert the given character to its digit value, in the given radix. - If the given character is not understood in the given radix, -1 is - returned. Otherwise the digit's numeric value is returned. - - The results will be odd if you use a radix < 2 or > 62, you are - expected to know what you're up to. - */ -int s_mp_tovalue(char ch, int r) -{ - int val, xch; - - if(r > 36) - xch = ch; - else - xch = toupper(ch); - - if(isdigit(xch)) - val = xch - '0'; - else if(isupper(xch)) - val = xch - 'A' + 10; - else if(islower(xch)) - val = xch - 'a' + 36; - else if(xch == '+') - val = 62; - else if(xch == '/') - val = 63; - else - return -1; - - if(val < 0 || val >= r) - return -1; - - return val; - -} /* end s_mp_tovalue() */ - -/* }}} */ - -/* {{{ s_mp_todigit(val, r, low) */ - -/* - Convert val to a radix-r digit, if possible. If val is out of range - for r, returns zero. Otherwise, returns an ASCII character denoting - the value in the given radix. - - The results may be odd if you use a radix < 2 or > 64, you are - expected to know what you're doing. - */ - -char s_mp_todigit(int val, int r, int low) -{ - char ch; - - if(val < 0 || val >= r) - return 0; - - ch = s_dmap_1[val]; - - if(r <= 36 && low) - ch = tolower(ch); - - return ch; - -} /* end s_mp_todigit() */ - -/* }}} */ - -/* {{{ s_mp_outlen(bits, radix) */ - -/* - Return an estimate for how long a string is needed to hold a radix - r representation of a number with 'bits' significant bits. - - Does not include space for a sign or a NUL terminator. - */ -int s_mp_outlen(int bits, int r) -{ - return (int)((double)bits * LOG_V_2(r) + 0.5); - -} /* end s_mp_outlen() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* HERE THERE BE DRAGONS */ diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mpi/mpi.h --- a/src/protocols/sametime/meanwhile/mpi/mpi.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,221 +0,0 @@ -/* - mpi.h - - by Michael J. Fromberger - Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved - - Arbitrary precision integer arithmetic library - - $Id: mpi.h 14563 2005-11-29 23:31:40Z taliesein $ - */ - -#ifndef _H_MPI_ -#define _H_MPI_ - -#include "mpi-config.h" - -#if MP_DEBUG -#undef MP_IOFUNC -#define MP_IOFUNC 1 -#endif - -#if MP_IOFUNC -#include -#include -#endif - -#include - -#define MP_NEG 1 -#define MP_ZPOS 0 - -/* Included for compatibility... */ -#define NEG MP_NEG -#define ZPOS MP_ZPOS - -#define MP_OKAY 0 /* no error, all is well */ -#define MP_YES 0 /* yes (boolean result) */ -#define MP_NO -1 /* no (boolean result) */ -#define MP_MEM -2 /* out of memory */ -#define MP_RANGE -3 /* argument out of range */ -#define MP_BADARG -4 /* invalid parameter */ -#define MP_UNDEF -5 /* answer is undefined */ -#define MP_LAST_CODE MP_UNDEF - -#include "mpi-types.h" - -/* Included for compatibility... */ -#define DIGIT_BIT MP_DIGIT_BIT -#define DIGIT_MAX MP_DIGIT_MAX - -/* Macros for accessing the mp_int internals */ -#define SIGN(MP) ((MP)->sign) -#define USED(MP) ((MP)->used) -#define ALLOC(MP) ((MP)->alloc) -#define DIGITS(MP) ((MP)->dp) -#define DIGIT(MP,N) (MP)->dp[(N)] - -#if MP_ARGCHK == 1 -#define ARGCHK(X,Y) {if(!(X)){return (Y);}} -#elif MP_ARGCHK == 2 -#include -#define ARGCHK(X,Y) assert(X) -#else -#define ARGCHK(X,Y) /* */ -#endif - -/* This defines the maximum I/O base (minimum is 2) */ -#define MAX_RADIX 64 - -typedef struct { - mp_sign sign; /* sign of this quantity */ - mp_size alloc; /* how many digits allocated */ - mp_size used; /* how many digits used */ - mp_digit *dp; /* the digits themselves */ -} mp_int; - -/*------------------------------------------------------------------------*/ -/* Default precision */ - -unsigned int mp_get_prec(void); -void mp_set_prec(unsigned int prec); - -/*------------------------------------------------------------------------*/ -/* Memory management */ - -mp_err mp_init(mp_int *mp); -mp_err mp_init_array(mp_int mp[], int count); -mp_err mp_init_size(mp_int *mp, mp_size prec); -mp_err mp_init_copy(mp_int *mp, mp_int *from); -mp_err mp_copy(mp_int *from, mp_int *to); -void mp_exch(mp_int *mp1, mp_int *mp2); -void mp_clear(mp_int *mp); -void mp_clear_array(mp_int mp[], int count); -void mp_zero(mp_int *mp); -void mp_set(mp_int *mp, mp_digit d); -mp_err mp_set_int(mp_int *mp, long z); - -/*------------------------------------------------------------------------*/ -/* Single digit arithmetic */ - -mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b); -mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b); -mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b); -mp_err mp_mul_2(mp_int *a, mp_int *c); -mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r); -mp_err mp_div_2(mp_int *a, mp_int *c); -mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c); - -/*------------------------------------------------------------------------*/ -/* Sign manipulations */ - -mp_err mp_abs(mp_int *a, mp_int *b); -mp_err mp_neg(mp_int *a, mp_int *b); - -/*------------------------------------------------------------------------*/ -/* Full arithmetic */ - -mp_err mp_add(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c); -#if MP_SQUARE -mp_err mp_sqr(mp_int *a, mp_int *b); -#else -#define mp_sqr(a, b) mp_mul(a, a, b) -#endif -mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r); -mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r); -mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_2expt(mp_int *a, mp_digit k); -mp_err mp_sqrt(mp_int *a, mp_int *b); - -/*------------------------------------------------------------------------*/ -/* Modular arithmetic */ - -#if MP_MODARITH -mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c); -mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c); -mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -#if MP_SQUARE -mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c); -#else -#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c) -#endif -mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c); -#endif /* MP_MODARITH */ - -/*------------------------------------------------------------------------*/ -/* Comparisons */ - -int mp_cmp_z(mp_int *a); -int mp_cmp_d(mp_int *a, mp_digit d); -int mp_cmp(mp_int *a, mp_int *b); -int mp_cmp_mag(mp_int *a, mp_int *b); -int mp_cmp_int(mp_int *a, long z); -int mp_isodd(mp_int *a); -int mp_iseven(mp_int *a); - -/*------------------------------------------------------------------------*/ -/* Number theoretic */ - -#if MP_NUMTH -mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y); -mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c); -#endif /* end MP_NUMTH */ - -/*------------------------------------------------------------------------*/ -/* Input and output */ - -#if MP_IOFUNC -void mp_print(mp_int *mp, FILE *ofp); -#endif /* end MP_IOFUNC */ - -/*------------------------------------------------------------------------*/ -/* Base conversion */ - -#define BITS 1 -#define BYTES CHAR_BIT - -mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len); -int mp_signed_bin_size(mp_int *mp); -mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str); - -mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len); -int mp_unsigned_bin_size(mp_int *mp); -mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str); - -int mp_count_bits(mp_int *mp); - -#if MP_COMPAT_MACROS -#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) -#define mp_raw_size(mp) mp_signed_bin_size(mp) -#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) -#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) -#define mp_mag_size(mp) mp_unsigned_bin_size(mp) -#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) -#endif - -mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix); -int mp_radix_size(mp_int *mp, int radix); -int mp_value_radix_size(int num, int qty, int radix); -mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix); - -int mp_char2value(char ch, int r); - -#define mp_tobinary(M, S) mp_toradix((M), (S), 2) -#define mp_tooctal(M, S) mp_toradix((M), (S), 8) -#define mp_todecimal(M, S) mp_toradix((M), (S), 10) -#define mp_tohex(M, S) mp_toradix((M), (S), 16) - -/*------------------------------------------------------------------------*/ -/* Error strings */ - -const char *mp_strerror(mp_err ec); - -#endif /* end _H_MPI_ */ diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_channel.h --- a/src/protocols/sametime/meanwhile/mw_channel.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,366 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_CHANNEL_H -#define _MW_CHANNEL_H - - -#include -#include "mw_common.h" - - -/** @file mw_channel.h - -Life-cycle of an outgoing channel: - -1: mwChannel_new is called. If there is a channel in the outgoing -collection in state NEW, then it is returned. Otherwise, a channel -is allocated, assigned a unique outgoing id, marked as NEW, and -returned. - -2: channel is set to INIT status (effectively earmarking it as in- -use). fields on the channel can then be set as necessary to -prepare it for creation. - -3: mwChannel_create is called. The channel is marked to WAIT status -and a message is sent to the server. The channel is also marked as -inactive as of that moment. - -4: the channel is accepted (step 5) or rejected (step 7) - -5: an accept message is received from the server, and the channel -is marked as OPEN, and the inactive mark is removed. And messages -in the in or out queues for that channel are processed. The channel -is now ready to be used. - -6: data is sent and received over the channel - -7: the channel is closed either by receipt of a close message or by -local action. If by local action, then a close message is sent to -the server. The channel is cleaned up, its queues dumped, and it -is set to NEW status to await re-use. - -Life-cycle of an incoming channel: - -1: a channel create message is received. A channel is allocated and -given an id matching the message. It is placed in status WAIT, and -marked as inactive as of that moment. The service matching that -channel is alerted of the incoming creation request. - -2: the service can either accept (step 3) or reject (step 5) the -channel - -3: mwChannel_accept is called. The channel is marked as OPEN, and -an accept message is sent to the server. And messages in the in or -out queues for that channel are processed. The channel is now ready -to be used. - -4: data is sent and received over the channel - -5: The channel is closed either by receipt of a close message or by -local action. If by local action, then a close message is sent to -the server. The channel is cleaned up, its queues dumped, and it -is deallocated. */ - - -/* place-holders */ -struct mwCipherInstance; -struct mwMsgChannelAccept; -struct mwMsgChannelCreate; -struct mwMsgChannelDestroy; -struct mwMsgChannelSend; -struct mwService; -struct mwSession; - - - -/** @struct mwChannel - Represents a channel to a service */ -struct mwChannel; - - -/** @struct mwChannelSet - Collection of channels */ -struct mwChannelSet; - - -/** special ID indicating the master channel */ -#define MW_MASTER_CHANNEL_ID 0x00000000 - - -/** non-zero if a channel id appears to be that of an outgoing channel */ -#define mwChannel_idIsOutgoing(id) \ - (! (0x80000000 & (id))) - -/** non-zero if a channel id appears to be that of an incoming channel */ -#define mwChannel_idIsIncoming(id) \ - (! mwChannel_idIsOutgoing(id)) - -/** non-zero if a channel appears to be an outgoing channel */ -#define mwChannel_isOutgoing(chan) \ - mwChannel_idIsOutgoing(mwChannel_getId(chan)) - -/** non-zero if a channel appears to be an incoming channel */ -#define mwChannel_isIncoming(chan) \ - mwChannel_idIsIncoming(mwChannel_getId(chan)) - - -/** channel status */ -enum mwChannelState { - mwChannel_NEW, /**< channel is newly allocated, in the pool */ - mwChannel_INIT, /**< channel is being prepared, out of the pool */ - mwChannel_WAIT, /**< channel is waiting for accept */ - mwChannel_OPEN, /**< channel is accepted and open */ - mwChannel_DESTROY, /**< channel is being destroyed */ - mwChannel_ERROR, /**< channel is being destroyed due to error */ - mwChannel_UNKNOWN, /**< unknown state, or error determining state */ -}; - - -#define mwChannel_isState(chan, state) \ - (mwChannel_getState(chan) == (state)) - - -/** channel statistic fields. - @see mwChannel_getStatistic */ -enum mwChannelStatField { - mwChannelStat_MSG_SENT, /**< total send-on-chan messages sent */ - mwChannelStat_MSG_RECV, /**< total send-on-chan messages received */ - mwChannelStat_U_BYTES_SENT, /**< total bytes sent, pre-encryption */ - mwChannelStat_U_BYTES_RECV, /**< total bytes received, post-decryption */ - mwChannelStat_OPENED_AT, /**< time when channel was opened */ - mwChannelStat_CLOSED_AT, /**< time when channel was closed */ -}; - - -/** @enum mwEncryptPolicy - - Policy for a channel, dictating what sort of encryption should be - used, if any, and when. -*/ -enum mwEncryptPolicy { - mwEncrypt_NONE = 0x0000, /**< encrypt none */ - mwEncrypt_WHATEVER = 0x0001, /**< encrypt whatever you want */ - mwEncrypt_ALL = 0x0002, /**< encrypt all, any cipher */ - mwEncrypt_RC2_40 = 0x1000, /**< encrypt all, RC2/40 cipher */ - mwEncrypt_RC2_128 = 0x2000, /**< encrypt all, RC2/128 cipher */ -}; - - -/** Allocate and initialize a channel set for a session */ -struct mwChannelSet *mwChannelSet_new(struct mwSession *); - - -/** Clear and deallocate a channel set. Closes, clears, and frees all - contained channels. */ -void mwChannelSet_free(struct mwChannelSet *); - - -/** Create an incoming channel with the given channel id. Channel's state - will be set to WAIT. Primarily for use in mw_session */ -struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *, guint32 id); - - -/** Create an outgoing channel. Its channel ID will be generated by - the owning channel set. Channel's state will be set to INIT */ -struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *); - - -/** Obtain a reference to a channel by its id. - @returns the channel matching chan, or NULL */ -struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan); - - -/** get the ID for a channel. 0x00 indicates an error, as that is not - a permissible value */ -guint32 mwChannel_getId(struct mwChannel *); - - -/** get the session for a channel. */ -struct mwSession *mwChannel_getSession(struct mwChannel *); - - -/** get the ID of the service for a channel. This may be 0x00 for NEW - channels */ -guint32 mwChannel_getServiceId(struct mwChannel *); - - -/** get the service for a channel. This may be NULL for NEW - channels */ -struct mwService *mwChannel_getService(struct mwChannel *); - - -/** associate a channel with an owning service */ -void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc); - - -/** get service-specific data. This is for use by service - implementations to easily associate information with the - channel */ -gpointer mwChannel_getServiceData(struct mwChannel *chan); - - -/** set service-specific data. This is for use by service - implementations to easily associate information with the - channel */ -void mwChannel_setServiceData(struct mwChannel *chan, - gpointer data, GDestroyNotify clean); - - -void mwChannel_removeServiceData(struct mwChannel *chan); - - -guint32 mwChannel_getProtoType(struct mwChannel *chan); - - -void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type); - - -guint32 mwChannel_getProtoVer(struct mwChannel *chan); - - -void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver); - - -/** Channel encryption policy. - - Cannot currently be set, used internally to automatically - negotiate ciphers. Future revisions may allow this to be specified - in a new channel to dictate channel encryption. - - @see enum mwEncryptPolicy -*/ -guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan); - - -guint32 mwChannel_getOptions(struct mwChannel *chan); - - -void mwChannel_setOptions(struct mwChannel *chan, guint32 options); - - -/** User at the other end of the channel. The target user for outgoing - channels, the creator for incoming channels */ -struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan); - - -/** direct reference to the create addtl information for a channel */ -struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *); - - -/** direct reference to the accept addtl information for a channel */ -struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *); - - -/** automatically adds instances of all ciphers in the session to the - list of supported ciphers for a channel */ -void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan); - - -/** add a cipher instance to a channel's list of supported - ciphers. Channel must be NEW. */ -void mwChannel_addSupportedCipherInstance(struct mwChannel *chan, - struct mwCipherInstance *ci); - - -/** the list of supported ciphers for a channel. This list will be - empty once a cipher has been selected for the channel */ -GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan); - - -/** select a cipher instance for a channel. A NULL instance indicates - that no encryption should be used. */ -void mwChannel_selectCipherInstance(struct mwChannel *chan, - struct mwCipherInstance *ci); - - -/** get the state of a channel */ -enum mwChannelState mwChannel_getState(struct mwChannel *); - - -/** obtain the value for a statistic field as a gpointer */ -gpointer mwChannel_getStatistic(struct mwChannel *chan, - enum mwChannelStatField stat); - - -/** Formally open a channel. - - For outgoing channels: instruct the session to send a channel - create message to the server, and to mark the channel (which must - be in INIT status) as being in WAIT status. - - For incoming channels: configures the channel according to options - in the channel create message. Marks the channel as being in WAIT - status -*/ -int mwChannel_create(struct mwChannel *chan); - - -/** Formally accept an incoming channel. Instructs the session to send - a channel accept message to the server, and to mark the channel as - being OPEN. */ -int mwChannel_accept(struct mwChannel *chan); - - -/** Destroy a channel. Sends a channel-destroy message to the server, - and perform cleanup to remove the channel. - - @param chan the channel to destroy - @param reason the reason code for closing the channel - @param data optional additional information -*/ -int mwChannel_destroy(struct mwChannel *chan, guint32 reason, - struct mwOpaque *data); - - -/** Compose a send-on-channel message, encrypt it as per the channel's - specification, and send it */ -int mwChannel_send(struct mwChannel *chan, guint32 msg_type, - struct mwOpaque *msg); - - -/** Compose a send-on-channel message, and if encrypt is TRUE, encrypt - it as per the channel's specification, and send it */ -int mwChannel_sendEncrypted(struct mwChannel *chan, - guint32 msg_type, struct mwOpaque *msg, - gboolean encrypt); - - -/** pass a create message to a channel for handling */ -void mwChannel_recvCreate(struct mwChannel *chan, - struct mwMsgChannelCreate *msg); - - -/** pass an accept message to a channel for handling */ -void mwChannel_recvAccept(struct mwChannel *chan, - struct mwMsgChannelAccept *msg); - - -/** pass a destroy message to a channel for handling */ -void mwChannel_recvDestroy(struct mwChannel *chan, - struct mwMsgChannelDestroy *msg); - - -/** Feed data into a channel. */ -void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg); - - -#endif - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_cipher.h --- a/src/protocols/sametime/meanwhile/mw_cipher.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,294 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_CIPHER_H -#define _MW_CIPHER_H - - -#include -#include "mw_common.h" - - -/* place-holders */ -struct mwChannel; -struct mwSession; - - -/** @enum mwCipherType - Common cipher types */ -enum mwCipherType { - mwCipher_RC2_40 = 0x0000, - mwCipher_RC2_128 = 0x0001, -}; - - -struct mwCipher; -struct mwCipherInstance; - - -/** Obtain an instance of a given cipher, which can be used for the - processing of a single channel. */ -typedef struct mwCipherInstance *(*mwCipherInstantiator) - (struct mwCipher *cipher, struct mwChannel *chan); - - -/** Generate a descriptor for use in a channel create message to - indicate the availability of this cipher - - @todo remove for 1.0 -*/ -typedef struct mwEncryptItem *(*mwCipherDescriptor) - (struct mwCipherInstance *instance); - - -/** Process (encrypt or decrypt, depending) the given data. The passed - buffer may be freed in processing and be replaced with a freshly - allocated buffer. The post-processed buffer must in turn be freed - after use */ -typedef int (*mwCipherProcessor) - (struct mwCipherInstance *ci, struct mwOpaque *data); - - -/** A cipher. Ciphers are primarily used to provide cipher instances - for bi-directional encryption on channels, but some may be used - for other activities. Expand upon this structure to create a - custom encryption provider. - @see mwCipherInstance */ -struct mwCipher { - - /** service this cipher is providing for - @see mwCipher_getSession */ - struct mwSession *session; - - guint16 type; /**< @see mwCipher_getType */ - const char *(*get_name)(void); /**< @see mwCipher_getName */ - const char *(*get_desc)(void); /**< @see mwCipher_getDesc */ - - /** Generate a new Cipher Instance for use on a channel - @see mwCipher_newInstance */ - mwCipherInstantiator new_instance; - - void (*offered)(struct mwCipherInstance *ci, struct mwEncryptItem *item); - struct mwEncryptItem *(*offer)(struct mwCipherInstance *ci); - void (*accepted)(struct mwCipherInstance *ci, struct mwEncryptItem *item); - struct mwEncryptItem *(*accept)(struct mwCipherInstance *ci); - - mwCipherProcessor encrypt; /**< @see mwCipherInstance_encrypt */ - mwCipherProcessor decrypt; /**< @see mwCipherInstance_decrypt */ - - /** prepare this cipher for being free'd - @see mwCipher_free */ - void (*clear)(struct mwCipher *c); - - /** clean up a cipher instance before being free'd - @see mwCipherInstance_free */ - void (*clear_instance)(struct mwCipherInstance *ci); -}; - - -/** An instance of a cipher. Expand upon this structure to contain - necessary state data - @see mwCipher */ -struct mwCipherInstance { - - /** the parent cipher. - @see mwCipherInstance_getCipher */ - struct mwCipher *cipher; - - /** the channel this instances processes - @see mwCipherInstance_getChannel */ - struct mwChannel *channel; -}; - - -struct mwCipher *mwCipher_new_RC2_40(struct mwSession *s); - - -struct mwCipher *mwCipher_new_RC2_128(struct mwSession *s); - - -struct mwSession *mwCipher_getSession(struct mwCipher *cipher); - - -guint16 mwCipher_getType(struct mwCipher *cipher); - - -const char *mwCipher_getName(struct mwCipher *cipher); - - -const char *mwCipher_getDesc(struct mwCipher *cipher); - - -struct mwCipherInstance *mwCipher_newInstance(struct mwCipher *cipher, - struct mwChannel *channel); - - -/** destroy a cipher */ -void mwCipher_free(struct mwCipher* cipher); - - -/** reference the parent cipher of an instance */ -struct mwCipher *mwCipherInstance_getCipher(struct mwCipherInstance *ci); - - -/** Indicates a cipher has been offered to our channel */ -void mwCipherInstance_offered(struct mwCipherInstance *ci, - struct mwEncryptItem *item); - - -/** Offer a cipher */ -struct mwEncryptItem * -mwCipherInstance_offer(struct mwCipherInstance *ci); - - -/** Indicates an offered cipher has been accepted */ -void mwCipherInstance_accepted(struct mwCipherInstance *ci, - struct mwEncryptItem *item); - - -/** Accept a cipher offered to our channel */ -struct mwEncryptItem * -mwCipherInstance_accept(struct mwCipherInstance *ci); - - -/** encrypt data */ -int mwCipherInstance_encrypt(struct mwCipherInstance *ci, - struct mwOpaque *data); - - -/** decrypt data */ -int mwCipherInstance_decrypt(struct mwCipherInstance *ci, - struct mwOpaque *data); - - -/** destroy a cipher instance */ -void mwCipherInstance_free(struct mwCipherInstance *ci); - - -/** - @section General Cipher Functions - - These functions are reused where encryption is necessary outside of - a channel (eg. session authentication) -*/ -/* @{ */ - - -/** generate some pseudo-random bytes - @param keylen count of bytes to write into key - @param key buffer to write keys into -*/ -void mwKeyRandom(guchar *key, gsize keylen); - - -/** Setup an Initialization Vector. IV must be at least 8 bytes */ -void mwIV_init(guchar *iv); - - -/** Expand a variable-length key into a 128-byte key (represented as - an an array of 64 ints) */ -void mwKeyExpand(int *ekey, const guchar *key, gsize keylen); - - -/** Encrypt data using an already-expanded key */ -void mwEncryptExpanded(const int *ekey, guchar *iv, - struct mwOpaque *in, - struct mwOpaque *out); - - -/** Encrypt data using an expanded form of the given key */ -void mwEncrypt(const guchar *key, gsize keylen, guchar *iv, - struct mwOpaque *in, struct mwOpaque *out); - - -/** Decrypt data using an already expanded key */ -void mwDecryptExpanded(const int *ekey, guchar *iv, - struct mwOpaque *in, - struct mwOpaque *out); - - -/** Decrypt data using an expanded form of the given key */ -void mwDecrypt(const guchar *key, gsize keylen, guchar *iv, - struct mwOpaque *in, struct mwOpaque *out); - - -/* @} */ - - -/** - @section Diffie-Hellman Functions - - These functions are reused where DH Key negotiation is necessary - outside of a channel (eg. session authentication). These are - wrapping a full multiple-precision integer math library, but most of - the functionality there-of is not exposed. Currently, the math is - provided by a copy of the public domain libmpi. - - for more information on the used MPI Library, visit - http://www.cs.dartmouth.edu/~sting/mpi/ -*/ -/* @{ */ - - -/** @struct mwMpi */ -struct mwMpi; - - -/** prepare a new mpi value */ -struct mwMpi *mwMpi_new(void); - - -/** destroy an mpi value */ -void mwMpi_free(struct mwMpi *i); - - -/** Import a value from an opaque */ -void mwMpi_import(struct mwMpi *i, struct mwOpaque *o); - - -/** Export a value into an opaque */ -void mwMpi_export(struct mwMpi *i, struct mwOpaque *o); - - -/** initialize and set a big integer to the Sametime Prime value */ -void mwMpi_setDHPrime(struct mwMpi *i); - - -/** initialize and set a big integer to the Sametime Base value */ -void mwMpi_setDHBase(struct mwMpi *i); - - -/** sets private to a randomly generated value, and calculates public - using the Sametime Prime and Base */ -void mwMpi_randDHKeypair(struct mwMpi *private, struct mwMpi *public); - - -/** sets the shared key value based on the remote and private keys, - using the Sametime Prime and Base */ -void mwMpi_calculateDHShared(struct mwMpi *shared, struct mwMpi *remote, - struct mwMpi *private); - - -/* @} */ - - -#endif - - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_client.h --- a/src/protocols/sametime/meanwhile/mw_client.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ - -#ifndef _MW_CLIENT_H -#define _MW_CLIENT_H - - -#include -#include - - -/* place-holders */ -struct mwChannel; -struct mwClient; -struct mwClientHandler; -struct mwConnection; -struct mwConnectionHandler; -struct mwMessage; -struct mwService; -struct mwSession; - - - -/* @file mw_client.h - -*/ - - - -/* @section Client - -*/ -/*@{*/ - - -struct mwClient; - - -typedef (struct mwConnectionHandler *)(*mwClientConnect) - (struct mwClient *c, const char *host); - - -struct mwClientHandler { - mwClientConnect connect; -} - - -struct mwClient * -mwClient_new(struct mwClientHandler *h); - - -struct mwChannel * -mwClient_newChannel(struct mwClient *client, - struct mwService *srvc); - - -struct mwChannel * -mwClient_newMasterChannel(struct mwClient *client, - struct mwSession *session); - - -int mwClient_sendKeepAlive(struct mwClient *client); - - -void mwClient_setUsesCountByte(struct mwClient *client, - gboolean use); - - -gboolean mwClient_getUsesCountByte(struct mwClient *client); - - -void mwClient_destroy(struct mwClient *client); - - -/*@}*/ - - - -/* @section Connection - -*/ -/*{*/ - - -struct mwConnection; - - -typedef (int)(*mwConnectionWrite) - (struct mwConnection *c, const char *buf, gsize len); - - -typedef (void)(*mwConnectionClose) - (struct mwConnection *c); - - -struct mwConnectionHandler { - mwConnectionWrite write; - mwConnectionClose close; -} - - -struct mwConnection * -mwConnection_new(struct mwConnectionHandler *h); - - -void mwConnection_recv(struct mwConnection *connection, - const char *buf, - gsize len); - - -void mwConnection_destroy(struct mwConnection *connection); - - -/*@}*/ - - - -/* @section Channel - -*/ -/*@{*/ - - -struct mwChannel; - - -int mwChannel_sendMessage(struct mwChannel *channel, - struct mwMessage *msg); - - -int mwChannel_send(struct mwChannel *channel, - guint32 type, - guint32 options, - struct mwOpaque *data); - - -int mwChannel_destroy(struct mwChannel *channel, - guint32 reason, - struct mwOpaque *info); - - -gboolean mwChannel_isMasterChannel(struct mwChannel *channel); - - -guint32 mwChannel_getId(struct mwChannel *channel); - - -enum mwChannelState mwChannel_getState(struct mwChannel *channel); - - - -/*@}*/ - - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_common.h --- a/src/protocols/sametime/meanwhile/mw_common.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,427 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_COMMON_H -#define _MW_COMMON_H - - -#include - - -/** @file mw_common.h - - Common data types and functions for handling those types. - - Functions in this file all fit into similar naming conventions of - TYPE_ACTION as per the activity they perform. The - following actions are available: - - void TYPE_put(struct mwPutBuffer *b, TYPE *val) - - marshalls val onto the buffer b. The buffer will grow as necessary - to fit all the data put into it. For guint16, guint32, and - gboolean, TYPE val is used instead of TYPE - \*val. - - void TYPE_get(struct mwGetBuffer *b, TYPE *val) - - unmarshals val from the buffer b. Failure (due to lack of - insufficient remaining buffer) is indicated in the buffer's error - field. A call to a _get function with a buffer in an error state - has to effect. - - void TYPE_clear(TYPE *val) - - zeros and frees internal members of val, but does not free val - itself. Needs to be called before free-ing any complex types which - have been unmarshalled from a TYPE_get or populated from a - TYPE_clone call to prevent memory leaks. - - void TYPE_clone(TYPE *to, TYPE *from) - - copies/clones members of from into to. May result in memory - allocation for some types. Note that to is not cleared - before-hand, it must already be in a pristine condition. - - gboolean TYPE_equal(TYPE *y, TYPE *z) - - simple equality test. -*/ - - -/** @struct mwPutBuffer - buffer to be written to */ -struct mwPutBuffer; - -/** @struct mwGetBuffer - buffer to be read from */ -struct mwGetBuffer; - - -/** A length of binary data, not null-terminated. */ -struct mwOpaque { - gsize len; /**< length of data. */ - guchar *data; /**< data, normally with no NULL termination */ -}; - - -/* 8.3.6 Login Types */ - -/** The type of login. Normally meaning the type of client code being - used to login with. - - If you know of any additional client identifiers, please add them - below or submit an RFE to the meanwhile tracker. -*/ -enum mwLoginType { - mwLogin_LIB = 0x1000, /**< official Lotus binary library */ - mwLogin_JAVA_WEB = 0x1001, /**< official Lotus Java applet */ - mwLogin_BINARY = 0x1002, /**< official Lotus binary application */ - mwLogin_JAVA_APP = 0x1003, /**< official Lotus Java application */ - mwLogin_LINKS = 0x100a, /**< official Sametime Links toolkit */ - - /* now we're getting crazy */ - mwLogin_NOTES_6_5 = 0x1200, - mwLogin_NOTES_6_5_3 = 0x1203, - mwLogin_NOTES_7_0_beta = 0x1210, - mwLogin_NOTES_7_0 = 0x1214, - mwLogin_ICT = 0x1300, - mwLogin_ICT_1_7_8_2 = 0x1302, - mwLogin_ICT_SIP = 0x1303, - mwLogin_NOTESBUDDY_4_14 = 0x1400, /**< 0xff00 mask? */ - mwLogin_NOTESBUDDY_4_15 = 0x1405, - mwLogin_NOTESBUDDY_4_16 = 0x1406, - mwLogin_SANITY = 0x1600, - mwLogin_ST_PERL = 0x1625, - mwLogin_PMR_ALERT = 0x1650, - mwLogin_TRILLIAN = 0x16aa, /**< http://sf.net/st-plugin/ */ - mwLogin_TRILLIAN_IBM = 0x16bb, - mwLogin_MEANWHILE = 0x1700, /**< Meanwhile library */ -}; - - -/* 8.2 Common Structures */ -/* 8.2.1 Login Info block */ - -struct mwLoginInfo { - char *login_id; /**< community-unique ID of the login */ - guint16 type; /**< @see mwLoginType */ - char *user_id; /**< community-unique ID of the user */ - char *user_name; /**< name of user (nick name, full name, etc) */ - char *community; /**< community name (usually domain name) */ - gboolean full; /**< if FALSE, following fields non-existant */ - char *desc; /**< implementation defined description */ - guint32 ip_addr; /**< ip addr of the login */ - char *server_id; /**< unique ID of login's server */ -}; - - -/* 8.2.2 Private Info Block */ - -struct mwUserItem { - gboolean full; /**< if FALSE, don't include name */ - char *id; /**< user id */ - char *community; /**< community */ - char *name; /**< user name */ -}; - - -struct mwPrivacyInfo { - gboolean deny; /**< deny (true) or allow (false) users */ - guint32 count; /**< count of users */ - struct mwUserItem *users; /**< the users list */ -}; - - -/* 8.3.5 User Status Types */ - -enum mwStatusType { - mwStatus_ACTIVE = 0x0020, - mwStatus_IDLE = 0x0040, - mwStatus_AWAY = 0x0060, - mwStatus_BUSY = 0x0080, -}; - - -/* 8.2.3 User Status Block */ - -struct mwUserStatus { - guint16 status; /**< @see mwStatusType */ - guint32 time; /**< last status change time in seconds */ - char *desc; /**< status description */ -}; - - -/* 8.2.4 ID Block */ - -struct mwIdBlock { - char *user; /**< user id (login id or empty for some services) */ - char *community; /**< community id (NULL for same community) */ -}; - - -/* 8.3.8.2 Awareness Presence Types */ - -/* @todo move mwAwareType, mwAwareIdBlock and mwAwareSnapshot into the - aware service and out of common */ - -/** type codes for mwAwareIdBlock */ -enum mwAwareType { - mwAware_USER = 0x0002, /**< a single user */ - mwAware_GROUP = 0x0003, /**< a group */ - mwAware_SERVER = 0x0008, /**< a server */ -}; - - -/* 8.4.2 Awareness Messages */ -/* 8.4.2.1 Awareness ID Block */ - -struct mwAwareIdBlock { - guint16 type; /**< @see mwAwareType */ - char *user; /**< user id */ - char *community; /**< community id (NULL for same community) */ -}; - - -/* 8.4.2.4 Snapshot */ - -struct mwAwareSnapshot { - struct mwAwareIdBlock id; - char *group; /**< group this id belongs to */ - gboolean online; /**< is this user online? */ - char *alt_id; /**< alternate ID, often same as id.user */ - struct mwUserStatus status; /**< status of this user */ - char *name; /**< Formatted version of ID */ -}; - - -/** encryption blocks */ -struct mwEncryptItem { - guint16 id; /**< cipher identifier */ - struct mwOpaque info; /**< cipher information */ -}; - - -/** @name buffer utility functions */ -/*@{*/ - - -/** allocate a new empty buffer */ -struct mwPutBuffer *mwPutBuffer_new(void); - - -/** write raw data to the put buffer */ -void mwPutBuffer_write(struct mwPutBuffer *b, gpointer data, gsize len); - - -/** destroy the buffer */ -void mwPutBuffer_free(struct mwPutBuffer *b); - - -/** move the buffer's data into an opaque, destroy the buffer */ -void mwPutBuffer_finalize(struct mwOpaque *to, struct mwPutBuffer *from); - - -/** allocate a new buffer with a copy of the given data */ -struct mwGetBuffer *mwGetBuffer_new(struct mwOpaque *data); - - -/** read len bytes of raw data from the get buffer into mem. If len is - greater than the count of bytes remaining in the buffer, the - buffer's error flag will NOT be set. - - @returns count of bytes successfully copied to mem */ -gsize mwGetBuffer_read(struct mwGetBuffer *b, gpointer mem, gsize len); - - -/** skip len bytes in the get buffer. If len is greater than the count - of bytes remaining in the buffer, the buffer's error flag will NOT - be set. - - @returns count of bytes successfully skipped */ -gsize mwGetBuffer_advance(struct mwGetBuffer *b, gsize len); - - -/** allocate a new buffer backed by the given data. Calling - mwGetBuffer_free will not result in the underlying data being - freed */ -struct mwGetBuffer *mwGetBuffer_wrap(const struct mwOpaque *data); - - -/** destroy the buffer */ -void mwGetBuffer_free(struct mwGetBuffer *b); - - -/** reset the buffer to the very beginning. Also clears the buffer's - error flag. */ -void mwGetBuffer_reset(struct mwGetBuffer *b); - - -/** count of remaining available bytes */ -gsize mwGetBuffer_remaining(struct mwGetBuffer *b); - - -/** TRUE if an error occurred while reading a basic type from this - buffer */ -gboolean mwGetBuffer_error(struct mwGetBuffer *b); - - -/*@}*/ - - -/** @name Basic Data Type Marshalling - The basic types are combined to construct the complex types. - */ -/*@{*/ - - -void guint16_put(struct mwPutBuffer *b, guint16 val); - -void guint16_get(struct mwGetBuffer *b, guint16 *val); - -guint16 guint16_peek(struct mwGetBuffer *b); - - -void guint32_put(struct mwPutBuffer *b, guint32 val); - -void guint32_get(struct mwGetBuffer *b, guint32 *val); - -guint32 guint32_peek(struct mwGetBuffer *b); - - -void gboolean_put(struct mwPutBuffer *b, gboolean val); - -void gboolean_get(struct mwGetBuffer *b, gboolean *val); - -gboolean gboolean_peek(struct mwGetBuffer *b); - - -void mwString_put(struct mwPutBuffer *b, const char *str); - -void mwString_get(struct mwGetBuffer *b, char **str); - - -void mwOpaque_put(struct mwPutBuffer *b, const struct mwOpaque *o); - -void mwOpaque_get(struct mwGetBuffer *b, struct mwOpaque *o); - -void mwOpaque_clear(struct mwOpaque *o); - -void mwOpaque_free(struct mwOpaque *o); - -void mwOpaque_clone(struct mwOpaque *to, const struct mwOpaque *from); - - -/*@}*/ - - -/** @name Complex Data Type Marshalling */ -/*@{*/ - - -void mwLoginInfo_put(struct mwPutBuffer *b, const struct mwLoginInfo *info); - -void mwLoginInfo_get(struct mwGetBuffer *b, struct mwLoginInfo *info); - -void mwLoginInfo_clear(struct mwLoginInfo *info); - -void mwLoginInfo_clone(struct mwLoginInfo *to, const struct mwLoginInfo *from); - - -void mwUserItem_put(struct mwPutBuffer *b, const struct mwUserItem *user); - -void mwUserItem_get(struct mwGetBuffer *b, struct mwUserItem *user); - -void mwUserItem_clear(struct mwUserItem *user); - -void mwUserItem_clone(struct mwUserItem *to, const struct mwUserItem *from); - - -void mwPrivacyInfo_put(struct mwPutBuffer *b, - const struct mwPrivacyInfo *info); - -void mwPrivacyInfo_get(struct mwGetBuffer *b, struct mwPrivacyInfo *info); - -void mwPrivacyInfo_clear(struct mwPrivacyInfo *info); - -void mwPrivacyInfo_clone(struct mwPrivacyInfo *to, - const struct mwPrivacyInfo *from); - - -void mwUserStatus_put(struct mwPutBuffer *b, - const struct mwUserStatus *stat); - -void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat); - -void mwUserStatus_clear(struct mwUserStatus *stat); - -void mwUserStatus_clone(struct mwUserStatus *to, - const struct mwUserStatus *from); - - -void mwIdBlock_put(struct mwPutBuffer *b, const struct mwIdBlock *id); - -void mwIdBlock_get(struct mwGetBuffer *b, struct mwIdBlock *id); - -void mwIdBlock_clear(struct mwIdBlock *id); - -void mwIdBlock_clone(struct mwIdBlock *to, - const struct mwIdBlock *from); - -guint mwIdBlock_hash(const struct mwIdBlock *idb); - -gboolean mwIdBlock_equal(const struct mwIdBlock *a, - const struct mwIdBlock *b); - - -void mwAwareIdBlock_put(struct mwPutBuffer *b, - const struct mwAwareIdBlock *idb); - -void mwAwareIdBlock_get(struct mwGetBuffer *b, struct mwAwareIdBlock *idb); - -void mwAwareIdBlock_clear(struct mwAwareIdBlock *idb); - -void mwAwareIdBlock_clone(struct mwAwareIdBlock *to, - const struct mwAwareIdBlock *from); - -guint mwAwareIdBlock_hash(const struct mwAwareIdBlock *a); - -gboolean mwAwareIdBlock_equal(const struct mwAwareIdBlock *a, - const struct mwAwareIdBlock *b); - - -void mwAwareSnapshot_get(struct mwGetBuffer *b, - struct mwAwareSnapshot *idb); - -void mwAwareSnapshot_clear(struct mwAwareSnapshot *idb); - -void mwAwareSnapshot_clone(struct mwAwareSnapshot *to, - const struct mwAwareSnapshot *from); - - -void mwEncryptItem_put(struct mwPutBuffer *b, - const struct mwEncryptItem *item); - -void mwEncryptItem_get(struct mwGetBuffer *b, struct mwEncryptItem *item); - -void mwEncryptItem_clear(struct mwEncryptItem *item); - -void mwEncryptItem_free(struct mwEncryptItem *item); - - -/*@}*/ - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_debug.c --- a/src/protocols/sametime/meanwhile/mw_debug.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -#include - -#include "mw_debug.h" - - - -#define FRMT1 "%02x" -#define FRMT2 FRMT1 FRMT1 " " -#define FRMT4 FRMT2 FRMT2 -#define FRMT8 FRMT4 FRMT4 -#define FRMT16 FRMT8 FRMT8 - -#define ADVANCE(b, n, c) {b += c; n -= c;} - - - -/** writes hex pairs of buf to str */ -static void pretty_print(GString *str, const guchar *buf, gsize len) { - while(len >= 16) { - /* write a complete line */ - g_string_append_printf(str, FRMT16, - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], - buf[12], buf[13], buf[14], buf[15]); - ADVANCE(buf, len, 16); - - /* append \n to each line but the last */ - if(len) g_string_append(str, "\n"); - } - - /* write an incomplete line */ - if(len >= 8) { - g_string_append_printf(str, FRMT8, - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); - ADVANCE(buf, len, 8); - } - - if(len >= 4) { - g_string_append_printf(str, FRMT4, - buf[0], buf[1], buf[2], buf[3]); - ADVANCE(buf, len, 4); - } - - if(len >= 2) { - g_string_append_printf(str, FRMT2, buf[0], buf[1]); - ADVANCE(buf, len, 2); - } - - if(len >= 1) { - g_string_append_printf(str, FRMT1, buf[0]); - ADVANCE(buf, len, 1); - } -} - - - -void mw_debug_datav(const guchar *buf, gsize len, - const char *msg, va_list args) { - GString *str; - - g_return_if_fail(buf != NULL || len == 0); - - str = g_string_new(NULL); - - if(msg) { - char *txt = g_strdup_vprintf(msg, args); - g_string_append_printf(str, "%s\n", txt); - g_free(txt); - } - pretty_print(str, buf, len); - - g_debug("%s", str->str); - g_string_free(str, TRUE); -} - - - -void mw_debug_data(const guchar *buf, gsize len, - const char *msg, ...) { - va_list args; - - g_return_if_fail(buf != NULL || len == 0); - - va_start(args, msg); - mw_debug_datav(buf, len, msg, args); - va_end(args); -} - - - -void mw_debug_opaquev(struct mwOpaque *o, const char *txt, va_list args) { - g_return_if_fail(o != NULL); - mw_debug_datav(o->data, o->len, txt, args); -} - - - -void mw_debug_opaque(struct mwOpaque *o, const char *txt, ...) { - va_list args; - - g_return_if_fail(o != NULL); - - va_start(args, txt); - mw_debug_opaquev(o, txt, args); - va_end(args); -} - - -void mw_mailme_datav(const guchar *buf, gsize len, - const char *info, va_list args) { - -#if defined(MW_MAILME) && MW_MAILME - GString *str; - char *txt; - - str = g_string_new(MW_MAILME_MESSAGE "\n" - " Please send mail to: " MW_MAILME_ADDRESS "\n" - MW_MAILME_CUT_START "\n"); - str = g_string_new(NULL); - - txt = g_strdup_vprintf(info, args); - g_string_append_printf(str, "%s\n", txt); - g_free(txt); - - if(buf && len) pretty_print(str, buf, len); - - g_string_append(str, MW_MAILME_CUT_STOP); - - g_debug(str->str); - g_string_free(str, TRUE); - -#else - mw_debug_datav(buf, len, info, args); - -#endif -} - - - -void mw_mailme_data(const guchar *buf, gsize len, - const char *info, ...) { - va_list args; - va_start(args, info); - mw_mailme_datav(buf, len, info, args); - va_end(args); -} - - - -void mw_mailme_opaquev(struct mwOpaque *o, const char *info, va_list args) { - mw_mailme_datav(o->data, o->len, info, args); -} - - - -void mw_mailme_opaque(struct mwOpaque *o, const char *info, ...) { - va_list args; - va_start(args, info); - mw_mailme_opaquev(o, info, args); - va_end(args); -} diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_debug.h --- a/src/protocols/sametime/meanwhile/mw_debug.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_DEBUG_H -#define _MW_DEBUG_H - - -#include -#include - -#include "mw_common.h" - - -/** replaces NULL strings with "(null)". useful for printf where - you're unsure that the %s will be non-NULL. Note that while the - linux printf will do this automatically, not all will. The others - will instead segfault */ -#define NSTR(str) ((str)? (str): "(null)") - - -#ifndef g_debug -#define g_debug(format...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) -#endif - - -#ifndef g_info -#define g_info(format...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) -#endif - - -#ifndef MW_MAILME_ADDRESS -/** email address used in mw_debug_mailme. */ -#define MW_MAILME_ADDRESS "meanwhile-devel@lists.sourceforge.net" -#endif - - -#ifndef MW_MAILME_CUT_START -#define MW_MAILME_CUT_START "-------- begin copy --------" -#endif - - -#ifndef MW_MAILME_CUT_STOP -#define MW_MAILME_CUT_STOP "--------- end copy ---------" -#endif - - -#ifndef MW_MAILME_MESSAGE -/** message used in mw_debug_mailme instructing user on what to do - with the debugging output produced from that function */ -#define MW_MAILME_MESSAGE "\n" \ - " Greetings! It seems that you've run across protocol data that the\n" \ - "Meanwhile library does not yet know about. As such, there may be\n" \ - "some unexpected behaviour in this session. If you'd like to help\n" \ - "resolve this issue, please copy and paste the following block into\n" \ - "an email to the address listed below with a brief explanation of\n" \ - "what you were doing at the time of this message. Thanks a lot!" -#endif - - -void mw_debug_datav(const guchar *buf, gsize len, - const char *info, va_list args); - - -void mw_debug_data(const guchar *buf, gsize len, - const char *info, ...); - - -void mw_debug_opaquev(struct mwOpaque *o, const char *info, va_list args); - - -void mw_debug_opaque(struct mwOpaque *o, const char *info, ...); - - -void mw_mailme_datav(const guchar *buf, gsize len, - const char *info, va_list args); - -void mw_mailme_data(const guchar *buf, gsize len, - const char *info, ...); - - -/** Outputs a hex dump of a mwOpaque with debugging info and a - pre-defined message. Identical to mw_mailme_opaque, but taking a - va_list argument */ -void mw_mailme_opaquev(struct mwOpaque *o, const char *info, va_list args); - - - -/** Outputs a hex dump of a mwOpaque with debugging info and a - pre-defined message. - - if MW_MAILME is undefined or false, this function acts the same as - mw_mailme_opaque. - - @arg block data to be printed in a hex block - @arg info a printf-style format string - - The resulting message is in the following format: - @code - MW_MAILME_MESSAGE - " Please send mail to: " MW_MAILME_ADDRESS - MW_MAILME_CUT_START - info - block - MW_MAILME_CUT_STOP - @endcode - */ -void mw_mailme_opaque(struct mwOpaque *o, const char *info, ...); - - -#endif - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_error.h --- a/src/protocols/sametime/meanwhile/mw_error.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_ERROR_H -#define _MW_ERROR_H - -#include - - -/** @file mw_error.h - - Common error code constants used by Meanwhile. - - Not all of these error codes (or even many, really) will ever - actually appear from Meanwhile. These are taken directly from the - houri draft, along with the minimal explanation for each. -*/ - - -/** reference to a new string appropriate for the given error code.*/ -char* mwError(guint32 code); - - -/* 8.3 Constants */ -/* 8.3.1 Error Codes */ -/* 8.3.1.1 General error/success codes */ - -/** @enum ERR_GENERAL - general error codes */ -enum ERR_GENERAL { - ERR_SUCCESS = 0x00000000, - ERR_FAILURE = 0x80000000, - ERR_REQUEST_DELAY = 0x00000001, - ERR_REQUEST_INVALID = 0x80000001, - ERR_NOT_LOGGED_IN = 0x80000002, - ERR_NOT_AUTHORIZED = 0x80000003, - ERR_ABORT = 0x80000004, - ERR_NO_ELEMENT = 0x80000005, - ERR_NO_USER = 0x80000006, - ERR_BAD_DATA = 0x80000007, - ERR_NOT_IMPLEMENTED = 0x80000008, - ERR_UNKNOWN_ERROR = 0x80000009, /* what is this? */ - ERR_STARVING = 0x8000000a, - ERR_CHANNEL_NO_SUPPORT = 0x8000000b, - ERR_CHANNEL_EXISTS = 0x8000000c, - ERR_SERVICE_NO_SUPPORT = 0x8000000d, - ERR_PROTOCOL_NO_SUPPORT = 0x8000000e, - ERR_PROTOCOL_NO_SUPPORT2 = 0x8000000f, /* duplicate? */ - ERR_VERSION_NO_SUPPORT = 0x80000010, - ERR_USER_SKETCHY = 0x80000011, - ERR_ALREADY_INITIALIZED = 0x80000013, - ERR_NOT_OWNER = 0x80000014, - ERR_TOKEN_INVALID = 0x80000015, - ERR_TOKEN_EXPIRED = 0x80000016, - ERR_TOKEN_IP_MISMATCH = 0x80000017, - ERR_PORT_IN_USE = 0x80000018, - ERR_NETWORK_DEAD = 0x80000019, - ERR_NO_MASTER_CHANNEL = 0x8000001a, - ERR_ALREADY_SUBSCRIBED = 0x8000001b, - ERR_NOT_SUBSCRIBED = 0x8000001c, - ERR_ENCRYPT_NO_SUPPORT = 0x8000001d, - ERR_ENCRYPT_UNINITIALIZED = 0x8000001e, - ERR_ENCRYPT_UNACCEPTABLE = 0x8000001f, - ERR_ENCRYPT_INVALID = 0x80000020, - ERR_NO_COMMON_ENCRYPT = 0x80000021, - ERR_CHANNEL_DESTROYED = 0x80000022, - ERR_CHANNEL_REDIRECTED = 0x80000023 -}; - - -/* 8.3.1.2 Connection/disconnection errors */ - -#define VERSION_MISMATCH 0x80000200 -#define INSUF_BUFFER 0x80000201 -#define NOT_IN_USE 0x80000202 -#define INSUF_SOCKET 0x80000203 -#define HARDWARE_ERROR 0x80000204 -#define NETWORK_DOWN 0x80000205 -#define HOST_DOWN 0x80000206 -#define HOST_UNREACHABLE 0x80000207 -#define TCPIP_ERROR 0x80000208 -#define FAT_MESSAGE 0x80000209 -#define PROXY_ERROR 0x8000020A -#define SERVER_FULL 0x8000020B -#define SERVER_NORESPOND 0x8000020C -#define CANT_CONNECT 0x8000020D -#define USER_REMOVED 0x8000020E -#define PROTOCOL_ERROR 0x8000020F -#define USER_RESTRICTED 0x80000210 -#define INCORRECT_LOGIN 0x80000211 -#define ENCRYPT_MISMATCH 0x80000212 -#define USER_UNREGISTERED 0x80000213 -#define VERIFICATION_DOWN 0x80000214 -#define USER_TOO_IDLE 0x80000216 -#define GUEST_IN_USE 0x80000217 -#define USER_EXISTS 0x80000218 -#define USER_RE_LOGIN 0x80000219 -#define BAD_NAME 0x8000021A -#define REG_MODE_NS 0x8000021B -#define WRONG_USER_PRIV 0x8000021C -#define NEED_EMAIL 0x8000021D -#define DNS_ERROR 0x8000021E -#define DNS_FATAL_ERROR 0x8000021F -#define DNS_NOT_FOUND 0x80000220 -#define CONNECTION_BROKEN 0x80000221 -#define CONNECTION_ABORTED 0x80000222 -#define CONNECTION_REFUSED 0x80000223 -#define CONNECTION_RESET 0x80000224 -#define CONNECTION_TIMED 0x80000225 -#define CONNECTION_CLOSED 0x80000226 -#define MULTI_SERVER_LOGIN 0x80000227 -#define MULTI_SERVER_LOGIN2 0x80000228 -#define MULTI_LOGIN_COMP 0x80000229 -#define MUTLI_LOGIN_ALREADY 0x8000022A -#define SERVER_BROKEN 0x8000022B -#define SERVER_PATH_OLD 0x8000022C -#define APPLET_LOGOUT 0x8000022D - - -/* 8.3.1.3 Client error codes */ - -/** @enum ERR_CLIENT - Client error codes */ -enum ERR_CLIENT { - ERR_CLIENT_USER_GONE = 0x80002000, /* user isn't here */ - ERR_CLIENT_USER_DND = 0x80002001, /* user is DND */ - ERR_CLIENT_USER_ELSEWHERE = 0x80002002, /* already logged in elsewhere */ -}; - - -/* 8.3.1.4 IM error codes */ - -/** @enum ERR_IM - IM error codes */ -enum ERR_IM { - ERR_IM_COULDNT_REGISTER = 0x80002003, - ERR_IM_ALREADY_REGISTERED = 0x80002004, - - /** apparently, this is used to mean that the requested feature (per - the channel create addtl data) is not supported by the client on - the other end of the IM channel */ - ERR_IM_NOT_REGISTERED = 0x80002005, -}; - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_message.h --- a/src/protocols/sametime/meanwhile/mw_message.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,295 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_MESSAGE_H -#define _MW_MESSAGE_H - - -#include -#include "mw_common.h" - - -/** Cast a pointer to a message subtype (eg, mwMsgHandshake, - mwMsgAdmin) into a pointer to a mwMessage */ -#define MW_MESSAGE(msg) (&msg->head) - - -/** Indicates the type of a message. */ -enum mwMessageType { - mwMessage_HANDSHAKE = 0x0000, /**< mwMsgHandshake */ - mwMessage_HANDSHAKE_ACK = 0x8000, /**< mwMsgHandshakeAck */ - mwMessage_LOGIN = 0x0001, /**< mwMsgLogin */ - mwMessage_LOGIN_ACK = 0x8001, /**< mwMsgLoginAck */ - mwMessage_LOGIN_REDIRECT = 0x0018, /**< mwMsgLoginRedirect */ - mwMessage_LOGIN_CONTINUE = 0x0016, /**< mwMsgLoginContinue */ - - mwMessage_CHANNEL_CREATE = 0x0002, /**< mwMsgChannelCreate */ - mwMessage_CHANNEL_DESTROY = 0x0003, /**< mwMsgChannelDestroy */ - mwMessage_CHANNEL_SEND = 0x0004, /**< mwMsgChannelSend */ - mwMessage_CHANNEL_ACCEPT = 0x0006, /**< mwMsgChannelAccept */ - - mwMessage_SET_USER_STATUS = 0x0009, /**< mwMsgSetUserStatus */ - mwMessage_SET_PRIVACY_LIST = 0x000b, /**< mwMsgSetPrivacyList */ - mwMessage_SENSE_SERVICE = 0x0011, /**< mwMsgSenseService */ - mwMessage_ADMIN = 0x0019, /**< mwMsgAdmin */ - mwMessage_ANNOUNCE = 0x0022, /**< mwMsgAnnounce */ -}; - - -enum mwMessageOption { - mwMessageOption_ENCRYPT = 0x4000, /**< message data is encrypted */ - mwMessageOption_HAS_ATTRIBS = 0x8000, /**< message has attributes */ -}; - - -/** @see mwMessageOption */ -#define MW_MESSAGE_HAS_OPTION(msg, opt) \ - ((msg)->options & (opt)) - - -struct mwMessage { - guint16 type; /**< @see mwMessageType */ - guint16 options; /**< @see mwMessageOption */ - guint32 channel; /**< ID of channel message is intended for */ - struct mwOpaque attribs; /**< optional message attributes */ -}; - - - -/** Allocate and initialize a new message of the specified type */ -struct mwMessage *mwMessage_new(enum mwMessageType type); - - -/** build a message from its representation */ -struct mwMessage *mwMessage_get(struct mwGetBuffer *b); - - -void mwMessage_put(struct mwPutBuffer *b, struct mwMessage *msg); - - -void mwMessage_free(struct mwMessage *msg); - - -/* 8.4 Messages */ -/* 8.4.1 Basic Community Messages */ -/* 8.4.1.1 Handshake */ - -struct mwMsgHandshake { - struct mwMessage head; - guint16 major; /**< client's major version number */ - guint16 minor; /**< client's minor version number */ - guint32 srvrcalc_addr; /**< 0.0.0.0 */ - guint16 login_type; /**< @see mwLoginType */ - guint32 loclcalc_addr; /**< local public IP */ - guint16 unknown_a; /**< normally 0x0100 */ - guint32 unknown_b; /**< normally 0x00000000 */ - char *local_host; /**< name of client host */ -}; - - -/* 8.4.1.2 HandshakeAck */ - -struct mwMsgHandshakeAck { - struct mwMessage head; - guint16 major; /**< server's major version number */ - guint16 minor; /**< server's minor version number */ - guint32 srvrcalc_addr; /**< server-calculated address */ - guint32 magic; /**< four bytes of something */ - struct mwOpaque data; /**< server's DH public key for auth */ -}; - - -/* 8.3.7 Authentication Types */ - -enum mwAuthType { - mwAuthType_PLAIN = 0x0000, - mwAuthType_TOKEN = 0x0001, - mwAuthType_ENCRYPT = 0x0002, /**< @todo remove for 1.0 */ - mwAuthType_RC2_40 = 0x0002, - mwAuthType_RC2_128 = 0x0004, -}; - - -/* 8.4.1.3 Login */ - -struct mwMsgLogin { - struct mwMessage head; - guint16 login_type; /**< @see mwLoginType */ - char *name; /**< user identification */ - guint16 auth_type; /**< @see mwAuthType */ - struct mwOpaque auth_data; /**< authentication data */ -}; - - -/* 8.4.1.4 LoginAck */ - -struct mwMsgLoginAck { - struct mwMessage head; - struct mwLoginInfo login; - struct mwPrivacyInfo privacy; - struct mwUserStatus status; -}; - - -/* 8.4.1.5 LoginCont */ - -struct mwMsgLoginContinue { - struct mwMessage head; -}; - - -/* 8.4.1.6 AuthPassed */ - -struct mwMsgLoginRedirect { - struct mwMessage head; - char *host; - char *server_id; -}; - - -/* 8.4.1.7 CreateCnl */ - -/** an offer of encryption items */ -struct mwEncryptOffer { - guint16 mode; /**< encryption mode */ - GList *items; /**< list of mwEncryptItem offered */ - guint16 extra; /**< encryption mode again? */ - gboolean flag; /**< unknown flag */ -}; - - -struct mwMsgChannelCreate { - struct mwMessage head; - guint32 reserved; /**< unknown reserved data */ - guint32 channel; /**< intended ID for new channel */ - struct mwIdBlock target; /**< User ID. for service use */ - guint32 service; /**< ID for the target service */ - guint32 proto_type; /**< protocol type for the service */ - guint32 proto_ver; /**< protocol version for the service */ - guint32 options; /**< options */ - struct mwOpaque addtl; /**< service-specific additional data */ - gboolean creator_flag; /**< indicate presence of creator information */ - struct mwLoginInfo creator; - struct mwEncryptOffer encrypt; -}; - - -/* 8.4.1.8 AcceptCnl */ - -/** a selected encryption item from those offered */ -struct mwEncryptAccept { - guint16 mode; /**< encryption mode */ - struct mwEncryptItem *item; /**< chosen mwEncryptItem (optional) */ - guint16 extra; /**< encryption mode again? */ - gboolean flag; /**< unknown flag */ -}; - - -struct mwMsgChannelAccept { - struct mwMessage head; - guint32 service; /**< ID for the channel's service */ - guint32 proto_type; /**< protocol type for the service */ - guint32 proto_ver; /**< protocol version for the service */ - struct mwOpaque addtl; /**< service-specific additional data */ - gboolean acceptor_flag; /**< indicate presence of acceptor information */ - struct mwLoginInfo acceptor; - struct mwEncryptAccept encrypt; -}; - - -/* 8.4.1.9 SendOnCnl */ - -struct mwMsgChannelSend { - struct mwMessage head; - - /** message type. each service defines its own send types. Type IDs - are only necessarily unique within a given service. */ - guint16 type; - - /** protocol data to be interpreted by the handling service */ - struct mwOpaque data; -}; - - -/* 8.4.1.10 DestroyCnl */ - -struct mwMsgChannelDestroy { - struct mwMessage head; - guint32 reason; /**< reason for closing the channel. */ - struct mwOpaque data; /**< additional information */ -}; - - -/* 8.4.1.11 SetUserStatus */ - -struct mwMsgSetUserStatus { - struct mwMessage head; - struct mwUserStatus status; -}; - - -/* 8.4.1.12 SetPrivacyList */ - -struct mwMsgSetPrivacyList { - struct mwMessage head; - struct mwPrivacyInfo privacy; -}; - - -/* Sense Service */ - -/** Sent to the server to request the presense of a service by its - ID. Sent to the client to indicate the presense of such a - service */ -struct mwMsgSenseService { - struct mwMessage head; - guint32 service; -}; - - -/* Admin */ - -/** An administrative broadcast message */ -struct mwMsgAdmin { - struct mwMessage head; - char *text; -}; - - -/* Announce */ - -/** An announcement between users */ -struct mwMsgAnnounce { - struct mwMessage head; - gboolean sender_present; /**< indicates presence of sender data */ - struct mwLoginInfo sender; /**< who sent the announcement */ - guint16 unknown_a; /**< unknown A. Usually 0x00 */ - gboolean may_reply; /**< replies allowed */ - char *text; /**< text of message */ - - /** list of (char *) indicating recipients. Recipient users are in - the format "@U username" and recipient NAB groups are in the - format "@G groupname" */ - GList *recipients; -}; - - -#endif - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_service.h --- a/src/protocols/sametime/meanwhile/mw_service.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,360 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SERVICE_H -#define _MW_SERVICE_H - - -#include "mw_common.h" - - -/* place-holders */ -struct mwChannel; -struct mwService; -struct mwSession; -struct mwMsgChannelCreate; -struct mwMsgChannelAccept; -struct mwMsgChannelDestroy; - - -/** State-tracking for a service */ -enum mwServiceState { - mwServiceState_STOPPED, /**< the service is not active */ - mwServiceState_STOPPING, /**< the service is shutting down */ - mwServiceState_STARTED, /**< the service is active */ - mwServiceState_STARTING, /**< the service is starting up */ - mwServiceState_ERROR, /**< error in service, shutting down */ - mwServiceState_UNKNOWN, /**< error determining state */ -}; - - -/** Casts a concrete service (such as mwServiceAware) into a mwService */ -#define MW_SERVICE(srv) ((struct mwService *) srv) - - -#define MW_SERVICE_IS_STATE(srvc, state) \ - (mwService_getState(MW_SERVICE(srvc)) == (state)) - -#define MW_SERVICE_IS_STOPPED(srvc) \ - MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPED) - -#define MW_SERVICE_IS_STOPPING(srvc) \ - MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPING) - -#define MW_SERVICE_IS_STARTED(srvc) \ - MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTED) - -#define MW_SERVICE_IS_STARTING(srvc) \ - MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTING) - - -/** If a service is STARTING or STARTED, it's considered LIVE */ -#define MW_SERVICE_IS_LIVE(srvc) \ - (MW_SERVICE_IS_STARTING(srvc) || MW_SERVICE_IS_STARTED(srvc)) - -/** If a service is STOPPING or STOPPED, it's considered DEAD */ -#define MW_SERVICE_IS_DEAD(srvc) \ - (MW_SERVICE_IS_STOPPING(srvc) || MW_SERVICE_IS_STOPPED(srvc)) - - -typedef void (*mwService_funcStart)(struct mwService *service); - -typedef void (*mwService_funcStop)(struct mwService *service); - -typedef void (*mwService_funcClear)(struct mwService *service); - -typedef const char *(*mwService_funcGetName)(struct mwService *service); - -typedef const char *(*mwService_funcGetDesc)(struct mwService *service); - -/** @todo remove msg and replace with appropriate additional parameters */ -typedef void (*mwService_funcRecvCreate) - (struct mwService *service, - struct mwChannel *channel, - struct mwMsgChannelCreate *msg); - -/** @todo remove msg and replace with appropriate additional parameters */ -typedef void (*mwService_funcRecvAccept) - (struct mwService *service, - struct mwChannel *channel, - struct mwMsgChannelAccept *msg); - -/** @todo remove msg and replace with appropriate additional parameters */ -typedef void (*mwService_funcRecvDestroy) - (struct mwService *service, - struct mwChannel *channel, - struct mwMsgChannelDestroy *msg); - -typedef void (*mwService_funcRecv) - (struct mwService *service, - struct mwChannel *channel, - guint16 msg_type, - struct mwOpaque *data); - - -/** A service is the recipient of sendOnCnl messages sent over - channels marked with the corresponding service id. Services - provide functionality such as IM relaying, Awareness tracking and - notification, and Conference handling. It is a service's - responsibility to accept or destroy channels, and to process data - sent over those channels */ -struct mwService { - - /** the unique identifier by which this service is registered. The - type value also relates to those channels which will be directed - to this service */ - guint32 type; - - /** the state of this service. Determines whether or not the session - should call the start function upon receipt of a service - available message. Should not be set or checked by hand. - - @relates mwService_getState */ - enum mwServiceState state; - - /** session this service is attached to. - @relates mwService_getSession */ - struct mwSession *session; - - /** @return string short name of the service - @relates mwService_getName */ - mwService_funcGetName get_name; - - /** @return string short description of the service - @relates mwService_getDesc */ - mwService_funcGetDesc get_desc; - - /** The service's channel create handler. Called when the session - receives a channel create message with a service matching this - service's type. - - @relates mwService_recvCreate */ - mwService_funcRecvCreate recv_create; - - /** The service's channel accept handler. Called when the session - receives a channel accept message for a channel with a service - matching this service's type. - - @relates mwService_recvAccept */ - mwService_funcRecvAccept recv_accept; - - /** The service's channel destroy handler. Called when the session - receives a channel destroy message for a channel with a service - matching this service's type. - - @relates mwService_recvDestroy */ - mwService_funcRecvDestroy recv_destroy; - - /** The service's input handler. Called when the session receives - data on a channel belonging to this service - - @relates mwService_recv */ - mwService_funcRecv recv; - - /** The service's start handler. Called upon the receipt of a - service available message. - - @relates mwService_start */ - mwService_funcStart start; - - /** The service's stop handler. Called when the session is shutting - down, or when the service is free'd. - - @relates mwService_stop */ - mwService_funcStop stop; - - /** The service's cleanup handler. Service implementations should - presume that mwService::stop will be called first. The clear - handler is not for shutting down channels or generating - non-cleanup side-effects, it is only for handling tear-down of - the service, and will only be called once for any instance. - - @relates mwService_free */ - mwService_funcClear clear; - - /** Optional client data, not for use by service implementations - - @relates mwService_getClientData - @relates mwService_setClientData */ - gpointer client_data; - - /** Optional client data cleanup function. Called with client_data - from mwService_free - - @relates mwService_getClientData - @relates mwService_setClientData */ - GDestroyNotify client_cleanup; -}; - - -/** @name Service Extension API - - These functions are for use by service implementations */ -/*@{*/ - - -/** Prepares a newly allocated service for use. - - Intended for use by service implementations, rather than by code - utilizing a service. - - The service state will be initialized to STOPPED. - - @param service the service to initialize - @param session the service's owning session - @param service_type the service ID number */ -void mwService_init(struct mwService *service, - struct mwSession *session, - guint32 service_type); - - -/** Indicate that a service is started. To be used by service - implementations when the service is fully started. */ -void mwService_started(struct mwService *service); - - -/** Indicate that a service is stopped. To be used by service - implementations when the service is fully stopped. */ -void mwService_stopped(struct mwService *service); - - -/*@}*/ - - -/** @name General Services API - - These functions provide unified access to the general functions of - a client service, with some simple sanity-checking. */ -/*@{*/ - - -/** Triggers the recv_create handler on the service. - - @param service the service to handle the message - @param channel the channel being created - @param msg the channel create message */ -void mwService_recvCreate(struct mwService *service, - struct mwChannel *channel, - struct mwMsgChannelCreate *msg); - - -/** Triggers the recv_accept handler on the service. - - @param service the service to handle the message - @param channel the channel being accepted - @param msg the channel accept message */ -void mwService_recvAccept(struct mwService *service, - struct mwChannel *channel, - struct mwMsgChannelAccept *msg); - - -/** Triggers the recv_destroy handler on the service. - - @param service the service to handle the message - @param channel the channel being destroyed - @param msg the channel destroy message */ -void mwService_recvDestroy(struct mwService *service, - struct mwChannel *channel, - struct mwMsgChannelDestroy *msg); - - -/** Triggers the input handler on the service - - @param service the service to receive the input - @param channel the channel the input was received from - @param msg_type the service-dependant message type - @param data the message data */ -void mwService_recv(struct mwService *service, - struct mwChannel *channel, - guint16 msg_type, - struct mwOpaque *data); - - -/** @return the appropriate type id for the service */ -guint32 mwService_getType(struct mwService *); - - -/** @return string short name of the service */ -const char *mwService_getName(struct mwService *); - - -/** @return string short description of the service */ -const char *mwService_getDesc(struct mwService *); - - -/** @return the service's session */ -struct mwSession *mwService_getSession(struct mwService *service); - - -/** @returns the service's state -*/ -enum mwServiceState mwService_getState(struct mwService *service); - - -/** Triggers the start handler for the service. Normally called from - the session upon receipt of a service available message. Service - implementations should use this handler to open any necessary - channels, etc. Checks that the service is STOPPED, or returns. - - @param service The service to start -*/ -void mwService_start(struct mwService *service); - - -/** Triggers the stop handler for the service. Normally called from - the session before closing down the connection. Checks that the - service is STARTED or STARTING, or returns - - @param service The service to stop -*/ -void mwService_stop(struct mwService *service); - - -/** Frees memory used by a service. Will trigger the stop handler if - the service is STARTED or STARTING. Triggers clear handler to allow - cleanup. - - @param service The service to clear and free -*/ -void mwService_free(struct mwService *service); - - -/** Associates client data with service. If there is existing data, it - will not have its cleanup function called. Client data is not for - use by service implementations. Rather, it is for use by client - code which may later make use of those service implementations. */ -void mwService_setClientData(struct mwService *service, - gpointer data, GDestroyNotify cleanup); - - -/** Reference associated client data */ -gpointer mwService_getClientData(struct mwService *service); - - -/** Removes client data from service. If there is a cleanup function, - it will be called. */ -void mwService_removeClientData(struct mwService *service); - - -/*@}*/ - - -#endif - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_session.h --- a/src/protocols/sametime/meanwhile/mw_session.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,387 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SESSION_H -#define _MW_SESSION_H - - -/** @file mw_session.h - - A client session with a Sametime server is encapsulated in the - mwSession structure. The session controls channels, provides - encryption ciphers, and manages services using messages over the - Master channel. - - A session does not directly communicate with a socket or stream, - instead the session is initialized from client code with an - instance of a mwSessionHandler structure. This session handler - provides functions as call-backs for common session events, and - provides functions for writing-to and closing the connection to - the server. - - A session does not perform reads on a socket directly. Instead, it - must be fed from an outside source via the mwSession_recv - function. The session will buffer and merge data passed to this - function to build complete protocol messages, and will act upon - each complete message accordingly. -*/ - - -#include "mw_common.h" - - -struct mwChannelSet; -struct mwCipher; -struct mwMessage; -struct mwService; - - -/** default protocol major version */ -#define MW_PROTOCOL_VERSION_MAJOR 0x001e - - -/** default protocol minor version */ -#define MW_PROTOCOL_VERSION_MINOR 0x001d - - -/** @section Session Properties - for use with mwSession_setProperty, et al. -*/ -/*@{*/ - -/** char *, session user ID */ -#define mwSession_AUTH_USER_ID "session.auth.user" - -/** char *, plaintext password */ -#define mwSession_AUTH_PASSWORD "session.auth.password" - -/** struct mwOpaque *, authentication token */ -#define mwSession_AUTH_TOKEN "session.auth.token" - -/** char *, hostname of client */ -#define mwSession_CLIENT_HOST "client.host" - -/** guint32, local IP of client */ -#define mwSession_CLIENT_IP "client.ip" - -/** guint16, major version of client protocol */ -#define mwSession_CLIENT_VER_MAJOR "client.version.major" - -/** guint16, minor version of client protocol */ -#define mwSession_CLIENT_VER_MINOR "client.version.minor" - -/** guint16, client type identifier */ -#define mwSession_CLIENT_TYPE_ID "client.id" - -/** guint16, major version of server protocol */ -#define mwSession_SERVER_VER_MAJOR "server.version.major" - -/** guint16, minor version of server protocol */ -#define mwSession_SERVER_VER_MINOR "server.version.minor" - -/*@}*/ - - -enum mwSessionState { - mwSession_STARTING, /**< session is starting */ - mwSession_HANDSHAKE, /**< session has sent handshake */ - mwSession_HANDSHAKE_ACK, /**< session has received handshake ack */ - mwSession_LOGIN, /**< session has sent login */ - mwSession_LOGIN_REDIR, /**< session has been redirected */ - mwSession_LOGIN_ACK, /**< session has received login ack */ - mwSession_STARTED, /**< session is active */ - mwSession_STOPPING, /**< session is shutting down */ - mwSession_STOPPED, /**< session is stopped */ - mwSession_UNKNOWN, /**< indicates an error determining state */ - mwSession_LOGIN_CONT, /**< session has sent a login continue */ -}; - - -#define mwSession_isState(session, state) \ - (mwSession_getState((session)) == (state)) - -#define mwSession_isStarting(s) \ - (mwSession_isState((s), mwSession_STARTING) || \ - mwSession_isState((s), mwSession_HANDSHAKE) || \ - mwSession_isState((s), mwSession_HANDSHAKE_ACK) || \ - mwSession_isState((s), mwSession_LOGIN) || \ - mwSession_isState((s), mwSession_LOGIN_ACK) || \ - mwSession_isState((s), mwSession_LOGIN_REDIR) || \ - mwSession_isState((s), mwSession_LOGIN_CONT)) - -#define mwSession_isStarted(s) \ - (mwSession_isState((s), mwSession_STARTED)) - -#define mwSession_isStopping(s) \ - (mwSession_isState((s), mwSession_STOPPING)) - -#define mwSession_isStopped(s) \ - (mwSession_isState((s), mwSession_STOPPED)) - - -/** @struct mwSession - - Represents a Sametime client session */ -struct mwSession; - - -/** @struct mwSessionHandler - - session handler. Structure which interfaces a session with client - code to provide I/O and event handling */ -struct mwSessionHandler { - - /** write data to the server connection. Required. Should return - zero for success, non-zero for error */ - int (*io_write)(struct mwSession *, const guchar *buf, gsize len); - - /** close the server connection. Required */ - void (*io_close)(struct mwSession *); - - /** triggered by mwSession_free. Optional. Put cleanup code here */ - void (*clear)(struct mwSession *); - - /** Called when the session has changed status. - - @see mwSession_getStateInfo for uses of info field - - @param s the session - @param state the session's state - @param info additional state information */ - void (*on_stateChange)(struct mwSession *s, - enum mwSessionState state, gpointer info); - - /** called when privacy information has been sent or received - - @see mwSession_getPrivacyInfo - */ - void (*on_setPrivacyInfo)(struct mwSession *); - - /** called when user status has changed - - @see mwSession_getUserStatus */ - void (*on_setUserStatus)(struct mwSession *); - - /** called when an admin messages has been received */ - void (*on_admin)(struct mwSession *, const char *text); - - /** called when an announcement arrives */ - void (*on_announce)(struct mwSession *, struct mwLoginInfo *from, - gboolean may_reply, const char *text); - -}; - - -/** allocate a new session */ -struct mwSession *mwSession_new(struct mwSessionHandler *); - - -/** stop, clear, free a session. Does not free contained ciphers or - services, these must be taken care of explicitly. */ -void mwSession_free(struct mwSession *); - - -/** obtain a reference to the session's handler */ -struct mwSessionHandler *mwSession_getHandler(struct mwSession *); - - -/** instruct the session to begin. This will result in the initial - handshake message being sent. */ -void mwSession_start(struct mwSession *); - - -/** instruct the session to shut down with the following reason - code. */ -void mwSession_stop(struct mwSession *, guint32 reason); - - -/** Data is buffered, unpacked, and parsed into a message, then - processed accordingly. */ -void mwSession_recv(struct mwSession *, const guchar *, gsize); - - -/** primarily used by services to have messages serialized and sent - @param s session to send message over - @param msg message to serialize and send - @returns 0 for success */ -int mwSession_send(struct mwSession *s, struct mwMessage *msg); - - -/** sends the keepalive byte */ -int mwSession_sendKeepalive(struct mwSession *s); - - -/** respond to a login redirect message by forcing the login sequence - to continue through the immediate server. */ -int mwSession_forceLogin(struct mwSession *s); - - -/** send an announcement to a list of users/groups. Targets of - announcement must be in the same community as the session. - - @param s session to send announcement from - @param may_reply permit clients to reply. Not all clients honor this. - @param text text of announcement - @param recipients list of recipients. Each recipient is specified - by a single string, prefix with "@U " for users - and "@G " for Notes Address Book groups. -*/ -int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply, - const char *text, const GList *recipients); - - -/** set the internal privacy information, and inform the server as - necessary. Triggers the on_setPrivacyInfo call-back. */ -int mwSession_setPrivacyInfo(struct mwSession *, struct mwPrivacyInfo *); - - -/** direct reference to the session's internal privacy structure */ -struct mwPrivacyInfo *mwSession_getPrivacyInfo(struct mwSession *); - - -/** reference the login information for the session */ -struct mwLoginInfo *mwSession_getLoginInfo(struct mwSession *); - - -/** set the internal user status state, and inform the server as - necessary. Triggers the on_setUserStatus call-back */ -int mwSession_setUserStatus(struct mwSession *, struct mwUserStatus *); - - -struct mwUserStatus *mwSession_getUserStatus(struct mwSession *); - - -/** current status of the session */ -enum mwSessionState mwSession_getState(struct mwSession *); - - -/** additional status-specific information. Depending on the state of - the session, this value has different meaning. - - @li @c mwSession_STOPPING guint32 error code causing - the session to shut down - - @li @c mwSession_STOPPED guint32 error code causing - the session to shut down - - @li @c mwSession_LOGIN_REDIR (char *) host to redirect - to -*/ -gpointer mwSession_getStateInfo(struct mwSession *); - - -struct mwChannelSet *mwSession_getChannels(struct mwSession *); - - -/** adds a service to the session. If the session is started (or when - the session is successfully started) and the service has a start - function, the session will request service availability from the - server. On receipt of the service availability notification, the - session will call the service's start function. - - @return TRUE if the session was added correctly */ -gboolean mwSession_addService(struct mwSession *, struct mwService *); - - -/** find a service by its type identifier */ -struct mwService *mwSession_getService(struct mwSession *, guint32 type); - - -/** removes a service from the session. If the session is started and - the service has a stop function, it will be called. Returns the - removed service */ -struct mwService *mwSession_removeService(struct mwSession *, guint32 type); - - -/** a GList of services in this session. The GList needs to be freed - after use */ -GList *mwSession_getServices(struct mwSession *); - - -/** instruct a STARTED session to check the server for the presense of - a given service. The service will be automatically started upon - receipt of an affirmative reply from the server. This function is - automatically called upon all services in a session when the - session is fully STARTED. - - Services which terminate due to an error may call this on - themselves to re-initialize when their server-side counterpart is - made available again. - - @param s owning session - @param type service type ID */ -void mwSession_senseService(struct mwSession *s, guint32 type); - - -/** adds a cipher to the session. */ -gboolean mwSession_addCipher(struct mwSession *, struct mwCipher *); - - -/** find a cipher by its type identifier */ -struct mwCipher *mwSession_getCipher(struct mwSession *, guint16 type); - - -/** remove a cipher from the session */ -struct mwCipher *mwSession_removeCipher(struct mwSession *, guint16 type); - - -/** a GList of ciphers in this session. The GList needs to be freed - after use */ -GList *mwSession_getCiphers(struct mwSession *); - - -/** associate a key:value pair with the session. If an existing value is - associated with the same key, it will have its clear function called - and will be replaced with the new value */ -void mwSession_setProperty(struct mwSession *, const char *key, - gpointer val, GDestroyNotify clear); - - -/** obtain the value of a previously set property, or NULL */ -gpointer mwSession_getProperty(struct mwSession *, const char *key); - - -/** remove a property, calling the optional GDestroyNotify function - indicated in mwSession_setProperty if applicable */ -void mwSession_removeProperty(struct mwSession *, const char *key); - - -/** associate arbitrary data with the session for use by the client - code. Only client applications should use this, never services. - - @param session the session to associate the data with - @param data arbitrary client data - @param clear optional cleanup function called on data from - mwSession_removeClientData and mwSession_free -*/ -void mwSession_setClientData(struct mwSession *session, - gpointer data, GDestroyNotify clear); - - -gpointer mwSession_getClientData(struct mwSession *session); - - -/** remove client data, calling the optional GDestroyNotify function - indicated in mwSession_setClientData if applicable */ -void mwSession_removeClientData(struct mwSession *session); - - -#endif - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_aware.h --- a/src/protocols/sametime/meanwhile/mw_srvc_aware.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SRVC_AWARE_H -#define _MW_SRVC_AWARE_H - - -#include "mw_common.h" - - -/** @file mw_srvc_aware.h - - The aware service... - - @todo remove the whole idea of an instantiated mwAwareList and - instead use arbitrary pointers (including NULL) as keys to - internally stored lists. This removes the problem of the service - free'ing its lists and invalidating mwAwareList references from - client code. -*/ - - -/** Type identifier for the aware service */ -#define mwService_AWARE 0x00000011 - - -/** @struct mwServiceAware - - Instance of an Aware Service. The members of this structure are - not made available. Accessing the parts of an aware service should - be performed through the appropriate functions. Note that - instances of this structure can be safely cast to a mwService. -*/ -struct mwServiceAware; - - -/** @struct mwAwareList - - Instance of an Aware List. The members of this structure are not - made available. Access to the parts of an aware list should be - handled through the appropriate functions. - - Any references to an aware list are rendered invalid when the - parent service is free'd -*/ -struct mwAwareList; - - -/** @struct mwAwareAttribute - - Key/Opaque pair indicating an identity's attribute. - */ -struct mwAwareAttribute; - - -/** Predefined keys appropriate for a mwAwareAttribute - */ -enum mwAwareAttributeKeys { - mwAttribute_AV_PREFS_SET = 0x01, /**< A/V prefs specified, gboolean */ - mwAttribute_MICROPHONE = 0x02, /**< has a microphone, gboolean */ - mwAttribute_SPEAKERS = 0x03, /**< has speakers, gboolean */ - mwAttribute_VIDEO_CAMERA = 0x04, /**< has a video camera, gboolean */ - mwAttribute_FILE_TRANSFER = 0x06, /**< supports file transfers, gboolean */ -}; - - -typedef void (*mwAwareAttributeHandler) - (struct mwServiceAware *srvc, - struct mwAwareAttribute *attrib); - - -struct mwAwareHandler { - mwAwareAttributeHandler on_attrib; - void (*clear)(struct mwServiceAware *srvc); -}; - - -/** Appropriate function type for the on-aware signal - - @param list mwAwareList emiting the signal - @param id awareness status information - @param data user-specified data -*/ -typedef void (*mwAwareSnapshotHandler) - (struct mwAwareList *list, - struct mwAwareSnapshot *id); - - -/** Appropriate function type for the on-option signal. The option's - value may need to be explicitly loaded in some instances, - resulting in this handler being triggered again. - - @param list mwAwareList emiting the signal - @param id awareness the attribute belongs to - @param attrib attribute -*/ -typedef void (*mwAwareIdAttributeHandler) - (struct mwAwareList *list, - struct mwAwareIdBlock *id, - struct mwAwareAttribute *attrib); - - -struct mwAwareListHandler { - /** handle aware updates */ - mwAwareSnapshotHandler on_aware; - - /** handle attribute updates */ - mwAwareIdAttributeHandler on_attrib; - - /** optional. Called from mwAwareList_free */ - void (*clear)(struct mwAwareList *list); -}; - - -struct mwServiceAware * -mwServiceAware_new(struct mwSession *session, - struct mwAwareHandler *handler); - - -/** Set an attribute value for this session */ -int mwServiceAware_setAttribute(struct mwServiceAware *srvc, - guint32 key, struct mwOpaque *opaque); - - -int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc, - guint32 key, gboolean val); - - -int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc, - guint32 key, guint32 val); - - -int mwServiceAware_setAttributeString(struct mwServiceAware *srvc, - guint32 key, const char *str); - - -/** Unset an attribute for this session */ -int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc, - guint32 key); - - -guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib); - - -gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib); - - -guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib); - - -/** Copy of attribute string, must be g_free'd. If the attribute's - content cannot be loaded as a string, returns NULL */ -char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib); - - -/** Direct access to an attribute's underlying opaque */ -const struct mwOpaque * -mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib); - - -/** Allocate and initialize an aware list */ -struct mwAwareList * -mwAwareList_new(struct mwServiceAware *srvc, - struct mwAwareListHandler *handler); - - -/** Clean and free an aware list */ -void mwAwareList_free(struct mwAwareList *list); - - -struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list); - - -/** Add a collection of user IDs to an aware list. - @param list mwAwareList to add user ID to - @param id_list mwAwareIdBlock list of user IDs to add - @return 0 for success, non-zero to indicate an error. -*/ -int mwAwareList_addAware(struct mwAwareList *list, GList *id_list); - - -/** Remove a collection of user IDs from an aware list. - @param list mwAwareList to remove user ID from - @param id_list mwAwareIdBlock list of user IDs to remove - @return 0 for success, non-zero to indicate an error. -*/ -int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list); - - -int mwAwareList_removeAllAware(struct mwAwareList *list); - - -/** watch an NULL terminated array of keys */ -int mwAwareList_watchAttributeArray(struct mwAwareList *list, - guint32 *keys); - - -/** watch a NULL terminated list of keys */ -int mwAwareList_watchAttributes(struct mwAwareList *list, - guint32 key, ...); - - -/** stop watching a NULL terminated array of keys */ -int mwAwareList_unwatchAttributeArray(struct mwAwareList *list, - guint32 *keys); - - -/** stop watching a NULL terminated list of keys */ -int mwAwareList_unwatchAttributes(struct mwAwareList *list, - guint32 key, ...); - - -/** remove all watched attributes */ -int mwAwareList_unwatchAllAttributes(struct mwAwareList *list); - - -guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list); - - -void mwAwareList_setClientData(struct mwAwareList *list, - gpointer data, GDestroyNotify cleanup); - - -void mwAwareList_removeClientData(struct mwAwareList *list); - - -gpointer mwAwareList_getClientData(struct mwAwareList *list); - - -/** trigger a got_aware event constructed from the passed user and - status information. Useful for adding false users and having the - getText function work for them */ -void mwServiceAware_setStatus(struct mwServiceAware *srvc, - struct mwAwareIdBlock *user, - struct mwUserStatus *stat); - - -/** look up the status description for a user */ -const char *mwServiceAware_getText(struct mwServiceAware *srvc, - struct mwAwareIdBlock *user); - - -/** look up the last known copy of an attribute for a user by the - attribute's key */ -const struct mwAwareAttribute * -mwServiceAware_getAttribute(struct mwServiceAware *srvc, - struct mwAwareIdBlock *user, - guint32 key); - - -#endif - - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_conf.h --- a/src/protocols/sametime/meanwhile/mw_srvc_conf.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SRVC_CONF_H -#define _MW_SRVC_CONF_H - - -#include -#include "mw_common.h" - - -/** Type identifier for the conference service */ -#define mwService_CONFERENCE 0x80000010 - - -enum mwConferenceState { - mwConference_NEW, /**< new outgoing conference */ - mwConference_PENDING, /**< outgoing conference pending creation */ - mwConference_INVITED, /**< invited to incoming conference */ - mwConference_OPEN, /**< conference open and active */ - mwConference_CLOSING, /**< conference is closing */ - mwConference_ERROR, /**< conference is closing due to error */ - mwConference_UNKNOWN, /**< unable to determine conference state */ -}; - - -/** @struct mwServiceConference - Instance of the multi-user conference service */ -struct mwServiceConference; - - -/** @struct mwConference - A multi-user chat */ -struct mwConference; - - -/** Handler structure used to provide callbacks for an instance of the - conferencing service */ -struct mwConferenceHandler { - - /** triggered when we receive a conference invitation. Call - mwConference_accept to accept the invitation and join the - conference, or mwConference_close to reject the invitation. - - @param conf the newly created conference - @param inviter the indentity of the user who sent the invitation - @param invite the invitation text - */ - void (*on_invited)(struct mwConference *conf, - struct mwLoginInfo *inviter, const char *invite); - - /** triggered when we enter the conference. Provides the initial - conference membership list as a GList of mwLoginInfo structures - - @param conf the conference just joined - @param members mwLoginInfo list of existing conference members - */ - void (*conf_opened)(struct mwConference *conf, GList *members); - - /** triggered when a conference is closed. This is typically when - we've left it */ - void (*conf_closed)(struct mwConference *, guint32 reason); - - /** triggered when someone joins the conference */ - void (*on_peer_joined)(struct mwConference *, struct mwLoginInfo *); - - /** triggered when someone leaves the conference */ - void (*on_peer_parted)(struct mwConference *, struct mwLoginInfo *); - - /** triggered when someone says something */ - void (*on_text)(struct mwConference *conf, - struct mwLoginInfo *who, const char *what); - - /** typing notification */ - void (*on_typing)(struct mwConference *conf, - struct mwLoginInfo *who, gboolean typing); - - /** optional. called from mwService_free */ - void (*clear)(struct mwServiceConference *srvc); -}; - - -/** Allocate a new conferencing service, attaching the given handler - @param sess owning session - @param handler handler providing call-back functions for the service - */ -struct mwServiceConference * -mwServiceConference_new(struct mwSession *sess, - struct mwConferenceHandler *handler); - - -/** @returns the conference handler for the service */ -struct mwConferenceHandler * -mwServiceConference_getHandler(struct mwServiceConference *srvc); - - -/** a mwConference list of the conferences in this service. The GList - will need to be destroyed with g_list_free after use */ -GList *mwServiceConference_getConferences(struct mwServiceConference *srvc); - - -/** Allocate a new conference, in state NEW with the given title. - @see mwConference_create */ -struct mwConference *mwConference_new(struct mwServiceConference *srvc, - const char *title); - - -/** @returns the owning service of a conference */ -struct mwServiceConference *mwConference_getService(struct mwConference *conf); - - -/** @returns unique conference name */ -const char *mwConference_getName(struct mwConference *conf); - - -/** @returns conference title */ -const char *mwConference_getTitle(struct mwConference *conf); - - -/** a mwIdBlock list of the members of the conference. The GList will - need to be free'd after use */ -GList *mwConference_getMembers(struct mwConference *conf); - - -/** Initiate a conference. Conference must be in state NEW. If no name - or title for the conference has been set, they will be - generated. Conference will be placed into state PENDING. */ -int mwConference_open(struct mwConference *conf); - - -/** Leave and close an existing conference, or reject an invitation. - Triggers mwServiceConfHandler::conf_closed and free's the - conference. - */ -int mwConference_destroy(struct mwConference *conf, - guint32 reason, const char *text); - - -#define mwConference_reject(c,r,t) \ - mwConference_destroy((c),(r),(t)) - - -/** accept a conference invitation. Conference must be in the state - INVITED. */ -int mwConference_accept(struct mwConference *conf); - - -/** invite another user to an ACTIVE conference - @param conf conference - @param who user to invite - @param text invitation message - */ -int mwConference_invite(struct mwConference *conf, - struct mwIdBlock *who, const char *text); - - -/** send a text message over an open conference */ -int mwConference_sendText(struct mwConference *conf, const char *text); - - -/** send typing notification over an open conference */ -int mwConference_sendTyping(struct mwConference *conf, gboolean typing); - - -/** associate arbitrary client data and an optional cleanup function - with a conference. If there is already client data with a clear - function, it will not be called. */ -void mwConference_setClientData(struct mwConference *conf, - gpointer data, GDestroyNotify clear); - - -/** reference associated client data */ -gpointer mwConference_getClientData(struct mwConference *conf); - - -/** remove associated client data if any, and call the cleanup - function on the data as necessary */ -void mwConference_removeClientData(struct mwConference *conf); - - -#endif - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_dir.h --- a/src/protocols/sametime/meanwhile/mw_srvc_dir.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +0,0 @@ -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SRVC_DIR_H -#define _MW_SERV_DIR_H - - -#include -#include - - -struct mwSession; - - -#define SERVICE_DIRECTORY 0x0000001a - - -/** @struct mwServiceDirectory - - the directory service. */ -struct mwServiceDirectory; - - -/** @struct mwAddressBook - - server-side collection of users and groups. Open a directory - based on an address book to search or list its contents */ -struct mwAddressBook; - - -/** @struct mwDirectory - - searchable directory, based off of an address book */ -struct mwDirectory; - - -enum mwDirectoryState { - mwDirectory_NEW, /**< directory is created, but not open */ - mwDirectory_PENDING, /**< directory has in the process of opening */ - mwDirectory_OPEN, /**< directory is open */ - mwDirectory_ERROR, /**< error opening or using directory */ - mwDirectory_UNKNOWN, /**< error determining directory state */ -}; - - -/** return value of directory searches that fail */ -#define DIR_SEARCH_ERROR 0x00000000 - - -#define MW_DIRECTORY_IS_STATE(dir, state) \ - (mwDirectory_getState(dir) == (state)) - -#define MW_DIRECTORY_IS_NEW(dir) \ - MW_DIRECTORY_IS_STATE((dir), mwDirectory_NEW) - -#define MW_DIRECTORY_IS_PENDING(dir) \ - MW_DIRECTORY_IS_STATE((dir), mwDirectory_PENDING) - -#define MW_DIRECTORY_IS_OPEN(dir) \ - MW_DIRECTORY_IS_STATE((dir), mwDirectory_OPEN) - - -enum mwDirectoryMemberType { - mwDirectoryMember_USER = 0x0000, - mwDirectoryMember_GROUP = 0x0001, -}; - - -struct mwDirectoryMember { - guint16 type; /**< @see mwDirectoryMemberType */ - char *id; /**< proper ID for member */ - char *long_name; /**< full name of member (USER type only) */ - char *short_name; /**< short name of member */ - guint16 foo; /**< unknown */ -}; - - -/** Appropriate function signature for handling directory search results */ -typedef void (*mwSearchHandler) - (struct mwDirectory *dir, - guint32 code, guint32 offset, GList *members); - - -/** handles asynchronous events for a directory service instance */ -struct mwDirectoryHandler { - - /** handle receipt of the address book list from the service. - Initially triggered by mwServiceDirectory_refreshAddressBooks - and at service startup */ - void (*on_book_list)(struct mwServiceDirectory *srvc, GList *books); - - /** triggered when a directory has been successfully opened */ - void (*dir_opened)(struct mwDirectory *dir); - - /** triggered when a directory has been closed */ - void (*dir_closed)(struct mwDirectory *dir, guint32 reason); - - /** optional. called from mwService_free */ - void (*clear)(struct mwServiceDirectory *srvc); -}; - - -/** Allocate a new directory service instance for use with session */ -struct mwServiceDirectory * -mwServiceDirectory_new(struct mwSession *session, - struct mwDirectoryHandler *handler); - - -/** the handler associated with the service at its creation */ -struct mwDirectoryHandler * -mwServiceDirectory_getHandler(struct mwServiceDirectory *srvc); - - -/** most recent list of address books available in service */ -GList *mwServiceDirectory_getAddressBooks(struct mwServiceDirectory *srvc); - - -/** submit a request to obtain an updated list of address books from - service */ -int mwServiceDirectory_refreshAddressBooks(struct mwServiceDirectory *srvc); - - -/** list of directories in the service */ -GList *mwServiceDirectory_getDirectories(struct mwServiceDirectory *srvc); - - -/** list of directories associated with address book. Note that the - returned GList will need to be free'd after use */ -GList *mwAddressBook_getDirectories(struct mwAddressBook *book); - - -/** the name of the address book */ -const char *mwAddressBook_getName(struct mwAddressBook *book); - - -/** allocate a new directory based off the given address book */ -struct mwDirectory *mwDirectory_new(struct mwAddressBook *book); - - -enum mwDirectoryState mwDirectory_getState(struct mwDirectory *dir); - - -/** set client data. If there is an existing clear function, it will - not be called */ -void mwDirectory_setClientData(struct mwDirectory *dir, - gpointer data, GDestroyNotify clear); - - -/** reference associated client data */ -gpointer mwDirectory_getClientData(struct mwDirectory *dir); - - -/** remove and cleanup user data */ -void mwDirectory_removeClientData(struct mwDirectory *dir); - - -/** reference owning service */ -struct mwServiceDirectory *mwDirectory_getService(struct mwDirectory *dir); - - -/** reference owning address book */ -struct mwAddressBook *mwDirectory_getAddressBook(struct mwDirectory *dir); - - -/** initialize a directory. */ -int mwDirectory_open(struct mwDirectory *dir, mwSearchHandler cb); - - -/** continue a search into its next results */ -int mwDirectory_next(struct mwDirectory *dir); - - -/** continue a search into its previous results */ -int mwDirectory_previous(struct mwDirectory *dir); - - -/** initiate a search on an open directory */ -int mwDirectory_search(struct mwDirectory *dir, const char *query); - - -/** close and free the directory, and unassociate it with its owning - address book and service */ -int mwDirectory_destroy(struct mwDirectory *dir); - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_ft.h --- a/src/protocols/sametime/meanwhile/mw_srvc_ft.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -#ifndef _MW_SRVC_FT_H -#define _MW_SRVC_FT_H - - -#include "mw_common.h" - - -/** @file mw_srvc_ft.h - - A file transfer is a simple way to get large chunks of binary data - from one client to another. -*/ - - -/** @struct mwServiceFileTransfer - File transfer service -*/ -struct mwServiceFileTransfer; - - -/** @struct mwFileTransfer - A single file trasfer session - */ -struct mwFileTransfer; - - -#define mwService_FILE_TRANSFER 0x00000038 - - -enum mwFileTransferState { - mwFileTransfer_NEW, /**< file transfer is not open */ - mwFileTransfer_PENDING, /**< file transfer is opening */ - mwFileTransfer_OPEN, /**< file transfer is open */ - mwFileTransfer_CANCEL_LOCAL, - mwFileTransfer_CANCEL_REMOTE, - mwFileTransfer_DONE, - mwFileTransfer_ERROR, /**< error in file transfer */ - mwFileTransfer_UNKNOWN, /**< unknown state */ -}; - - -#define mwFileTransfer_isState(ft, state) \ - (mwFileTransfer_getState(ft) == (state)) - -#define mwFileTransfer_isNew(ft) \ - mwFileTransfer_isState((ft), mwFileTransfer_NEW) - -#define mwFileTransfer_isPending(ft) \ - mwFileTransfer_isState((ft), mwFileTransfer_PENDING) - -#define mwFileTransfer_isOpen(ft) \ - mwFileTransfer_isState((ft), mwFileTransfer_OPEN) - -#define mwFileTransfer_isDone(ft) \ - mwFileTransfer_isState((ft), mwFileTransfer_DONE) - -#define mwFileTransfer_isCancelLocal(ft) \ - mwFileTransfer_isState((ft), mwFileTransfer_CANCEL_LOCAL) - -#define mwFileTransfer_isCancelRemote(ft) \ - mwFileTransfer_isState((ft), mwFileTransfer_CANCEL_REMOTE) - - -enum mwFileTranferCode { - mwFileTransfer_SUCCESS = 0x00000000, - mwFileTransfer_REJECTED = 0x08000606, -}; - - -struct mwFileTransferHandler { - - /** an incoming file transfer has been offered */ - void (*ft_offered)(struct mwFileTransfer *ft); - - /** a file transfer has been fully initiated */ - void (*ft_opened)(struct mwFileTransfer *ft); - - /** a file transfer has been closed. Check the status of the file - transfer to determine if the transfer was complete or if it had - been interrupted */ - void (*ft_closed)(struct mwFileTransfer *ft, guint32 code); - - /** receive a chunk of a file from an inbound file transfer. */ - void (*ft_recv)(struct mwFileTransfer *ft, struct mwOpaque *data); - - /** received an ack for a sent chunk on an outbound file transfer. - this indicates that a previous call to mwFileTransfer_send has - reached the target and that the target has responded. */ - void (*ft_ack)(struct mwFileTransfer *ft); - - /** optional. called from mwService_free */ - void (*clear)(struct mwServiceFileTransfer *srvc); -}; - - -struct mwServiceFileTransfer * -mwServiceFileTransfer_new(struct mwSession *session, - struct mwFileTransferHandler *handler); - - -struct mwFileTransferHandler * -mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc); - - -const GList * -mwServiceFileTransfer_getTransfers(struct mwServiceFileTransfer *srvc); - - -struct mwFileTransfer * -mwFileTransfer_new(struct mwServiceFileTransfer *srvc, - const struct mwIdBlock *who, const char *msg, - const char *filename, guint32 filesize); - - -/** deallocate a file transfer. will call mwFileTransfer_close if - necessary */ -void -mwFileTransfer_free(struct mwFileTransfer *ft); - - -/** the status of this file transfer */ -enum mwFileTransferState -mwFileTransfer_getState(struct mwFileTransfer *ft); - - -struct mwServiceFileTransfer * -mwFileTransfer_getService(struct mwFileTransfer *ft); - - -/** the user on the other end of the file transfer */ -const struct mwIdBlock * -mwFileTransfer_getUser(struct mwFileTransfer *ft); - - -/** the message sent along with an offered file transfer */ -const char * -mwFileTransfer_getMessage(struct mwFileTransfer *ft); - - -/** the publicized file name. Not necessarily related to any actual - file on either system */ -const char * -mwFileTransfer_getFileName(struct mwFileTransfer *ft); - - -/** total bytes intended to be sent/received */ -guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft); - - -/** bytes remaining to be received/send */ -guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft); - - -/** count of bytes sent/received over this file transfer so far */ -#define mwFileTransfer_getSent(ft) \ - (mwFileTransfer_getFileSize(ft) - mwFileTransfer_getRemaining(ft)) - - -/** initiate an outgoing file transfer */ -int mwFileTransfer_offer(struct mwFileTransfer *ft); - - -/** accept an incoming file transfer */ -int mwFileTransfer_accept(struct mwFileTransfer *ft); - - -/** reject an incoming file transfer */ -#define mwFileTransfer_reject(ft) \ - mwFileTransfer_close((ft), mwFileTransfer_REJECTED) - - -/** cancel an open file transfer */ -#define mwFileTransfer_cancel(ft) \ - mwFileTransfer_close((ft), mwFileTransfer_SUCCESS); - - -/** Close a file transfer. This will trigger the ft_close function of the - session's handler. - - @see mwFileTransfer_reject - @see mwFileTransfer_cancel -*/ -int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code); - - -/** send a chunk of data over an outbound file transfer. The client at - the other end of the transfer should respond with an acknowledgement - message, which can be caught in the service's handler. - - @see mwFileTransferHandler::ft_ack -*/ -int mwFileTransfer_send(struct mwFileTransfer *ft, - struct mwOpaque *data); - - -/** acknowledge the receipt of a chunk of data from an inbound file - transfer. This should be done after every received chunk, or the - transfer will stall. However, not all clients will wait for an ack - after sending a chunk before sending the next chunk, so it is - possible to have the handler's ft_recv function triggered again - even if no ack was sent. - - @see mwFileTransferHandler::ft_recv -*/ -int mwFileTransfer_ack(struct mwFileTransfer *ft); - - -void mwFileTransfer_setClientData(struct mwFileTransfer *ft, - gpointer data, GDestroyNotify clean); - - -gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft); - - -void mwFileTransfer_removeClientData(struct mwFileTransfer *ft); - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_im.h --- a/src/protocols/sametime/meanwhile/mw_srvc_im.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SRVC_IM_H -#define _MW_SRVC_IM_H - - -#include -#include "mw_common.h" - - -/** @file mw_srvc_im.h - - The IM service provides one-on-one communication between - users. Messages sent over conversations may relay different types - of information, in a variety of formats. The basic feature-set - provides plain-text chat with typing notification. More complex - features may be negotiated transparently by setting the IM Client - Type for a conversation, or for the service as a whole. - */ - - -/** Type identifier for the IM service */ -#define mwService_IM 0x00001000 - - -/** @struct mwServiceIm - - An instance of the IM service. This service provides simple - instant messaging functionality */ -struct mwServiceIm; - - -/** @struct mwConversation - - A conversation between the local service and a single other user */ -struct mwConversation; - - -enum mwImClientType { - mwImClient_PLAIN = 0x00000001, /**< text, typing */ - mwImClient_NOTESBUDDY = 0x00033453, /**< adds html, subject, mime */ - mwImClient_PRECONF = 0x00000019, /**< pre-conference, legacy */ - mwImClient_UNKNOWN = 0xffffffff, /**< trouble determining type */ -}; - - -/** - Types of supported messages. When a conversation is created, the - least common denominator of features between either side of the - conversation (based on what features are available in the IM - service itself) becomes the set of supported features for that - conversation. At any point, the feature set for the service may - change, without affecting any existing conversations. - - @see mwServiceIm_supports - @see mwServiceIm_setSupported - @see mwConversation_supports - @see mwConversation_send - @see mwServiceImHandler::conversation_recv - */ -enum mwImSendType { - mwImSend_PLAIN, /**< char *, plain-text message */ - mwImSend_TYPING, /**< gboolean, typing status */ - mwImSend_HTML, /**< char *, HTML formatted message (NOTESBUDDY) */ - mwImSend_SUBJECT, /**< char *, conversation subject (NOTESBUDDY) */ - mwImSend_MIME, /**< char *, MIME-encoded message (NOTESBUDDY) */ - mwImSend_TIMESTAMP, /**< char *, YYYY:MM:DD:HH:mm:SS format (NOTESBUDDY) */ -}; - - - -/** @see mwConversation_getState */ -enum mwConversationState { - mwConversation_CLOSED, /**< conversation is not open */ - mwConversation_PENDING, /**< conversation is opening */ - mwConversation_OPEN, /**< conversation is open */ - mwConversation_UNKNOWN, /**< unknown state */ -}; - - -#define mwConversation_isState(conv, state) \ - (mwConversation_getState(conv) == (state)) - -#define mwConversation_isClosed(conv) \ - mwConversation_isState((conv), mwConversation_CLOSED) - -#define mwConversation_isPending(conv) \ - mwConversation_isState((conv), mwConversation_PENDING) - -#define mwConversation_isOpen(conv) \ - mwConversation_isState((conv), mwConversation_OPEN) - - - -/** IM Service Handler. Provides functions for events triggered from an - IM service instance. */ -struct mwImHandler { - - /** A conversation has been successfully opened */ - void (*conversation_opened)(struct mwConversation *conv); - - /** A conversation has been closed */ - void (*conversation_closed)(struct mwConversation *conv, guint32 err); - - /** A message has been received on a conversation */ - void (*conversation_recv)(struct mwConversation *conv, - enum mwImSendType type, gconstpointer msg); - - /** Handle a Place invitation. Set this to NULL and we should end up - receiving a conference invitation instead. */ - void (*place_invite)(struct mwConversation *conv, - const char *message, - const char *title, const char *name); - - /** optional. called from mwService_free */ - void (*clear)(struct mwServiceIm *srvc); -}; - - -struct mwServiceIm *mwServiceIm_new(struct mwSession *session, - struct mwImHandler *handler); - - -struct mwImHandler *mwServiceIm_getHandler(struct mwServiceIm *srvc); - - -/** reference an existing conversation to target, or create a new - conversation to target if one does not already exist */ -struct mwConversation *mwServiceIm_getConversation(struct mwServiceIm *srvc, - struct mwIdBlock *target); - - -/** reference an existing conversation to target */ -struct mwConversation *mwServiceIm_findConversation(struct mwServiceIm *srvc, - struct mwIdBlock *target); - - -/** determine if the conversations created from this service will - support a given send type */ -gboolean mwServiceIm_supports(struct mwServiceIm *srvc, - enum mwImSendType type); - - -/** Set the default client type for the service. Newly created - conversations will attempt to meet this level of functionality - first. - - @param srvc the IM service - @param type the send type to enable/disable -*/ -void mwServiceIm_setClientType(struct mwServiceIm *srvc, - enum mwImClientType type); - - -enum mwImClientType mwServiceIm_getClientType(struct mwServiceIm *srvc); - - -/** attempt to open a conversation. If the conversation was not - already open and it is accepted, - mwServiceImHandler::conversation_opened will be triggered. Upon - failure, mwServiceImHandler::conversation_closed will be - triggered */ -void mwConversation_open(struct mwConversation *conv); - - -/** close a conversation. If the conversation was not already closed, - mwServiceImHandler::conversation_closed will be triggered */ -void mwConversation_close(struct mwConversation *conv, guint32 err); - - -/** determine whether a conversation supports the given message type */ -gboolean mwConversation_supports(struct mwConversation *conv, - enum mwImSendType type); - - -enum mwImClientType mwConversation_getClientType(struct mwConversation *conv); - - -/** get the state of a conversation - - @see mwConversation_isOpen - @see mwConversation_isClosed - @see mwConversation_isPending -*/ -enum mwConversationState mwConversation_getState(struct mwConversation *conv); - - -/** send a message over an open conversation */ -int mwConversation_send(struct mwConversation *conv, - enum mwImSendType type, gconstpointer send); - - -/** @returns owning service for a conversation */ -struct mwServiceIm *mwConversation_getService(struct mwConversation *conv); - - -/** login information for conversation partner. returns NULL if conversation - is not OPEN */ -struct mwLoginInfo *mwConversation_getTargetInfo(struct mwConversation *conv); - - -/** ID for conversation partner */ -struct mwIdBlock *mwConversation_getTarget(struct mwConversation *conv); - - -/** set whether outgoing messages should be encrypted using the - negotiated cipher, if any */ -void mwConversation_setEncrypted(struct mwConversation *conv, - gboolean useCipher); - - -/** determine whether outgoing messages are being encrypted */ -gboolean mwConversation_isEncrypted(struct mwConversation *conv); - - -/** Associates client data with a conversation. If there is existing data, - it will not have its cleanup function called. - - @see mwConversation_getClientData - @see mwConversation_removeClientData -*/ -void mwConversation_setClientData(struct mwConversation *conv, - gpointer data, GDestroyNotify clean); - - -/** Reference associated client data - - @see mwConversation_setClientData - @see mwConversation_removeClientData - */ -gpointer mwConversation_getClientData(struct mwConversation *conv); - - -/** Remove any associated client data, calling the optional cleanup - function if one was provided - - @see mwConversation_setClientData - @see mwConversation_getClientData -*/ -void mwConversation_removeClientData(struct mwConversation *conv); - - -/** close and destroy the conversation and its backing channel, and - call the optional client data cleanup function */ -void mwConversation_free(struct mwConversation *conv); - - -#endif - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_place.h --- a/src/protocols/sametime/meanwhile/mw_srvc_place.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SRVC_PLACE_H -#define _MW_SRVC_PLACE_H - - -#include -#include "mw_common.h" - - -/** Type identifier for the place service */ -#define mwService_PLACE 0x80000022 - - -/** @struct mwServicePlace */ -struct mwServicePlace; - - -/** @struct mwPlace */ -struct mwPlace; - - -struct mwPlaceHandler { - void (*opened)(struct mwPlace *place); - void (*closed)(struct mwPlace *place, guint32 code); - - void (*peerJoined)(struct mwPlace *place, - const struct mwIdBlock *peer); - - void (*peerParted)(struct mwPlace *place, - const struct mwIdBlock *peer); - - void (*peerSetAttribute)(struct mwPlace *place, - const struct mwIdBlock *peer, - guint32 attr, struct mwOpaque *o); - - void (*peerUnsetAttribute)(struct mwPlace *place, - const struct mwIdBlock *peer, - guint32 attr); - - void (*message)(struct mwPlace *place, - const struct mwIdBlock *who, - const char *msg); - - void (*clear)(struct mwServicePlace *srvc); -}; - - -enum mwPlacePeerAttribute { - mwPlacePeer_TYPING = 0x00000008, -}; - - -struct mwServicePlace * -mwServicePlace_new(struct mwSession *session, - struct mwPlaceHandler *handler); - - -struct mwPlaceHandler * -mwServicePlace_getHandler(struct mwServicePlace *srvc); - - -const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc); - - -struct mwPlace *mwPlace_new(struct mwServicePlace *srvc, - const char *name, const char *title); - - -struct mwServicePlace *mwPlace_getService(struct mwPlace *place); - - -const char *mwPlace_getName(struct mwPlace *place); - - -const char *mwPlace_getTitle(struct mwPlace *place); - - -int mwPlace_open(struct mwPlace *place); - - -int mwPlace_destroy(struct mwPlace *place, guint32 code); - - -/** returns a GList* of struct mwIdBlock*. The GList will need to be - freed after use, the mwIdBlock structures should not be modified - or freed */ -GList *mwPlace_getMembers(struct mwPlace *place); - - -int mwPlace_sendText(struct mwPlace *place, const char *msg); - - -/** send a legacy invitation for this place to a user. The user will - receive an apparent invitation from a Conference (rather than a - Place) */ -int mwPlace_legacyInvite(struct mwPlace *place, - struct mwIdBlock *idb, - const char *message); - - -int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib, - struct mwOpaque *data); - - -int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib); - - -void mwPlace_setClientData(struct mwPlace *place, - gpointer data, GDestroyNotify clean); - - -gpointer mwPlace_getClientData(struct mwPlace *place); - - -void mwPlace_removeClientData(struct mwPlace *place); - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_resolve.h --- a/src/protocols/sametime/meanwhile/mw_srvc_resolve.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SRVC_RESOLVE_H -#define _MW_SRVC_RESOLVE_H - - -#include -#include - - -/** Type identifier for the conference service */ -#define mwService_RESOLVE 0x00000015 - - -/** Return value of mwServiceResolve_search indicating an error */ -#define SEARCH_ERROR 0x00 - - -/** @struct mwServiceResolve - User lookup service */ -struct mwServiceResolve; - - -enum mwResolveFlag { - /** return unique results or none at all */ - mwResolveFlag_UNIQUE = 0x00000001, - - /** return only the first result */ - mwResolveFlag_FIRST = 0x00000002, - - /** search all directories, not just the first with a match */ - mwResolveFlag_ALL_DIRS = 0x00000004, - - /** search for users */ - mwResolveFlag_USERS = 0x00000008, - - /** search for groups */ - mwResolveFlag_GROUPS = 0x00000010, -}; - - -/** @see mwResolveResult */ -enum mwResolveCode { - /** successful search */ - mwResolveCode_SUCCESS = 0x00000000, - - /** only some of the nested searches were successful */ - mwResolveCode_PARTIAL = 0x00010000, - - /** more than one result (occurs when mwResolveFlag_UNIQUE is used - and more than one result would have been otherwise returned) */ - mwResolveCode_MULTIPLE = 0x80020000, - - /** the name is not resolvable due to its format */ - mwResolveCode_BAD_FORMAT = 0x80030000, -}; - - -enum mwResolveMatchType { - mwResolveMatch_USER = 0x00000001, - mwResolveMatch_GROUP = 0x00000002, -}; - - -struct mwResolveMatch { - char *id; /**< user id */ - char *name; /**< user name */ - char *desc; /**< description */ - guint32 type; /**< @see mwResolveMatchType */ -}; - - -struct mwResolveResult { - guint32 code; /**< @see mwResolveCode */ - char *name; /**< name of the result */ - GList *matches; /**< list of mwResolveMatch */ -}; - - -/** Handle the results of a resolve request. If there was a cleanup - function specified to mwServiceResolve_search, it will be called - upon the user data after this callback returns. - - @param srvc the resolve service - @param id the resolve request ID - @param code return code - @param results list of mwResolveResult - @param data optional user data attached to the request -*/ -typedef void (*mwResolveHandler) - (struct mwServiceResolve *srvc, - guint32 id, guint32 code, GList *results, - gpointer data); - - -/** Allocate a new resolve service */ -struct mwServiceResolve *mwServiceResolve_new(struct mwSession *); - - -/** Inisitate a resolve request. - - @param srvc the resolve service - @param queries list query strings - @param flags search flags - @param handler result handling function - @param data optional user data attached to the request - @param cleanup optional function to clean up user data - @return generated ID for the search request, or SEARCH_ERROR -*/ -guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc, - GList *queries, enum mwResolveFlag flags, - mwResolveHandler handler, - gpointer data, GDestroyNotify cleanup); - - -/** Cancel a resolve request by its generated ID. The handler function - will not be called, and the optional cleanup function will be - called upon the optional user data for the request */ -void mwServiceResolve_cancelResolve(struct mwServiceResolve *, guint32); - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_srvc_store.h --- a/src/protocols/sametime/meanwhile/mw_srvc_store.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_SRVC_STORE_H -#define _MW_SRVC_STORE_H - - -#include -#include "mw_common.h" - - -/** Type identifier for the storage service */ -#define mwService_STORAGE 0x00000018 - - -/** @struct mwServiceStorage - @see mwServiceStorage_new - - Instance of the storage service */ -struct mwServiceStorage; - - -/** @struct mwStorage - - Unit Represents information intended for loading from or saving to - the storage service */ -struct mwStorageUnit; - - -/** The upper limit of reserved Lotus keys */ -#define LOTUS_RESERVED_LIMIT 0x186a0 - - -/** Check if a key is in the range of Lotus reserved keys */ -#define KEY_IS_LOTUS_RESERVED(key) \ - (((guint32) key) <= (LOTUS_RESERVED_LIMIT)) - - -/** Some common keys storage keys. Anything in the range 0x00 to - 0x186a0 (100000) is reserved for use by the Lotus - clients. */ -enum mwStorageKey { - - /** The buddy list, in the Sametime .dat file format. String */ - mwStore_AWARE_LIST = 0x00000000, - - /** Default text for chat invitations. String */ - mwStore_INVITE_CHAT = 0x00000006, - - /** Default text for meeting invitations. String */ - mwStore_INVITE_MEETING = 0x0000000e, - - /** Last five Away messages, separated by semicolon. String */ - mwStore_AWAY_MESSAGES = 0x00000050, - - /** Last five Busy (DND) messages, separated by semicolon. String */ - mwStore_BUSY_MESSAGES = 0x0000005a, - - /** Last five Active messages, separated by semicolon. String */ - mwStore_ACTIVE_MESSAGES = 0x00000064, -}; - - -/** Appropriate function type for load and store callbacks. - @param srvc the storage service - @param result the result value of the load or store call - @param item the storage unit loaded or saved - @param data optional user data -*/ -typedef void (*mwStorageCallback) - (struct mwServiceStorage *srvc, - guint32 result, struct mwStorageUnit *item, - gpointer data); - - -/** Allocates and initializes a storage service instance for use on - the passed session. */ -struct mwServiceStorage *mwServiceStorage_new(struct mwSession *); - - -/** create an empty storage unit */ -struct mwStorageUnit *mwStorageUnit_new(guint32 key); - - -/** creates a storage unit with the passed key, and a copy of data. */ -struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key, - struct mwOpaque *data); - - -/** creates a storage unit with the passed key, and an encapsulated - boolean value */ -struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key, - gboolean val); - - -struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key, - guint32 val); - - -/** creates a storage unit with the passed key, and an encapsulated - string value. */ -struct mwStorageUnit *mwStorageUnit_newString(guint32 key, - const char *str); - - -/** get the key for the given storage unit */ -guint32 mwStorageUnit_getKey(struct mwStorageUnit *); - - -/** attempts to obtain a boolean value from a storage unit. If the - unit is empty, or does not contain the type in a recongnizable - format, val is returned instead */ -gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *, gboolean val); - - -/** attempts to obtain a guint32 value from a storage unit. If the - unit is empty, or does not contain the type in a recognizable - format, val is returned instead */ -guint32 mwStorageUnit_asInteger(struct mwStorageUnit *, guint32 val); - - -/** attempts to obtain a string value from a storage unit. If the unit - is empty, or does not contain the type in a recognizable format, - NULL is returned instead. Note that the string returned is a copy, - and will need to be deallocated at some point. */ -char *mwStorageUnit_asString(struct mwStorageUnit *); - - -/** direct access to the opaque data backing the storage unit */ -struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *); - - -/** clears and frees a storage unit */ -void mwStorageUnit_free(struct mwStorageUnit *); - - -/** Initiates a load call to the storage service. If the service is - not currently available, the call will be cached and processed - when the service is started. - - @param srvc the storage service - @param item storage unit to load - @param cb callback function when the load call completes - @param data user data for callback - @param data_free optional cleanup function for user data -*/ -void mwServiceStorage_load(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify data_free); - - -/** Initiates a store call to the storage service. If the service is - not currently available, the call will be cached and processed - when the service is started. - - @param srvc the storage service - @param item storage unit to save - @param cb callback function when the load call completes - @param data optional user data for callback - @param data_free optional cleanup function for user data - */ -void mwServiceStorage_save(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify data_free); - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_st_list.h --- a/src/protocols/sametime/meanwhile/mw_st_list.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_ST_LIST_H -#define _MW_ST_LIST_H - - -#include -#include -#include "mw_common.h" - - -#define ST_LIST_MAJOR 3 -#define ST_LIST_MINOR 1 -#define ST_LIST_MICRO 3 - - -enum mwSametimeGroupType { - mwSametimeGroup_NORMAL = 1, /**< a normal group of users */ - mwSametimeGroup_DYNAMIC = 2, /**< a server-side group */ - mwSametimeGroup_UNKNOWN = 0, /**< error determining group type */ -}; - - -enum mwSametimeUserType { - mwSametimeUser_NORMAL = 1, /**< user on same community */ - mwSametimeUser_EXTERNAL = 2, /**< external user */ - mwSametimeUser_UNKNOWN = 0, /**< error determining user type */ -}; - - -/** @struct mwSametimeList - - Represents a group-based buddy list. */ -struct mwSametimeList; - - -/** @struct mwSametimeGroup - - Represents a group in a buddy list */ -struct mwSametimeGroup; - - -/** @struct mwSametimeUser - - Represents a user in a group in a buddy list */ -struct mwSametimeUser; - - -/** Create a new list */ -struct mwSametimeList *mwSametimeList_new(void); - - -/** Free the list, all of its groups, and all of the groups' members */ -void mwSametimeList_free(struct mwSametimeList *l); - - -/** Load a sametime list from a buffer. The list must be encapsulated - as a string (eg, the first two bytes in the buffer should be the - length of the string) */ -void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l); - - -/** Write a sametime list onto a buffer. The list will be encapsulated - in a string (the first two bytes written will be the length of the - rest of the written list data) */ -void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l); - - -/** convert a plain string into a sametime list */ -struct mwSametimeList *mwSametimeList_load(const char *str); - - -/** convert a sametime list into a string */ -char *mwSametimeList_store(struct mwSametimeList *l); - - -void mwSametimeList_setMajor(struct mwSametimeList *l, guint v); - - -guint mwSametimeList_getMajor(struct mwSametimeList *l); - - -void mwSametimeList_setMinor(struct mwSametimeList *l, guint v); - - -guint mwSametimeList_getMinor(struct mwSametimeList *l); - - -void mwSametimeList_setMicro(struct mwSametimeList *l, guint v); - - -guint mwSametimeList_getMicro(struct mwSametimeList *l); - - -/** Get a GList snapshot of the groups in a list */ -GList *mwSametimeList_getGroups(struct mwSametimeList *l); - - -struct mwSametimeGroup * -mwSametimeList_findGroup(struct mwSametimeList *l, - const char *name); - - -/** Create a new group in a list */ -struct mwSametimeGroup * -mwSametimeGroup_new(struct mwSametimeList *l, - enum mwSametimeGroupType type, - const char *name); - - -/** Remove a group from its list, and free it. Also frees all users - contained in the group */ -void mwSametimeGroup_free(struct mwSametimeGroup *g); - - -enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g); - - -const char *mwSametimeGroup_getName(struct mwSametimeGroup *g); - - -void mwSametimeGroup_setAlias(struct mwSametimeGroup *g, - const char *alias); - - -const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g); - - -void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open); - - -gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g); - - -struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g); - - -/** Get a GList snapshot of the users in a list */ -GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g); - - -struct mwSametimeUser * -mwSametimeGroup_findUser(struct mwSametimeGroup *g, - struct mwIdBlock *user); - - -/** Create a user in a group */ -struct mwSametimeUser * -mwSametimeUser_new(struct mwSametimeGroup *g, - enum mwSametimeUserType type, - struct mwIdBlock *user); - - -/** Remove user from its group, and free it */ -void mwSametimeUser_free(struct mwSametimeUser *u); - - -struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u); - - -enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u); - - -const char *mwSametimeUser_getUser(struct mwSametimeUser *u); - - -const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u); - - -void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name); - - -const char *mwSametimeUser_getShortName(struct mwSametimeUser *u); - - -void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias); - - -const char *mwSametimeUser_getAlias(struct mwSametimeUser *u); - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_util.c --- a/src/protocols/sametime/meanwhile/mw_util.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "mw_util.h" - - -static void collect_keys(gpointer key, gpointer val, gpointer data) { - GList **list = data; - *list = g_list_append(*list, key); -} - - -GList *map_collect_keys(GHashTable *ht) { - GList *ret = NULL; - g_hash_table_foreach(ht, collect_keys, &ret); - return ret; -} - - -static void collect_values(gpointer key, gpointer val, gpointer data) { - GList **list = data; - *list = g_list_append(*list, val); -} - - -GList *map_collect_values(GHashTable *ht) { - GList *ret = NULL; - g_hash_table_foreach(ht, collect_values, &ret); - return ret; -} - - -struct mw_datum *mw_datum_new(gpointer data, GDestroyNotify clear) { - struct mw_datum *d = g_new(struct mw_datum, 1); - mw_datum_set(d, data, clear); - return d; -} - - -void mw_datum_set(struct mw_datum *d, gpointer data, GDestroyNotify clear) { - d->data = data; - d->clear = clear; -} - - -gpointer mw_datum_get(struct mw_datum *d) { - return d->data; -} - - -void mw_datum_clear(struct mw_datum *d) { - if(d->clear) { - d->clear(d->data); - d->clear = NULL; - } - d->data = NULL; -} - - -void mw_datum_free(struct mw_datum *d) { - mw_datum_clear(d); - g_free(d); -} diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/mw_util.h --- a/src/protocols/sametime/meanwhile/mw_util.h Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_UTIL_H -#define _MW_UTIL_H - - -#include -#include -#include - - -#define map_guint_new() \ - g_hash_table_new(g_direct_hash, g_direct_equal) - - -#define map_guint_new_full(valfree) \ - g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (valfree)) - - -#define map_guint_insert(ht, key, val) \ - g_hash_table_insert((ht), GUINT_TO_POINTER((guint)(key)), (val)) - - -#define map_guint_replace(ht, key, val) \ - g_hash_table_replace((ht), GUINT_TO_POINTER((guint)(key)), (val)) - - -#define map_guint_lookup(ht, key) \ - g_hash_table_lookup((ht), GUINT_TO_POINTER((guint)(key))) - - -#define map_guint_remove(ht, key) \ - g_hash_table_remove((ht), GUINT_TO_POINTER((guint)(key))) - - -#define map_guint_steal(ht, key) \ - g_hash_table_steal((ht), GUINT_TO_POINTER((guint)(key))) - - -GList *map_collect_keys(GHashTable *ht); - - -GList *map_collect_values(GHashTable *ht); - - -struct mw_datum { - gpointer data; - GDestroyNotify clear; -}; - - -struct mw_datum *mw_datum_new(gpointer data, GDestroyNotify clear); - - -void mw_datum_set(struct mw_datum *d, gpointer data, GDestroyNotify clear); - - -gpointer mw_datum_get(struct mw_datum *d); - - -void mw_datum_clear(struct mw_datum *d); - - -void mw_datum_free(struct mw_datum *d); - - -#endif diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/service.c --- a/src/protocols/sametime/meanwhile/service.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "mw_channel.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" - - -/* I tried to be explicit with the g_return_* calls, to make the debug - logging a bit more sensible. Hence all the explicit "foo != NULL" - checks. */ - - -void mwService_recvCreate(struct mwService *s, struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - /* ensure none are null, ensure that the service and channel belong - to the same session, and ensure that the message belongs on the - channel */ - g_return_if_fail(s != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(s->session == mwChannel_getSession(chan)); - g_return_if_fail(mwChannel_getId(chan) == msg->channel); - - if(s->recv_create) { - s->recv_create(s, chan, msg); - } else { - mwChannel_destroy(chan, ERR_FAILURE, NULL); - } -} - - -void mwService_recvAccept(struct mwService *s, struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - /* ensure none are null, ensure that the service and channel belong - to the same session, and ensure that the message belongs on the - channel */ - g_return_if_fail(s != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(s->session == mwChannel_getSession(chan)); - g_return_if_fail(mwChannel_getId(chan) == msg->head.channel); - - if(s->recv_accept) - s->recv_accept(s, chan, msg); -} - - -void mwService_recvDestroy(struct mwService *s, struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - /* ensure none are null, ensure that the service and channel belong - to the same session, and ensure that the message belongs on the - channel */ - g_return_if_fail(s != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(s->session == mwChannel_getSession(chan)); - g_return_if_fail(mwChannel_getId(chan) == msg->head.channel); - - if(s->recv_destroy) - s->recv_destroy(s, chan, msg); -} - - -void mwService_recv(struct mwService *s, struct mwChannel *chan, - guint16 msg_type, struct mwOpaque *data) { - - /* ensure that none are null. zero-length messages are acceptable */ - g_return_if_fail(s != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(data != NULL); - g_return_if_fail(s->session == mwChannel_getSession(chan)); - - /* - g_message("mwService_recv: session = %p, service = %p, b = %p, n = %u", - mwService_getSession(s), s, data->data, data->len); - */ - - if(s->recv) - s->recv(s, chan, msg_type, data); -} - - -guint32 mwService_getType(struct mwService *s) { - g_return_val_if_fail(s != NULL, 0x00); - return s->type; -} - - -const char *mwService_getName(struct mwService *s) { - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->get_name != NULL, NULL); - - return s->get_name(s); -} - - -const char *mwService_getDesc(struct mwService *s) { - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->get_desc != NULL, NULL); - - return s->get_desc(s); -} - - -struct mwSession *mwService_getSession(struct mwService *s) { - g_return_val_if_fail(s != NULL, NULL); - return s->session; -} - - -void mwService_init(struct mwService *srvc, struct mwSession *sess, - guint32 type) { - - /* ensure nothing is null, and there's no such thing as a zero - service type */ - g_return_if_fail(srvc != NULL); - g_return_if_fail(sess != NULL); - g_return_if_fail(type != 0x00); - - srvc->session = sess; - srvc->type = type; - srvc->state = mwServiceState_STOPPED; -} - - -enum mwServiceState mwService_getState(struct mwService *srvc) { - g_return_val_if_fail(srvc != NULL, mwServiceState_STOPPED); - return srvc->state; -} - - -void mwService_start(struct mwService *srvc) { - g_return_if_fail(srvc != NULL); - - if(! MW_SERVICE_IS_STOPPED(srvc)) - return; - - srvc->state = mwServiceState_STARTING; - g_message("starting service %s", NSTR(mwService_getName(srvc))); - - if(srvc->start) { - srvc->start(srvc); - } else { - mwService_started(srvc); - } -} - - -void mwService_started(struct mwService *srvc) { - g_return_if_fail(srvc != NULL); - - srvc->state = mwServiceState_STARTED; - g_message("started service %s", NSTR(mwService_getName(srvc))); -} - - -void mwService_error(struct mwService *srvc) { - g_return_if_fail(srvc != NULL); - - if(MW_SERVICE_IS_DEAD(srvc)) - return; - - srvc->state = mwServiceState_ERROR; - g_message("error in service %s", NSTR(mwService_getName(srvc))); - - if(srvc->stop) { - srvc->stop(srvc); - } else { - mwService_stopped(srvc); - } -} - - -void mwService_stop(struct mwService *srvc) { - g_return_if_fail(srvc != NULL); - - if(MW_SERVICE_IS_DEAD(srvc)) - return; - - srvc->state = mwServiceState_STOPPING; - g_message("stopping service %s", NSTR(mwService_getName(srvc))); - - if(srvc->stop) { - srvc->stop(srvc); - } else { - mwService_stopped(srvc); - } -} - - -void mwService_stopped(struct mwService *srvc) { - g_return_if_fail(srvc != NULL); - - if(srvc->state != mwServiceState_STOPPED) { - srvc->state = mwServiceState_STOPPED; - g_message("stopped service %s", NSTR(mwService_getName(srvc))); - } -} - - -void mwService_free(struct mwService *srvc) { - g_return_if_fail(srvc != NULL); - - mwService_stop(srvc); - - if(srvc->clear) - srvc->clear(srvc); - - if(srvc->client_cleanup) - srvc->client_cleanup(srvc->client_data); - - g_free(srvc); -} - - -/** @todo switch the following to using mw_datum */ - -void mwService_setClientData(struct mwService *srvc, - gpointer data, GDestroyNotify cleanup) { - - g_return_if_fail(srvc != NULL); - - srvc->client_data = data; - srvc->client_cleanup = cleanup; -} - - -gpointer mwService_getClientData(struct mwService *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->client_data; -} - - -void mwService_removeClientData(struct mwService *srvc) { - g_return_if_fail(srvc != NULL); - - if(srvc->client_cleanup) { - srvc->client_cleanup(srvc->client_data); - srvc->client_cleanup = NULL; - } - - srvc->client_data = NULL; -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/session.c --- a/src/protocols/sametime/meanwhile/session.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1206 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#include "mw_channel.h" -#include "mw_cipher.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_util.h" - - -/** the hash table key for a service, for mwSession::services */ -#define SERVICE_KEY(srvc) mwService_getType(srvc) - -/** the hash table key for a cipher, for mwSession::ciphers */ -#define CIPHER_KEY(ciph) mwCipher_getType(ciph) - - -#define GPOINTER(val) (GUINT_TO_POINTER((guint) (val))) -#define GUINT(val) (GPOINTER_TO_UINT((val))) - - -struct mwSession { - - /** provides I/O and callback functions */ - struct mwSessionHandler *handler; - - enum mwSessionState state; /**< session state */ - gpointer state_info; /**< additional state info */ - - /* input buffering for an incoming message */ - guchar *buf; /**< buffer for incoming message data */ - gsize buf_len; /**< length of buf */ - gsize buf_used; /**< offset to last-used byte of buf */ - - struct mwLoginInfo login; /**< login information */ - struct mwUserStatus status; /**< user status */ - struct mwPrivacyInfo privacy; /**< privacy list */ - - /** the collection of channels */ - struct mwChannelSet *channels; - - /** the collection of services, keyed to guint32 service id */ - GHashTable *services; - - /** the collection of ciphers, keyed to guint16 cipher type */ - GHashTable *ciphers; - - /** arbitrary key:value pairs */ - GHashTable *attributes; - - /** optional user data */ - struct mw_datum client_data; -}; - - -static void property_set(struct mwSession *s, const char *key, - gpointer val, GDestroyNotify clean) { - - g_hash_table_insert(s->attributes, g_strdup(key), - mw_datum_new(val, clean)); -} - - -static gpointer property_get(struct mwSession *s, const char *key) { - struct mw_datum *p = g_hash_table_lookup(s->attributes, key); - return p? p->data: NULL; -} - - -static void property_del(struct mwSession *s, const char *key) { - g_hash_table_remove(s->attributes, key); -} - - -/** - set up the default properties for a newly created session -*/ -static void session_defaults(struct mwSession *s) { - property_set(s, mwSession_CLIENT_VER_MAJOR, - GPOINTER(MW_PROTOCOL_VERSION_MAJOR), NULL); - - property_set(s, mwSession_CLIENT_VER_MINOR, - GPOINTER(MW_PROTOCOL_VERSION_MINOR), NULL); - - property_set(s, mwSession_CLIENT_TYPE_ID, - GPOINTER(mwLogin_MEANWHILE), NULL); -} - - -struct mwSession *mwSession_new(struct mwSessionHandler *handler) { - struct mwSession *s; - - g_return_val_if_fail(handler != NULL, NULL); - - /* consider io_write and io_close to be absolute necessities */ - g_return_val_if_fail(handler->io_write != NULL, NULL); - g_return_val_if_fail(handler->io_close != NULL, NULL); - - s = g_new0(struct mwSession, 1); - - s->state = mwSession_STOPPED; - - s->handler = handler; - - s->channels = mwChannelSet_new(s); - s->services = map_guint_new(); - s->ciphers = map_guint_new(); - - s->attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify) mw_datum_free); - - session_defaults(s); - - return s; -} - - -/** free and reset the session buffer */ -static void session_buf_free(struct mwSession *s) { - g_return_if_fail(s != NULL); - - g_free(s->buf); - s->buf = NULL; - s->buf_len = 0; - s->buf_used = 0; -} - - -/** a polite string version of the session state enum */ -static const char *state_str(enum mwSessionState state) { - switch(state) { - case mwSession_STARTING: return "starting"; - case mwSession_HANDSHAKE: return "handshake sent"; - case mwSession_HANDSHAKE_ACK: return "handshake acknowledged"; - case mwSession_LOGIN: return "login sent"; - case mwSession_LOGIN_REDIR: return "login redirected"; - case mwSession_LOGIN_CONT: return "forcing login"; - case mwSession_LOGIN_ACK: return "login acknowledged"; - case mwSession_STARTED: return "started"; - case mwSession_STOPPING: return "stopping"; - case mwSession_STOPPED: return "stopped"; - - case mwSession_UNKNOWN: /* fall-through */ - default: return "UNKNOWN"; - } -} - - -void mwSession_free(struct mwSession *s) { - struct mwSessionHandler *h; - - g_return_if_fail(s != NULL); - - if(! mwSession_isStopped(s)) { - g_debug("session is not stopped (state: %s), proceeding with free", - state_str(s->state)); - } - - h = s->handler; - if(h && h->clear) h->clear(s); - s->handler = NULL; - - session_buf_free(s); - - mwChannelSet_free(s->channels); - g_hash_table_destroy(s->services); - g_hash_table_destroy(s->ciphers); - g_hash_table_destroy(s->attributes); - - mwLoginInfo_clear(&s->login); - mwUserStatus_clear(&s->status); - mwPrivacyInfo_clear(&s->privacy); - - g_free(s); -} - - -/** write data to the session handler */ -static int io_write(struct mwSession *s, const guchar *buf, gsize len) { - g_return_val_if_fail(s != NULL, -1); - g_return_val_if_fail(s->handler != NULL, -1); - g_return_val_if_fail(s->handler->io_write != NULL, -1); - - return s->handler->io_write(s, buf, len); -} - - -/** close the session handler */ -static void io_close(struct mwSession *s) { - g_return_if_fail(s != NULL); - g_return_if_fail(s->handler != NULL); - g_return_if_fail(s->handler->io_close != NULL); - - s->handler->io_close(s); -} - - -static void state(struct mwSession *s, enum mwSessionState state, - gpointer info) { - - struct mwSessionHandler *sh; - - g_return_if_fail(s != NULL); - g_return_if_fail(s->handler != NULL); - - if(mwSession_isState(s, state)) return; - - s->state = state; - s->state_info = info; - - switch(state) { - case mwSession_STOPPING: - case mwSession_STOPPED: - g_message("session state: %s (0x%08x)", state_str(state), - GPOINTER_TO_UINT(info)); - break; - - case mwSession_LOGIN_REDIR: - g_message("session state: %s (%s)", state_str(state), - (char *)info); - break; - - default: - g_message("session state: %s", state_str(state)); - } - - sh = s->handler; - if(sh && sh->on_stateChange) - sh->on_stateChange(s, state, info); -} - - -void mwSession_start(struct mwSession *s) { - struct mwMsgHandshake *msg; - int ret; - - g_return_if_fail(s != NULL); - g_return_if_fail(mwSession_isStopped(s)); - - if(mwSession_isStarted(s) || mwSession_isStarting(s)) { - g_debug("attempted to start session that is already started/starting"); - return; - } - - state(s, mwSession_STARTING, 0); - - msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE); - msg->major = GUINT(property_get(s, mwSession_CLIENT_VER_MAJOR)); - msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR)); - msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); - - msg->loclcalc_addr = GUINT(property_get(s, mwSession_CLIENT_IP)); - - if(msg->major >= 0x001e && msg->minor >= 0x001d) { - msg->unknown_a = 0x0100; - msg->local_host = (char *) property_get(s, mwSession_CLIENT_HOST); - } - - ret = mwSession_send(s, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - if(ret) { - mwSession_stop(s, CONNECTION_BROKEN); - } else { - state(s, mwSession_HANDSHAKE, 0); - } -} - - -void mwSession_stop(struct mwSession *s, guint32 reason) { - GList *list, *l = NULL; - struct mwMsgChannelDestroy *msg; - - g_return_if_fail(s != NULL); - - if(mwSession_isStopped(s) || mwSession_isStopping(s)) { - g_debug("attempted to stop session that is already stopped/stopping"); - return; - } - - state(s, mwSession_STOPPING, GUINT_TO_POINTER(reason)); - - for(list = l = mwSession_getServices(s); l; l = l->next) - mwService_stop(MW_SERVICE(l->data)); - g_list_free(list); - - msg = (struct mwMsgChannelDestroy *) - mwMessage_new(mwMessage_CHANNEL_DESTROY); - - msg->head.channel = MW_MASTER_CHANNEL_ID; - msg->reason = reason; - - /* don't care if this fails, we're closing the connection anyway */ - mwSession_send(s, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - session_buf_free(s); - - /* close the connection */ - io_close(s); - - state(s, mwSession_STOPPED, GUINT_TO_POINTER(reason)); -} - - -/** compose authentication information into an opaque based on the - password, encrypted via RC2/40 */ -static void compose_auth_rc2_40(struct mwOpaque *auth, const char *pass) { - guchar iv[8], key[5]; - struct mwOpaque a, b, z; - struct mwPutBuffer *p; - - /* get an IV and a random five-byte key */ - mwIV_init(iv); - mwKeyRandom(key, 5); - - /* the opaque with the key */ - a.len = 5; - a.data = key; - - /* the opaque to receive the encrypted pass */ - b.len = 0; - b.data = NULL; - - /* the plain-text pass dressed up as an opaque */ - z.len = strlen(pass); - z.data = (guchar *) pass; - - /* the opaque with the encrypted pass */ - mwEncrypt(a.data, a.len, iv, &z, &b); - - /* an opaque containing the other two opaques */ - p = mwPutBuffer_new(); - mwOpaque_put(p, &a); - mwOpaque_put(p, &b); - mwPutBuffer_finalize(auth, p); - - /* this is the only one to clear, as the other uses a static buffer */ - mwOpaque_clear(&b); -} - - -static void compose_auth_rc2_128(struct mwOpaque *auth, const char *pass, - guint32 magic, struct mwOpaque *rkey) { - - guchar iv[8]; - struct mwOpaque a, b, c; - struct mwPutBuffer *p; - - struct mwMpi *private, *public; - struct mwMpi *remote; - struct mwMpi *shared; - - private = mwMpi_new(); - public = mwMpi_new(); - remote = mwMpi_new(); - shared = mwMpi_new(); - - mwIV_init(iv); - - mwMpi_randDHKeypair(private, public); - mwMpi_import(remote, rkey); - mwMpi_calculateDHShared(shared, remote, private); - - /* put the password in opaque a */ - p = mwPutBuffer_new(); - guint32_put(p, magic); - mwString_put(p, pass); - mwPutBuffer_finalize(&a, p); - - /* put the shared key in opaque b */ - mwMpi_export(shared, &b); - - /* encrypt the password (a) using the shared key (b), put the result - in opaque c */ - mwEncrypt(b.data+(b.len-16), 16, iv, &a, &c); - - /* don't need the shared key anymore, re-use opaque (b) as the - export of the public key */ - mwOpaque_clear(&b); - mwMpi_export(public, &b); - - p = mwPutBuffer_new(); - guint16_put(p, 0x0001); /* XXX: unknown */ - mwOpaque_put(p, &b); - mwOpaque_put(p, &c); - mwPutBuffer_finalize(auth, p); - - mwOpaque_clear(&a); - mwOpaque_clear(&b); - mwOpaque_clear(&c); - - mwMpi_free(private); - mwMpi_free(public); - mwMpi_free(remote); - mwMpi_free(shared); -} - - -/** handle the receipt of a handshake_ack message by sending the login - message */ -static void HANDSHAKE_ACK_recv(struct mwSession *s, - struct mwMsgHandshakeAck *msg) { - struct mwMsgLogin *log; - int ret; - - g_return_if_fail(s != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(mwSession_isState(s, mwSession_HANDSHAKE) || - mwSession_isState(s, mwSession_LOGIN_CONT)); - - if(mwSession_isState(s, mwSession_LOGIN_CONT)) { - /* this is a login continuation, don't re-send the login. We - should receive a login ack in a moment */ - - state(s, mwSession_HANDSHAKE_ACK, 0); - state(s, mwSession_LOGIN, 0); - return; - - } else { - state(s, mwSession_HANDSHAKE_ACK, 0); - } - - /* record the major/minor versions from the server */ - property_set(s, mwSession_SERVER_VER_MAJOR, GPOINTER(msg->major), NULL); - property_set(s, mwSession_SERVER_VER_MINOR, GPOINTER(msg->minor), NULL); - - /* compose the login message */ - log = (struct mwMsgLogin *) mwMessage_new(mwMessage_LOGIN); - log->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); - log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID)); - - /** @todo default to password for now. later use token optionally */ - { - const char *pw; - pw = (const char *) property_get(s, mwSession_AUTH_PASSWORD); - - if(msg->data.len >= 64) { - /* good login encryption */ - log->auth_type = mwAuthType_RC2_128; - compose_auth_rc2_128(&log->auth_data, pw, msg->magic, &msg->data); - - } else { - /* BAD login encryption */ - log->auth_type = mwAuthType_RC2_40; - compose_auth_rc2_40(&log->auth_data, pw); - } - } - - /* send the login message */ - ret = mwSession_send(s, MW_MESSAGE(log)); - mwMessage_free(MW_MESSAGE(log)); - - if(! ret) { - /* sent login OK, set state appropriately */ - state(s, mwSession_LOGIN, 0); - } -} - - -/** handle the receipt of a login_ack message. This completes the - startup sequence for the session */ -static void LOGIN_ACK_recv(struct mwSession *s, - struct mwMsgLoginAck *msg) { - GList *ll, *l; - - g_return_if_fail(s != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(mwSession_isState(s, mwSession_LOGIN)); - - /* store the login information in the session */ - mwLoginInfo_clear(&s->login); - mwLoginInfo_clone(&s->login, &msg->login); - - state(s, mwSession_LOGIN_ACK, 0); - - /* start up our services */ - for(ll = l = mwSession_getServices(s); l; l = l->next) { - mwService_start(l->data); - } - g_list_free(ll); - - /* @todo any further startup stuff? */ - - state(s, mwSession_STARTED, 0); -} - - -static void CHANNEL_CREATE_recv(struct mwSession *s, - struct mwMsgChannelCreate *msg) { - struct mwChannel *chan; - chan = mwChannel_newIncoming(s->channels, msg->channel); - - /* hand off to channel */ - mwChannel_recvCreate(chan, msg); -} - - -static void CHANNEL_ACCEPT_recv(struct mwSession *s, - struct mwMsgChannelAccept *msg) { - struct mwChannel *chan; - chan = mwChannel_find(s->channels, msg->head.channel); - - g_return_if_fail(chan != NULL); - - /* hand off to channel */ - mwChannel_recvAccept(chan, msg); -} - - -static void CHANNEL_DESTROY_recv(struct mwSession *s, - struct mwMsgChannelDestroy *msg) { - - /* the server can indicate that we should close the session by - destroying the zero channel */ - if(msg->head.channel == MW_MASTER_CHANNEL_ID) { - mwSession_stop(s, msg->reason); - - } else { - struct mwChannel *chan; - chan = mwChannel_find(s->channels, msg->head.channel); - - /* we don't have any such channel... so I guess we destroyed it. - This is to remove a warning from timing errors when two clients - both try to close a channel at about the same time. */ - if(! chan) return; - - /* hand off to channel */ - mwChannel_recvDestroy(chan, msg); - } -} - - -static void CHANNEL_SEND_recv(struct mwSession *s, - struct mwMsgChannelSend *msg) { - struct mwChannel *chan; - chan = mwChannel_find(s->channels, msg->head.channel); - - /* if we don't have any such channel, we're certainly not going to - accept data from it */ - if(! chan) return; - - /* hand off to channel */ - mwChannel_recv(chan, msg); -} - - -static void SET_PRIVACY_LIST_recv(struct mwSession *s, - struct mwMsgSetPrivacyList *msg) { - struct mwSessionHandler *sh = s->handler; - - g_info("SET_PRIVACY_LIST"); - - mwPrivacyInfo_clear(&s->privacy); - mwPrivacyInfo_clone(&s->privacy, &msg->privacy); - - if(sh && sh->on_setPrivacyInfo) - sh->on_setPrivacyInfo(s); -} - - -static void SET_USER_STATUS_recv(struct mwSession *s, - struct mwMsgSetUserStatus *msg) { - struct mwSessionHandler *sh = s->handler; - - mwUserStatus_clear(&s->status); - mwUserStatus_clone(&s->status, &msg->status); - - if(sh && sh->on_setUserStatus) - sh->on_setUserStatus(s); -} - - -static void SENSE_SERVICE_recv(struct mwSession *s, - struct mwMsgSenseService *msg) { - struct mwService *srvc; - - srvc = mwSession_getService(s, msg->service); - if(srvc) mwService_start(srvc); -} - - -static void ADMIN_recv(struct mwSession *s, struct mwMsgAdmin *msg) { - struct mwSessionHandler *sh = s->handler; - - if(sh && sh->on_admin) - sh->on_admin(s, msg->text); -} - - -static void ANNOUNCE_recv(struct mwSession *s, struct mwMsgAnnounce *msg) { - struct mwSessionHandler *sh = s->handler; - - if(sh && sh->on_announce) - sh->on_announce(s, &msg->sender, msg->may_reply, msg->text); -} - - -static void LOGIN_REDIRECT_recv(struct mwSession *s, - struct mwMsgLoginRedirect *msg) { - - state(s, mwSession_LOGIN_REDIR, msg->host); -} - - -#define CASE(var, type) \ -case mwMessage_ ## var: \ - var ## _recv(s, (struct type *) msg); \ - break; - - -static void session_process(struct mwSession *s, - const guchar *buf, gsize len) { - - struct mwOpaque o = { .len = len, .data = (guchar *) buf }; - struct mwGetBuffer *b; - struct mwMessage *msg; - - g_return_if_fail(s != NULL); - g_return_if_fail(buf != NULL); - - /* ignore zero-length messages */ - if(len == 0) return; - - /* wrap up buf */ - b = mwGetBuffer_wrap(&o); - - /* attempt to parse the message. */ - msg = mwMessage_get(b); - - if(mwGetBuffer_error(b)) { - mw_mailme_opaque(&o, "parsing of message failed"); - } - - mwGetBuffer_free(b); - - g_return_if_fail(msg != NULL); - - /* handle each of the appropriate incoming types of mwMessage */ - switch(msg->type) { - CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); - CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); - CASE(LOGIN_ACK, mwMsgLoginAck); - CASE(CHANNEL_CREATE, mwMsgChannelCreate); - CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); - CASE(CHANNEL_SEND, mwMsgChannelSend); - CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); - CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); - CASE(SET_USER_STATUS, mwMsgSetUserStatus); - CASE(SENSE_SERVICE, mwMsgSenseService); - CASE(ADMIN, mwMsgAdmin); - CASE(ANNOUNCE, mwMsgAnnounce); - - default: - g_warning("unknown message type 0x%04x, no handler", msg->type); - } - - mwMessage_free(msg); -} - - -#undef CASE - - -#define ADVANCE(b, n, count) { b += count; n -= count; } - - -/* handle input to complete an existing buffer */ -static gsize session_recv_cont(struct mwSession *s, - const guchar *b, gsize n) { - - /* determine how many bytes still required */ - gsize x = s->buf_len - s->buf_used; - - /* g_message(" session_recv_cont: session = %p, b = %p, n = %u", - s, b, n); */ - - if(n < x) { - /* not quite enough; still need some more */ - memcpy(s->buf+s->buf_used, b, n); - s->buf_used += n; - return 0; - - } else { - /* enough to finish the buffer, at least */ - memcpy(s->buf+s->buf_used, b, x); - ADVANCE(b, n, x); - - if(s->buf_len == 4) { - /* if only the length bytes were being buffered, we'll now try - to complete an actual message */ - - struct mwOpaque o = { 4, s->buf }; - struct mwGetBuffer *gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - - if(n < x) { - /* there isn't enough to meet the demands of the length, so - we'll buffer it for next time */ - - guchar *t; - x += 4; - t = (guchar *) g_malloc(x); - memcpy(t, s->buf, 4); - memcpy(t+4, b, n); - - session_buf_free(s); - - s->buf = t; - s->buf_len = x; - s->buf_used = n + 4; - return 0; - - } else { - /* there's enough (maybe more) for a full message. don't need - the old session buffer (which recall, was only the length - bytes) any more */ - - session_buf_free(s); - session_process(s, b, x); - ADVANCE(b, n, x); - } - - } else { - /* process the now-complete buffer. remember to skip the first - four bytes, since they're just the size count */ - session_process(s, s->buf+4, s->buf_len-4); - session_buf_free(s); - } - } - - return n; -} - - -/* handle input when there's nothing previously buffered */ -static gsize session_recv_empty(struct mwSession *s, - const guchar *b, gsize n) { - - struct mwOpaque o = { n, (guchar *) b }; - struct mwGetBuffer *gb; - gsize x; - - if(n < 4) { - /* uh oh. less than four bytes means we've got an incomplete - length indicator. Have to buffer to get the rest of it. */ - s->buf = (guchar *) g_malloc0(4); - memcpy(s->buf, b, n); - s->buf_len = 4; - s->buf_used = n; - return 0; - } - - /* peek at the length indicator. if it's a zero length message, - don't process, just skip it */ - gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - if(! x) return n - 4; - - if(n < (x + 4)) { - /* if the total amount of data isn't enough to cover the length - bytes and the length indicated by those bytes, then we'll need - to buffer. This is where the DOS mentioned below in - session_recv takes place */ - - x += 4; - s->buf = (guchar *) g_malloc(x); - memcpy(s->buf, b, n); - s->buf_len = x; - s->buf_used = n; - return 0; - - } else { - /* advance past length bytes */ - ADVANCE(b, n, 4); - - /* process and advance */ - session_process(s, b, x); - ADVANCE(b, n, x); - - /* return left-over count */ - return n; - } -} - - -static gsize session_recv(struct mwSession *s, - const guchar *b, gsize n) { - - /* This is messy and kind of confusing. I'd like to simplify it at - some point, but the constraints are as follows: - - - buffer up to a single full message on the session buffer - - buffer must contain the four length bytes - - the four length bytes indicate how much we'll need to buffer - - the four length bytes might not arrive all at once, so it's - possible that we'll need to buffer to get them. - - since our buffering includes the length bytes, we know we - still have an incomplete length if the buffer length is only - four. */ - - /** @todo we should allow a compiled-in upper limit to message - sizes, and just drop messages over that size. However, to do that - we'd need to keep track of the size of a message and keep - dropping bytes until we'd fulfilled the entire length. eg: if we - receive a message size of 10MB, we need to pass up exactly 10MB - before it's safe to start processing the rest as a new - message. As it stands, a malicious packet from the server can run - us out of memory by indicating it's going to send us some - obscenely long message (even if it never actually sends it) */ - - /* g_message(" session_recv: session = %p, b = %p, n = %u", - s, b, n); */ - - if(s->buf_len == 0) { - while(n && (*b & 0x80)) { - /* keep-alive and series bytes are ignored */ - ADVANCE(b, n, 1); - } - } - - if(n == 0) { - return 0; - - } else if(s->buf_len > 0) { - return session_recv_cont(s, b, n); - - } else { - return session_recv_empty(s, b, n); - } -} - - -#undef ADVANCE - - -void mwSession_recv(struct mwSession *s, const guchar *buf, gsize n) { - guchar *b = (guchar *) buf; - gsize remain = 0; - - g_return_if_fail(s != NULL); - - while(n > 0) { - remain = session_recv(s, b, n); - b += (n - remain); - n = remain; - } -} - - -int mwSession_send(struct mwSession *s, struct mwMessage *msg) { - struct mwPutBuffer *b; - struct mwOpaque o; - int ret = 0; - - g_return_val_if_fail(s != NULL, -1); - - /* writing nothing is easy */ - if(! msg) return 0; - - /* first we render the message into an opaque */ - b = mwPutBuffer_new(); - mwMessage_put(b, msg); - mwPutBuffer_finalize(&o, b); - - /* then we render the opaque into... another opaque! */ - b = mwPutBuffer_new(); - mwOpaque_put(b, &o); - mwOpaque_clear(&o); - mwPutBuffer_finalize(&o, b); - - /* then we use that opaque's data and length to write to the socket */ - ret = io_write(s, o.data, o.len); - mwOpaque_clear(&o); - - /* ensure we could actually write the message */ - if(! ret) { - - /* special case, as the server doesn't always respond to user - status messages. Thus, we trigger the event when we send the - messages as well as when we receive them */ - if(msg->type == mwMessage_SET_USER_STATUS) { - SET_USER_STATUS_recv(s, (struct mwMsgSetUserStatus *) msg); - } - } - - return ret; -} - - -int mwSession_sendKeepalive(struct mwSession *s) { - const guchar b = 0x80; - - g_return_val_if_fail(s != NULL, -1); - return io_write(s, &b, 1); -} - - -int mwSession_forceLogin(struct mwSession *s) { - struct mwMsgLoginContinue *msg; - int ret; - - g_return_val_if_fail(s != NULL, -1); - g_return_val_if_fail(mwSession_isState(s, mwSession_LOGIN_REDIR), -1); - - state(s, mwSession_LOGIN_CONT, 0x00); - - msg = (struct mwMsgLoginContinue *) - mwMessage_new(mwMessage_LOGIN_CONTINUE); - - ret = mwSession_send(s, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - return ret; -} - - -int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply, - const char *text, const GList *recipients) { - - struct mwMsgAnnounce *msg; - int ret; - - g_return_val_if_fail(s != NULL, -1); - g_return_val_if_fail(mwSession_isStarted(s), -1); - - msg = (struct mwMsgAnnounce *) mwMessage_new(mwMessage_ANNOUNCE); - - msg->recipients = (GList *) recipients; - msg->may_reply = may_reply; - msg->text = g_strdup(text); - - ret = mwSession_send(s, MW_MESSAGE(msg)); - - msg->recipients = NULL; /* don't kill our recipients param */ - mwMessage_free(MW_MESSAGE(msg)); - - return ret; -} - - -struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) { - g_return_val_if_fail(s != NULL, NULL); - return s->handler; -} - - -struct mwLoginInfo *mwSession_getLoginInfo(struct mwSession *s) { - g_return_val_if_fail(s != NULL, NULL); - return &s->login; -} - - -int mwSession_setPrivacyInfo(struct mwSession *s, - struct mwPrivacyInfo *privacy) { - - struct mwMsgSetPrivacyList *msg; - int ret; - - g_return_val_if_fail(s != NULL, -1); - g_return_val_if_fail(privacy != NULL, -1); - - msg = (struct mwMsgSetPrivacyList *) - mwMessage_new(mwMessage_SET_PRIVACY_LIST); - - mwPrivacyInfo_clone(&msg->privacy, privacy); - - ret = mwSession_send(s, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - return ret; -} - - -struct mwPrivacyInfo *mwSession_getPrivacyInfo(struct mwSession *s) { - g_return_val_if_fail(s != NULL, NULL); - return &s->privacy; -} - - -int mwSession_setUserStatus(struct mwSession *s, - struct mwUserStatus *stat) { - - struct mwMsgSetUserStatus *msg; - int ret; - - g_return_val_if_fail(s != NULL, -1); - g_return_val_if_fail(stat != NULL, -1); - - msg = (struct mwMsgSetUserStatus *) - mwMessage_new(mwMessage_SET_USER_STATUS); - - mwUserStatus_clone(&msg->status, stat); - - ret = mwSession_send(s, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - return ret; -} - - -struct mwUserStatus *mwSession_getUserStatus(struct mwSession *s) { - g_return_val_if_fail(s != NULL, NULL); - return &s->status; -} - - -enum mwSessionState mwSession_getState(struct mwSession *s) { - g_return_val_if_fail(s != NULL, mwSession_UNKNOWN); - return s->state; -} - - -gpointer mwSession_getStateInfo(struct mwSession *s) { - g_return_val_if_fail(s != NULL, 0); - return s->state_info; -} - - -struct mwChannelSet *mwSession_getChannels(struct mwSession *session) { - g_return_val_if_fail(session != NULL, NULL); - return session->channels; -} - - -gboolean mwSession_addService(struct mwSession *s, struct mwService *srv) { - g_return_val_if_fail(s != NULL, FALSE); - g_return_val_if_fail(srv != NULL, FALSE); - g_return_val_if_fail(s->services != NULL, FALSE); - - if(map_guint_lookup(s->services, SERVICE_KEY(srv))) { - return FALSE; - - } else { - map_guint_insert(s->services, SERVICE_KEY(srv), srv); - if(mwSession_isState(s, mwSession_STARTED)) - mwSession_senseService(s, mwService_getType(srv)); - return TRUE; - } -} - - -struct mwService *mwSession_getService(struct mwSession *s, guint32 srv) { - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->services != NULL, NULL); - - return map_guint_lookup(s->services, srv); -} - - -struct mwService *mwSession_removeService(struct mwSession *s, guint32 srv) { - struct mwService *svc; - - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->services != NULL, NULL); - - svc = map_guint_lookup(s->services, srv); - if(svc) map_guint_remove(s->services, srv); - return svc; -} - - -GList *mwSession_getServices(struct mwSession *s) { - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->services != NULL, NULL); - - return map_collect_values(s->services); -} - - -void mwSession_senseService(struct mwSession *s, guint32 srvc) { - struct mwMsgSenseService *msg; - - g_return_if_fail(s != NULL); - g_return_if_fail(srvc != 0x00); - g_return_if_fail(mwSession_isStarted(s)); - - msg = (struct mwMsgSenseService *) - mwMessage_new(mwMessage_SENSE_SERVICE); - msg->service = srvc; - - mwSession_send(s, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); -} - - -gboolean mwSession_addCipher(struct mwSession *s, struct mwCipher *c) { - g_return_val_if_fail(s != NULL, FALSE); - g_return_val_if_fail(c != NULL, FALSE); - g_return_val_if_fail(s->ciphers != NULL, FALSE); - - if(map_guint_lookup(s->ciphers, mwCipher_getType(c))) { - g_message("cipher %s is already added, apparently", - NSTR(mwCipher_getName(c))); - return FALSE; - - } else { - g_message("adding cipher %s", NSTR(mwCipher_getName(c))); - map_guint_insert(s->ciphers, mwCipher_getType(c), c); - return TRUE; - } -} - - -struct mwCipher *mwSession_getCipher(struct mwSession *s, guint16 c) { - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->ciphers != NULL, NULL); - - return map_guint_lookup(s->ciphers, c); -} - - -struct mwCipher *mwSession_removeCipher(struct mwSession *s, guint16 c) { - struct mwCipher *ciph; - - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->ciphers != NULL, NULL); - - ciph = map_guint_lookup(s->ciphers, c); - if(ciph) map_guint_remove(s->ciphers, c); - return ciph; -} - - -GList *mwSession_getCiphers(struct mwSession *s) { - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->ciphers != NULL, NULL); - - return map_collect_values(s->ciphers); -} - - -void mwSession_setProperty(struct mwSession *s, const char *key, - gpointer val, GDestroyNotify clean) { - - g_return_if_fail(s != NULL); - g_return_if_fail(s->attributes != NULL); - g_return_if_fail(key != NULL); - - property_set(s, key, val, clean); -} - - -gpointer mwSession_getProperty(struct mwSession *s, const char *key) { - - g_return_val_if_fail(s != NULL, NULL); - g_return_val_if_fail(s->attributes != NULL, NULL); - g_return_val_if_fail(key != NULL, NULL); - - return property_get(s, key); -} - - -void mwSession_removeProperty(struct mwSession *s, const char *key) { - g_return_if_fail(s != NULL); - g_return_if_fail(s->attributes != NULL); - g_return_if_fail(key != NULL); - - property_del(s, key); -} - - -void mwSession_setClientData(struct mwSession *session, - gpointer data, GDestroyNotify clear) { - - g_return_if_fail(session != NULL); - mw_datum_set(&session->client_data, data, clear); -} - - -gpointer mwSession_getClientData(struct mwSession *session) { - g_return_val_if_fail(session != NULL, NULL); - return mw_datum_get(&session->client_data); -} - - -void mwSession_removeClientData(struct mwSession *session) { - g_return_if_fail(session != NULL); - mw_datum_clear(&session->client_data); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_aware.c --- a/src/protocols/sametime/meanwhile/srvc_aware.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1318 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include - -#include "mw_channel.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_aware.h" -#include "mw_util.h" - - -struct mwServiceAware { - struct mwService service; - - struct mwAwareHandler *handler; - - /** map of ENTRY_KEY(aware_entry):aware_entry */ - GHashTable *entries; - - /** set of guint32:attrib_watch_entry attribute keys */ - GHashTable *attribs; - - /** collection of lists of awareness for this service. Each item is - a mwAwareList */ - GList *lists; - - /** the buddy list channel */ - struct mwChannel *channel; -}; - - -struct mwAwareList { - - /** the owning service */ - struct mwServiceAware *service; - - /** map of ENTRY_KEY(aware_entry):aware_entry */ - GHashTable *entries; - - /** set of guint32:attrib_watch_entry attribute keys */ - GHashTable *attribs; - - struct mwAwareListHandler *handler; - struct mw_datum client_data; -}; - - -struct mwAwareAttribute { - guint32 key; - struct mwOpaque data; -}; - - -struct attrib_entry { - guint32 key; - GList *membership; -}; - - -/** an actual awareness entry, belonging to any number of aware lists */ -struct aware_entry { - struct mwAwareSnapshot aware; - - /** list of mwAwareList containing this entry */ - GList *membership; - - /** collection of attribute values for this entry. - map of ATTRIB_KEY(mwAwareAttribute):mwAwareAttribute */ - GHashTable *attribs; -}; - - -#define ENTRY_KEY(entry) &entry->aware.id - - -/** the channel send types used by this service */ -enum msg_types { - msg_AWARE_ADD = 0x0068, /**< remove an aware */ - msg_AWARE_REMOVE = 0x0069, /**< add an aware */ - - msg_OPT_DO_SET = 0x00c9, /**< set an attribute */ - msg_OPT_DO_UNSET = 0x00ca, /**< unset an attribute */ - msg_OPT_WATCH = 0x00cb, /**< set the attribute watch list */ - - msg_AWARE_SNAPSHOT = 0x01f4, /**< recv aware snapshot */ - msg_AWARE_UPDATE = 0x01f5, /**< recv aware update */ - msg_AWARE_GROUP = 0x01f6, /**< recv group aware */ - - msg_OPT_GOT_SET = 0x0259, /**< recv attribute set update */ - msg_OPT_GOT_UNSET = 0x025a, /**< recv attribute unset update */ - - msg_OPT_GOT_UNKNOWN = 0x025b, /**< UNKNOWN */ - - msg_OPT_DID_SET = 0x025d, /**< attribute set response */ - msg_OPT_DID_UNSET = 0x025e, /**< attribute unset response */ - msg_OPT_DID_ERROR = 0x025f, /**< attribute set/unset error */ -}; - - -static void aware_entry_free(struct aware_entry *ae) { - mwAwareSnapshot_clear(&ae->aware); - g_list_free(ae->membership); - g_hash_table_destroy(ae->attribs); - g_free(ae); -} - - -static void attrib_entry_free(struct attrib_entry *ae) { - g_list_free(ae->membership); - g_free(ae); -} - - -static void attrib_free(struct mwAwareAttribute *attrib) { - mwOpaque_clear(&attrib->data); - g_free(attrib); -} - - -static struct aware_entry *aware_find(struct mwServiceAware *srvc, - struct mwAwareIdBlock *srch) { - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(srvc->entries != NULL, NULL); - g_return_val_if_fail(srch != NULL, NULL); - - return g_hash_table_lookup(srvc->entries, srch); -} - - -static struct aware_entry *list_aware_find(struct mwAwareList *list, - struct mwAwareIdBlock *srch) { - g_return_val_if_fail(list != NULL, NULL); - g_return_val_if_fail(list->entries != NULL, NULL); - g_return_val_if_fail(srch != NULL, NULL); - - return g_hash_table_lookup(list->entries, srch); -} - - -static void compose_list(struct mwPutBuffer *b, GList *id_list) { - guint32_put(b, g_list_length(id_list)); - for(; id_list; id_list = id_list->next) - mwAwareIdBlock_put(b, id_list->data); -} - - -static int send_add(struct mwChannel *chan, GList *id_list) { - struct mwPutBuffer *b = mwPutBuffer_new(); - struct mwOpaque o; - int ret; - - g_return_val_if_fail(chan != NULL, 0); - - compose_list(b, id_list); - - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_send(chan, msg_AWARE_ADD, &o); - mwOpaque_clear(&o); - - return ret; -} - - -static int send_rem(struct mwChannel *chan, GList *id_list) { - struct mwPutBuffer *b = mwPutBuffer_new(); - struct mwOpaque o; - int ret; - - g_return_val_if_fail(chan != NULL, 0); - - compose_list(b, id_list); - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_send(chan, msg_AWARE_REMOVE, &o); - mwOpaque_clear(&o); - - return ret; -} - - -static gboolean collect_dead(gpointer key, gpointer val, gpointer data) { - struct aware_entry *aware = val; - GList **dead = data; - - if(aware->membership == NULL) { - g_info(" removing %s, %s", - NSTR(aware->aware.id.user), NSTR(aware->aware.id.community)); - *dead = g_list_append(*dead, aware); - return TRUE; - - } else { - return FALSE; - } -} - - -static int remove_unused(struct mwServiceAware *srvc) { - /* - create a GList of all the unused aware entries - - remove each unused aware from the service - - if the service is alive, send a removal message for the collected - unused. - */ - - int ret = 0; - GList *dead = NULL, *l; - - if(srvc->entries) { - g_info("bring out your dead *clang*"); - g_hash_table_foreach_steal(srvc->entries, collect_dead, &dead); - } - - if(dead) { - if(MW_SERVICE_IS_LIVE(srvc)) - ret = send_rem(srvc->channel, dead) || ret; - - for(l = dead; l; l = l->next) - aware_entry_free(l->data); - - g_list_free(dead); - } - - return ret; -} - - -static int send_attrib_list(struct mwServiceAware *srvc) { - struct mwPutBuffer *b; - struct mwOpaque o; - - int tmp; - GList *l; - - g_return_val_if_fail(srvc != NULL, -1); - g_return_val_if_fail(srvc->channel != NULL, 0); - - l = map_collect_keys(srvc->attribs); - tmp = g_list_length(l); - - b = mwPutBuffer_new(); - guint32_put(b, 0x00); - guint32_put(b, tmp); - - for(; l; l = g_list_delete_link(l, l)) { - guint32_put(b, GPOINTER_TO_UINT(l->data)); - } - - mwPutBuffer_finalize(&o, b); - tmp = mwChannel_send(srvc->channel, msg_OPT_WATCH, &o); - mwOpaque_clear(&o); - - return tmp; -} - - -static gboolean collect_attrib_dead(gpointer key, gpointer val, - gpointer data) { - - struct attrib_entry *attrib = val; - GList **dead = data; - - if(attrib->membership == NULL) { - g_info(" removing 0x%08x", GPOINTER_TO_UINT(key)); - *dead = g_list_append(*dead, attrib); - return TRUE; - - } else { - return FALSE; - } -} - - -static int remove_unused_attrib(struct mwServiceAware *srvc) { - GList *dead = NULL; - - if(srvc->attribs) { - g_info("collecting dead attributes"); - g_hash_table_foreach_steal(srvc->attribs, collect_attrib_dead, &dead); - } - - /* since we stole them, we'll have to clean 'em up manually */ - for(; dead; dead = g_list_delete_link(dead, dead)) { - attrib_entry_free(dead->data); - } - - return MW_SERVICE_IS_LIVE(srvc)? send_attrib_list(srvc): 0; -} - - -static void recv_accept(struct mwServiceAware *srvc, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - g_return_if_fail(srvc->channel != NULL); - g_return_if_fail(srvc->channel == chan); - - if(MW_SERVICE_IS_STARTING(MW_SERVICE(srvc))) { - GList *list = NULL; - - list = map_collect_values(srvc->entries); - send_add(chan, list); - g_list_free(list); - - send_attrib_list(srvc); - - mwService_started(MW_SERVICE(srvc)); - - } else { - mwChannel_destroy(chan, ERR_FAILURE, NULL); - } -} - - -static void recv_destroy(struct mwServiceAware *srvc, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - srvc->channel = NULL; - mwService_stop(MW_SERVICE(srvc)); - - /** @todo session sense service and mwService_start */ -} - - -/** called from SNAPSHOT_recv, UPDATE_recv, and - mwServiceAware_setStatus */ -static void status_recv(struct mwServiceAware *srvc, - struct mwAwareSnapshot *idb) { - - struct aware_entry *aware; - GList *l; - - aware = aware_find(srvc, &idb->id); - - if(! aware) { - /* we don't deal with receiving status for something we're not - monitoring, but it will happen sometimes, eg from manually set - status */ - return; - } - - /* clear the existing status, then clone in the new status */ - mwAwareSnapshot_clear(&aware->aware); - mwAwareSnapshot_clone(&aware->aware, idb); - - /* trigger each of the entry's lists */ - for(l = aware->membership; l; l = l->next) { - struct mwAwareList *alist = l->data; - struct mwAwareListHandler *handler = alist->handler; - - if(handler && handler->on_aware) - handler->on_aware(alist, idb); - } -} - - -static void attrib_recv(struct mwServiceAware *srvc, - struct mwAwareIdBlock *idb, - struct mwAwareAttribute *attrib) { - - struct aware_entry *aware; - struct mwAwareAttribute *old_attrib = NULL; - GList *l; - guint32 key; - gpointer k; - - aware = aware_find(srvc, idb); - g_return_if_fail(aware != NULL); - - key = attrib->key; - k = GUINT_TO_POINTER(key); - - if(aware->attribs) - old_attrib = g_hash_table_lookup(aware->attribs, k); - - if(! old_attrib) { - old_attrib = g_new0(struct mwAwareAttribute, 1); - old_attrib->key = key; - g_hash_table_insert(aware->attribs, k, old_attrib); - } - - mwOpaque_clear(&old_attrib->data); - mwOpaque_clone(&old_attrib->data, &attrib->data); - - for(l = aware->membership; l; l = l->next) { - struct mwAwareList *list = l->data; - struct mwAwareListHandler *h = list->handler; - - if(h && h->on_attrib && - list->attribs && g_hash_table_lookup(list->attribs, k)) - - h->on_attrib(list, idb, old_attrib); - } -} - - -gboolean list_add(struct mwAwareList *list, struct mwAwareIdBlock *id) { - - struct mwServiceAware *srvc = list->service; - struct aware_entry *aware; - - g_return_val_if_fail(id->user != NULL, FALSE); - g_return_val_if_fail(strlen(id->user) > 0, FALSE); - - if(! list->entries) - list->entries = g_hash_table_new((GHashFunc) mwAwareIdBlock_hash, - (GEqualFunc) mwAwareIdBlock_equal); - - aware = list_aware_find(list, id); - if(aware) return FALSE; - - aware = aware_find(srvc, id); - if(! aware) { - aware = g_new0(struct aware_entry, 1); - aware->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) attrib_free); - mwAwareIdBlock_clone(ENTRY_KEY(aware), id); - - g_hash_table_insert(srvc->entries, ENTRY_KEY(aware), aware); - } - - aware->membership = g_list_append(aware->membership, list); - - g_hash_table_insert(list->entries, ENTRY_KEY(aware), aware); - - return TRUE; -} - - -static void group_member_recv(struct mwServiceAware *srvc, - struct mwAwareSnapshot *idb) { - /* @todo - - look up group by id - - find each list group belongs to - - add user to lists - */ - - struct mwAwareIdBlock gsrch = { mwAware_GROUP, idb->group, NULL }; - struct aware_entry *grp; - GList *l, *m; - - grp = aware_find(srvc, &gsrch); - g_return_if_fail(grp != NULL); /* this could happen, with timing. */ - - l = g_list_prepend(NULL, &idb->id); - - for(m = grp->membership; m; m = m->next) { - - /* if we just list_add, we won't receive updates for attributes, - so annoyingly we have to turn around and send out an add aware - message for each incoming group member */ - - /* list_add(m->data, &idb->id); */ - mwAwareList_addAware(m->data, l); - } - - g_list_free(l); -} - - -static void recv_SNAPSHOT(struct mwServiceAware *srvc, - struct mwGetBuffer *b) { - - guint32 count; - - struct mwAwareSnapshot *snap; - snap = g_new0(struct mwAwareSnapshot, 1); - - guint32_get(b, &count); - - while(count--) { - mwAwareSnapshot_get(b, snap); - - if(mwGetBuffer_error(b)) { - mwAwareSnapshot_clear(snap); - break; - } - - if(snap->group) - group_member_recv(srvc, snap); - - status_recv(srvc, snap); - mwAwareSnapshot_clear(snap); - } - - g_free(snap); -} - - -static void recv_UPDATE(struct mwServiceAware *srvc, - struct mwGetBuffer *b) { - - struct mwAwareSnapshot *snap; - - snap = g_new0(struct mwAwareSnapshot, 1); - mwAwareSnapshot_get(b, snap); - - if(snap->group) - group_member_recv(srvc, snap); - - if(! mwGetBuffer_error(b)) - status_recv(srvc, snap); - - mwAwareSnapshot_clear(snap); - g_free(snap); -} - - -static void recv_GROUP(struct mwServiceAware *srvc, - struct mwGetBuffer *b) { - - struct mwAwareIdBlock idb = { 0, 0, 0 }; - - /* really nothing to be done with this. The group should have - already been added to the list and service, and is now simply - awaiting a snapshot/update with users listed as belonging in said - group. */ - - mwAwareIdBlock_get(b, &idb); - mwAwareIdBlock_clear(&idb); -} - - -static void recv_OPT_GOT_SET(struct mwServiceAware *srvc, - struct mwGetBuffer *b) { - - struct mwAwareAttribute attrib; - struct mwAwareIdBlock idb; - guint32 junk, check; - - guint32_get(b, &junk); - mwAwareIdBlock_get(b, &idb); - guint32_get(b, &junk); - guint32_get(b, &check); - guint32_get(b, &junk); - guint32_get(b, &attrib.key); - - if(check) { - mwOpaque_get(b, &attrib.data); - } else { - attrib.data.len = 0; - attrib.data.data = NULL; - } - - attrib_recv(srvc, &idb, &attrib); - - mwAwareIdBlock_clear(&idb); - mwOpaque_clear(&attrib.data); -} - - -static void recv_OPT_GOT_UNSET(struct mwServiceAware *srvc, - struct mwGetBuffer *b) { - - struct mwAwareAttribute attrib; - struct mwAwareIdBlock idb; - guint32 junk; - - attrib.key = 0; - attrib.data.len = 0; - attrib.data.data = NULL; - - guint32_get(b, &junk); - mwAwareIdBlock_get(b, &idb); - guint32_get(b, &attrib.key); - - attrib_recv(srvc, &idb, &attrib); - - mwAwareIdBlock_clear(&idb); -} - - -static void recv(struct mwService *srvc, struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc; - struct mwGetBuffer *b; - - g_return_if_fail(srvc_aware->channel == chan); - g_return_if_fail(srvc->session == mwChannel_getSession(chan)); - g_return_if_fail(data != NULL); - - b = mwGetBuffer_wrap(data); - - switch(type) { - case msg_AWARE_SNAPSHOT: - recv_SNAPSHOT(srvc_aware, b); - break; - - case msg_AWARE_UPDATE: - recv_UPDATE(srvc_aware, b); - break; - - case msg_AWARE_GROUP: - recv_GROUP(srvc_aware, b); - break; - - case msg_OPT_GOT_SET: - recv_OPT_GOT_SET(srvc_aware, b); - break; - - case msg_OPT_GOT_UNSET: - recv_OPT_GOT_UNSET(srvc_aware, b); - break; - - case msg_OPT_GOT_UNKNOWN: - case msg_OPT_DID_SET: - case msg_OPT_DID_UNSET: - case msg_OPT_DID_ERROR: - break; - - default: - mw_mailme_opaque(data, "unknown message in aware service: 0x%04x", type); - } - - mwGetBuffer_free(b); -} - - -static void clear(struct mwService *srvc) { - struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc; - - g_return_if_fail(srvc != NULL); - - while(srvc_aware->lists) - mwAwareList_free( (struct mwAwareList *) srvc_aware->lists->data ); - - g_hash_table_destroy(srvc_aware->entries); - srvc_aware->entries = NULL; - - g_hash_table_destroy(srvc_aware->attribs); - srvc_aware->attribs = NULL; -} - - -static const char *name(struct mwService *srvc) { - return "Presence Awareness"; -} - - -static const char *desc(struct mwService *srvc) { - return "Buddy list service with support for server-side groups"; -} - - -static struct mwChannel *make_blist(struct mwServiceAware *srvc, - struct mwChannelSet *cs) { - - struct mwChannel *chan = mwChannel_newOutgoing(cs); - - mwChannel_setService(chan, MW_SERVICE(srvc)); - mwChannel_setProtoType(chan, 0x00000011); - mwChannel_setProtoVer(chan, 0x00030005); - - return mwChannel_create(chan)? NULL: chan; -} - - -static void start(struct mwService *srvc) { - struct mwServiceAware *srvc_aware; - struct mwChannel *chan = NULL; - - srvc_aware = (struct mwServiceAware *) srvc; - chan = make_blist(srvc_aware, mwSession_getChannels(srvc->session)); - - if(chan != NULL) { - srvc_aware->channel = chan; - } else { - mwService_stopped(srvc); - } -} - - -static void stop(struct mwService *srvc) { - struct mwServiceAware *srvc_aware; - - srvc_aware = (struct mwServiceAware *) srvc; - - if(srvc_aware->channel) { - mwChannel_destroy(srvc_aware->channel, ERR_SUCCESS, NULL); - srvc_aware->channel = NULL; - } - - mwService_stopped(srvc); -} - - -struct mwServiceAware * -mwServiceAware_new(struct mwSession *session, - struct mwAwareHandler *handler) { - - struct mwService *service; - struct mwServiceAware *srvc; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(handler != NULL, NULL); - - srvc = g_new0(struct mwServiceAware, 1); - srvc->handler = handler; - srvc->entries = g_hash_table_new_full((GHashFunc) mwAwareIdBlock_hash, - (GEqualFunc) mwAwareIdBlock_equal, - NULL, - (GDestroyNotify) aware_entry_free); - - srvc->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) attrib_entry_free); - - service = MW_SERVICE(srvc); - mwService_init(service, session, mwService_AWARE); - - service->recv_accept = (mwService_funcRecvAccept) recv_accept; - service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy; - service->recv = recv; - service->start = start; - service->stop = stop; - service->clear = clear; - service->get_name = name; - service->get_desc = desc; - - return srvc; -} - - -int mwServiceAware_setAttribute(struct mwServiceAware *srvc, - guint32 key, struct mwOpaque *data) { - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - b = mwPutBuffer_new(); - - guint32_put(b, 0x00); - guint32_put(b, data->len); - guint32_put(b, 0x00); - guint32_put(b, key); - mwOpaque_put(b, data); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(srvc->channel, msg_OPT_DO_SET, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc, - guint32 key, gboolean val) { - int ret; - struct mwPutBuffer *b; - struct mwOpaque o; - - b = mwPutBuffer_new(); - - gboolean_put(b, FALSE); - gboolean_put(b, val); - - mwPutBuffer_finalize(&o, b); - - ret = mwServiceAware_setAttribute(srvc, key, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc, - guint32 key, guint32 val) { - int ret; - struct mwPutBuffer *b; - struct mwOpaque o; - - b = mwPutBuffer_new(); - guint32_put(b, val); - - mwPutBuffer_finalize(&o, b); - - ret = mwServiceAware_setAttribute(srvc, key, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwServiceAware_setAttributeString(struct mwServiceAware *srvc, - guint32 key, const char *str) { - int ret; - struct mwPutBuffer *b; - struct mwOpaque o; - - b = mwPutBuffer_new(); - mwString_put(b, str); - - mwPutBuffer_finalize(&o, b); - - ret = mwServiceAware_setAttribute(srvc, key, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc, - guint32 key) { - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - b = mwPutBuffer_new(); - - guint32_put(b, 0x00); - guint32_put(b, key); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(srvc->channel, msg_OPT_DO_UNSET, &o); - mwOpaque_clear(&o); - - return ret; -} - - -guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib) { - g_return_val_if_fail(attrib != NULL, 0x00); - return attrib->key; -} - - -gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib) { - struct mwGetBuffer *b; - gboolean ret; - - if(! attrib) return FALSE; - - b = mwGetBuffer_wrap(&attrib->data); - if(attrib->data.len >= 4) { - guint32 r32 = 0x00; - guint32_get(b, &r32); - ret = !! r32; - - } else if(attrib->data.len >= 2) { - guint16 r16 = 0x00; - guint16_get(b, &r16); - ret = !! r16; - - } else if(attrib->data.len) { - gboolean_get(b, &ret); - } - - mwGetBuffer_free(b); - - return ret; -} - - -guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib) { - struct mwGetBuffer *b; - guint32 r32 = 0x00; - - if(! attrib) return 0x00; - - b = mwGetBuffer_wrap(&attrib->data); - if(attrib->data.len >= 4) { - guint32_get(b, &r32); - - } else if(attrib->data.len == 3) { - gboolean rb = FALSE; - guint16 r16 = 0x00; - gboolean_get(b, &rb); - guint16_get(b, &r16); - r32 = (guint32) r16; - - } else if(attrib->data.len == 2) { - guint16 r16 = 0x00; - guint16_get(b, &r16); - r32 = (guint32) r16; - - } else if(attrib->data.len) { - gboolean rb = FALSE; - gboolean_get(b, &rb); - r32 = (guint32) rb; - } - - mwGetBuffer_free(b); - - return r32; -} - - -char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib) { - struct mwGetBuffer *b; - char *ret = NULL; - - if(! attrib) return NULL; - - b = mwGetBuffer_wrap(&attrib->data); - mwString_get(b, &ret); - mwGetBuffer_free(b); - - return ret; -} - - -const struct mwOpaque * -mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib) { - g_return_val_if_fail(attrib != NULL, NULL); - return &attrib->data; -} - - -struct mwAwareList * -mwAwareList_new(struct mwServiceAware *srvc, - struct mwAwareListHandler *handler) { - - struct mwAwareList *al; - - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(handler != NULL, NULL); - - al = g_new0(struct mwAwareList, 1); - al->service = srvc; - al->handler = handler; - - srvc->lists = g_list_prepend(srvc->lists, al); - - return al; -} - - -void mwAwareList_free(struct mwAwareList *list) { - struct mwServiceAware *srvc; - struct mwAwareListHandler *handler; - - g_return_if_fail(list != NULL); - g_return_if_fail(list->service != NULL); - - srvc = list->service; - srvc->lists = g_list_remove_all(srvc->lists, list); - - handler = list->handler; - if(handler && handler->clear) { - handler->clear(list); - list->handler = NULL; - } - - mw_datum_clear(&list->client_data); - - mwAwareList_unwatchAllAttributes(list); - mwAwareList_removeAllAware(list); - - list->service = NULL; - - g_free(list); -} - - -struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list) { - g_return_val_if_fail(list != NULL, NULL); - return list->handler; -} - - -static void watch_add(struct mwAwareList *list, guint32 key) { - struct mwServiceAware *srvc; - struct attrib_entry *watch; - gpointer k = GUINT_TO_POINTER(key); - - if(! list->attribs) - list->attribs = g_hash_table_new(g_direct_hash, g_direct_equal); - - if(g_hash_table_lookup(list->attribs, k)) - return; - - srvc = list->service; - - watch = g_hash_table_lookup(srvc->attribs, k); - if(! watch) { - watch = g_new0(struct attrib_entry, 1); - watch->key = key; - g_hash_table_insert(srvc->attribs, k, watch); - } - - g_hash_table_insert(list->attribs, k, watch); - - watch->membership = g_list_prepend(watch->membership, list); -} - - -static void watch_remove(struct mwAwareList *list, guint32 key) { - struct attrib_entry *watch = NULL; - gpointer k = GUINT_TO_POINTER(key); - - if(list->attribs) - watch = g_hash_table_lookup(list->attribs, k); - - g_return_if_fail(watch != NULL); - - g_hash_table_remove(list->attribs, k); - watch->membership = g_list_remove(watch->membership, list); -} - - -int mwAwareList_watchAttributeArray(struct mwAwareList *list, - guint32 *keys) { - guint32 k; - - g_return_val_if_fail(list != NULL, -1); - g_return_val_if_fail(list->service != NULL, -1); - - if(! keys) return 0; - - for(k = *keys; k; keys++) - watch_add(list, k); - - return send_attrib_list(list->service); -} - - -int mwAwareList_watchAttributes(struct mwAwareList *list, - guint32 key, ...) { - guint32 k; - va_list args; - - g_return_val_if_fail(list != NULL, -1); - g_return_val_if_fail(list->service != NULL, -1); - - va_start(args, key); - for(k = key; k; k = va_arg(args, guint32)) - watch_add(list, k); - va_end(args); - - return send_attrib_list(list->service); -} - - -int mwAwareList_unwatchAttributeArray(struct mwAwareList *list, - guint32 *keys) { - guint32 k; - - g_return_val_if_fail(list != NULL, -1); - g_return_val_if_fail(list->service != NULL, -1); - - if(! keys) return 0; - - for(k = *keys; k; keys++) - watch_add(list, k); - - return remove_unused_attrib(list->service); -} - - -int mwAwareList_unwatchAttributes(struct mwAwareList *list, - guint32 key, ...) { - guint32 k; - va_list args; - - g_return_val_if_fail(list != NULL, -1); - g_return_val_if_fail(list->service != NULL, -1); - - va_start(args, key); - for(k = key; k; k = va_arg(args, guint32)) - watch_remove(list, k); - va_end(args); - - return remove_unused_attrib(list->service); -} - - -static void dismember_attrib(gpointer k, struct attrib_entry *watch, - struct mwAwareList *list) { - - watch->membership = g_list_remove(watch->membership, list); -} - - -int mwAwareList_unwatchAllAttributes(struct mwAwareList *list) { - - struct mwServiceAware *srvc; - - g_return_val_if_fail(list != NULL, -1); - srvc = list->service; - - if(list->attribs) { - g_hash_table_foreach(list->attribs, (GHFunc) dismember_attrib, list); - g_hash_table_destroy(list->attribs); - } - - return remove_unused_attrib(srvc); -} - - -static void collect_attrib_keys(gpointer key, struct attrib_entry *attrib, - guint32 **ck) { - guint32 *keys = (*ck)++; - *keys = GPOINTER_TO_UINT(key); -} - - -guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list) { - guint32 *keys, **ck; - guint count; - - g_return_val_if_fail(list != NULL, NULL); - g_return_val_if_fail(list->attribs != NULL, NULL); - - count = g_hash_table_size(list->attribs); - keys = g_new0(guint32, count + 1); - - ck = &keys; - g_hash_table_foreach(list->attribs, (GHFunc) collect_attrib_keys, ck); - - return keys; -} - - -int mwAwareList_addAware(struct mwAwareList *list, GList *id_list) { - - /* for each awareness id: - - if it's already in the list, continue - - if it's not in the service list: - - create an awareness - - add it to the service list - - add this list to the membership - - add to the list - */ - - struct mwServiceAware *srvc; - GList *additions = NULL; - int ret = 0; - - g_return_val_if_fail(list != NULL, -1); - - srvc = list->service; - g_return_val_if_fail(srvc != NULL, -1); - - for(; id_list; id_list = id_list->next) { - if(list_add(list, id_list->data)) - additions = g_list_prepend(additions, id_list->data); - } - - /* if the service is alive-- or getting there-- we'll need to send - these additions upstream */ - if(MW_SERVICE_IS_LIVE(srvc) && additions) - ret = send_add(srvc->channel, additions); - - g_list_free(additions); - return ret; -} - - -int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list) { - - /* for each awareness id: - - if it's not in the list, forget it - - remove from the list - - remove list from the membership - - - call remove round - */ - - struct mwServiceAware *srvc; - struct mwAwareIdBlock *id; - struct aware_entry *aware; - - g_return_val_if_fail(list != NULL, -1); - - srvc = list->service; - g_return_val_if_fail(srvc != NULL, -1); - - for(; id_list; id_list = id_list->next) { - id = id_list->data; - aware = list_aware_find(list, id); - - if(! aware) { - g_warning("buddy %s, %s not in list", - NSTR(id->user), - NSTR(id->community)); - continue; - } - - aware->membership = g_list_remove(aware->membership, list); - g_hash_table_remove(list->entries, id); - } - - return remove_unused(srvc); -} - - -static void dismember_aware(gpointer k, struct aware_entry *aware, - struct mwAwareList *list) { - - aware->membership = g_list_remove(aware->membership, list); -} - - -int mwAwareList_removeAllAware(struct mwAwareList *list) { - struct mwServiceAware *srvc; - - g_return_val_if_fail(list != NULL, -1); - srvc = list->service; - - g_return_val_if_fail(srvc != NULL, -1); - - /* for each entry, remove the aware list from the service entry's - membership collection */ - if(list->entries) { - g_hash_table_foreach(list->entries, (GHFunc) dismember_aware, list); - g_hash_table_destroy(list->entries); - } - - return remove_unused(srvc); -} - - -void mwAwareList_setClientData(struct mwAwareList *list, - gpointer data, GDestroyNotify clear) { - - g_return_if_fail(list != NULL); - mw_datum_set(&list->client_data, data, clear); -} - - -gpointer mwAwareList_getClientData(struct mwAwareList *list) { - g_return_val_if_fail(list != NULL, NULL); - return mw_datum_get(&list->client_data); -} - - -void mwAwareList_removeClientData(struct mwAwareList *list) { - g_return_if_fail(list != NULL); - mw_datum_clear(&list->client_data); -} - - -void mwServiceAware_setStatus(struct mwServiceAware *srvc, - struct mwAwareIdBlock *user, - struct mwUserStatus *stat) { - - struct mwAwareSnapshot idb; - - g_return_if_fail(srvc != NULL); - g_return_if_fail(user != NULL); - g_return_if_fail(stat != NULL); - - /* just reference the strings. then we don't need to free them */ - idb.id.type = user->type; - idb.id.user = user->user; - idb.id.community = user->community; - - idb.group = NULL; - idb.online = TRUE; - idb.alt_id = NULL; - - idb.status.status = stat->status; - idb.status.time = stat->time; - idb.status.desc = stat->desc; - - idb.name = NULL; - - status_recv(srvc, &idb); -} - - -const struct mwAwareAttribute * -mwServiceAware_getAttribute(struct mwServiceAware *srvc, - struct mwAwareIdBlock *user, - guint32 key) { - - struct aware_entry *aware; - - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(user != NULL, NULL); - g_return_val_if_fail(key != 0x00, NULL); - - aware = aware_find(srvc, user); - g_return_val_if_fail(aware != NULL, NULL); - - return g_hash_table_lookup(aware->attribs, GUINT_TO_POINTER(key)); -} - - -const char *mwServiceAware_getText(struct mwServiceAware *srvc, - struct mwAwareIdBlock *user) { - - struct aware_entry *aware; - - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(user != NULL, NULL); - - aware = aware_find(srvc, user); - if(! aware) return NULL; - - return aware->aware.status.desc; -} - - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_conf.c --- a/src/protocols/sametime/meanwhile/srvc_conf.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,865 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include - -#include -#include -#include -#include - -#include "mw_channel.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_conf.h" -#include "mw_util.h" - - -/* This thing needs a re-write. More than anything else, I need to - re-examine the conferencing service protocol from more modern - clients */ - - -#define PROTOCOL_TYPE 0x00000010 -#define PROTOCOL_VER 0x00000002 - - -/** @see mwMsgChannelSend::type - @see recv */ -enum msg_type { - msg_WELCOME = 0x0000, /**< welcome message */ - msg_INVITE = 0x0001, /**< outgoing invitation */ - msg_JOIN = 0x0002, /**< someone joined */ - msg_PART = 0x0003, /**< someone left */ - msg_MESSAGE = 0x0004, /**< conference message */ -}; - - -/** the conferencing service */ -struct mwServiceConference { - struct mwService service; - - /** call-back handler for this service */ - struct mwConferenceHandler *handler; - - /** collection of conferences in this service */ - GList *confs; -}; - - -/** a conference and its members */ -struct mwConference { - enum mwConferenceState state; /**< state of the conference */ - struct mwServiceConference *service; /**< owning service */ - struct mwChannel *channel; /**< conference's channel */ - - char *name; /**< server identifier for the conference */ - char *title; /**< topic for the conference */ - - struct mwLoginInfo owner; /**< person who created this conference */ - GHashTable *members; /**< mapping guint16:mwLoginInfo */ - struct mw_datum client_data; -}; - - -#define MEMBER_FIND(conf, id) \ - g_hash_table_lookup(conf->members, GUINT_TO_POINTER((guint) id)) - - -#define MEMBER_ADD(conf, id, member) \ - g_hash_table_insert(conf->members, GUINT_TO_POINTER((guint) id), member) - - -#define MEMBER_REM(conf, id) \ - g_hash_table_remove(conf->members, GUINT_TO_POINTER((guint) id)); - - -/** clear and free a login info block */ -static void login_free(struct mwLoginInfo *li) { - mwLoginInfo_clear(li); - g_free(li); -} - - -/** generates a random conference name built around a user name */ -static char *conf_generate_name(const char *user) { - guint a, b; - char *ret; - - user = user? user: ""; - - srand(clock() + rand()); - a = ((rand() & 0xff) << 8) | (rand() & 0xff); - b = time(NULL); - - ret = g_strdup_printf("%s(%08x,%04x)", user, b, a); - g_debug("generated random conference name: '%s'", ret); - return ret; -} - - - - - -static struct mwConference *conf_new(struct mwServiceConference *srvc) { - - struct mwConference *conf; - struct mwSession *session; - const char *user; - - conf = g_new0(struct mwConference, 1); - conf->state = mwConference_NEW; - conf->service = srvc; - conf->members = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) login_free); - - session = mwService_getSession(MW_SERVICE(srvc)); - user = mwSession_getProperty(session, mwSession_AUTH_USER_ID); - - srvc->confs = g_list_prepend(srvc->confs, conf); - - return conf; -} - - -/** clean and free a conference structure */ -static void conf_free(struct mwConference *conf) { - struct mwServiceConference *srvc; - - /* this shouldn't ever happen, but just to be sure */ - g_return_if_fail(conf != NULL); - - srvc = conf->service; - - if(conf->members) - g_hash_table_destroy(conf->members); - - g_list_remove_all(srvc->confs, conf); - - mw_datum_clear(&conf->client_data); - - g_free(conf->name); - g_free(conf->title); - g_free(conf); -} - - -static struct mwConference *conf_find(struct mwServiceConference *srvc, - struct mwChannel *chan) { - GList *l; - - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(chan != NULL, NULL); - - for(l = srvc->confs; l; l = l->next) { - struct mwConference *conf = l->data; - if(conf->channel == chan) return conf; - } - - return NULL; -} - - -static const char *conf_state_str(enum mwConferenceState state) { - switch(state) { - case mwConference_NEW: return "new"; - case mwConference_PENDING: return "pending"; - case mwConference_INVITED: return "invited"; - case mwConference_OPEN: return "open"; - case mwConference_CLOSING: return "closing"; - case mwConference_ERROR: return "error"; - - case mwConference_UNKNOWN: /* fall through */ - default: return "UNKNOWN"; - } -} - - -static void conf_state(struct mwConference *conf, - enum mwConferenceState state) { - g_return_if_fail(conf != NULL); - - if(conf->state == state) return; - - conf->state = state; - g_message("conference %s state: %s", - NSTR(conf->name), conf_state_str(state)); -} - - -static void recv_channelCreate(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - /* - this is how we really receive invitations - - create a conference and associate it with the channel - - obtain the invite data from the msg addtl info - - mark the conference as INVITED - - trigger the got_invite event - */ - - struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc; - struct mwConference *conf; - - struct mwGetBuffer *b; - - char *invite = NULL; - guint tmp; - - conf = conf_new(srvc_conf); - conf->channel = chan; - - b = mwGetBuffer_wrap(&msg->addtl); - - guint32_get(b, &tmp); - mwString_get(b, &conf->name); - mwString_get(b, &conf->title); - guint32_get(b, &tmp); - mwLoginInfo_get(b, &conf->owner); - guint32_get(b, &tmp); - mwString_get(b, &invite); - - if(mwGetBuffer_error(b)) { - g_warning("failure parsing addtl for conference invite"); - mwConference_destroy(conf, ERR_FAILURE, NULL); - - } else { - struct mwConferenceHandler *h = srvc_conf->handler; - conf_state(conf, mwConference_INVITED); - if(h->on_invited) - h->on_invited(conf, &conf->owner, invite); - } - - mwGetBuffer_free(b); - g_free(invite); -} - - -static void recv_channelAccept(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - ; -} - - -static void recv_channelDestroy(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - /* - find conference from channel - - trigger got_closed - - remove conference, dealloc - */ - - struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc; - struct mwConference *conf = conf_find(srvc_conf, chan); - struct mwConferenceHandler *h = srvc_conf->handler; - - /* if there's no such conference, then I guess there's nothing to worry - about. Except of course for the fact that we should never receive a - channel destroy for a conference that doesn't exist. */ - if(! conf) return; - - conf->channel = NULL; - - conf_state(conf, msg->reason? mwConference_ERROR: mwConference_CLOSING); - - if(h->conf_closed) - h->conf_closed(conf, msg->reason); - - mwConference_destroy(conf, ERR_SUCCESS, NULL); -} - - -static void WELCOME_recv(struct mwServiceConference *srvc, - struct mwConference *conf, - struct mwGetBuffer *b) { - - struct mwConferenceHandler *h; - guint16 tmp16; - guint32 tmp32; - guint32 count; - GList *l = NULL; - - /* re-read name and title */ - g_free(conf->name); - g_free(conf->title); - conf->name = NULL; - conf->title = NULL; - mwString_get(b, &conf->name); - mwString_get(b, &conf->title); - - /* some numbers we don't care about, then a count of members */ - guint16_get(b, &tmp16); - guint32_get(b, &tmp32); - guint32_get(b, &count); - - if(mwGetBuffer_error(b)) { - g_warning("error parsing welcome message for conference"); - mwConference_destroy(conf, ERR_FAILURE, NULL); - return; - } - - while(count--) { - guint16 member_id; - struct mwLoginInfo *member = g_new0(struct mwLoginInfo, 1); - - guint16_get(b, &member_id); - mwLoginInfo_get(b, member); - - if(mwGetBuffer_error(b)) { - login_free(member); - break; - } - - MEMBER_ADD(conf, member_id, member); - l = g_list_append(l, member); - } - - conf_state(conf, mwConference_OPEN); - - h = srvc->handler; - if(h->conf_opened) - h->conf_opened(conf, l); - - /* get rid of the GList, but not its contents */ - g_list_free(l); -} - - -static void JOIN_recv(struct mwServiceConference *srvc, - struct mwConference *conf, - struct mwGetBuffer *b) { - - struct mwConferenceHandler *h; - guint16 m_id; - struct mwLoginInfo *m; - - /* for some inane reason, conferences we create will send a join - message for ourselves before the welcome message. Since the - welcome message will list our ID among those in the channel, - we're going to just pretend that these join messages don't - exist */ - if(conf->state == mwConference_PENDING) - return; - - m = g_new0(struct mwLoginInfo, 1); - - guint16_get(b, &m_id); - mwLoginInfo_get(b, m); - - if(mwGetBuffer_error(b)) { - g_warning("failed parsing JOIN message in conference"); - login_free(m); - return; - } - - MEMBER_ADD(conf, m_id, m); - - h = srvc->handler; - if(h->on_peer_joined) - h->on_peer_joined(conf, m); -} - - -static void PART_recv(struct mwServiceConference *srvc, - struct mwConference *conf, - struct mwGetBuffer *b) { - - /* - parse who left - - look up their membership - - remove them from the members list - - trigger the event - */ - - struct mwConferenceHandler *h; - guint16 id = 0; - struct mwLoginInfo *m; - - guint16_get(b, &id); - - if(mwGetBuffer_error(b)) return; - - m = MEMBER_FIND(conf, id); - if(! m) return; - - h = srvc->handler; - if(h->on_peer_parted) - h->on_peer_parted(conf, m); - - MEMBER_REM(conf, id); -} - - -static void text_recv(struct mwServiceConference *srvc, - struct mwConference *conf, - struct mwLoginInfo *m, - struct mwGetBuffer *b) { - - /* this function acts a lot like receiving an IM Text message. The text - message contains only a string */ - - char *text = NULL; - struct mwConferenceHandler *h; - - mwString_get(b, &text); - - if(mwGetBuffer_error(b)) { - g_warning("failed to parse text message in conference"); - g_free(text); - return; - } - - h = srvc->handler; - if(text && h->on_text) { - h->on_text(conf, m, text); - } - - g_free(text); -} - - -static void data_recv(struct mwServiceConference *srvc, - struct mwConference *conf, - struct mwLoginInfo *m, - struct mwGetBuffer *b) { - - /* this function acts a lot like receiving an IM Data message. The - data message has a type, a subtype, and an opaque. We only - support typing notification though. */ - - /** @todo it's possible that some clients send text in a data - message, as we've seen rarely in the IM service. Have to add - support for that here */ - - guint32 type, subtype; - struct mwConferenceHandler *h; - - guint32_get(b, &type); - guint32_get(b, &subtype); - - if(mwGetBuffer_error(b)) return; - - /* don't know how to deal with any others yet */ - if(type != 0x01) { - g_message("unknown data message type (0x%08x, 0x%08x)", type, subtype); - return; - } - - h = srvc->handler; - if(h->on_typing) { - h->on_typing(conf, m, !subtype); - } -} - - -static void MESSAGE_recv(struct mwServiceConference *srvc, - struct mwConference *conf, - struct mwGetBuffer *b) { - - /* - look up who send the message by their id - - trigger the event - */ - - guint16 id; - guint32 type; - struct mwLoginInfo *m; - - /* an empty buffer isn't an error, just ignored */ - if(! mwGetBuffer_remaining(b)) return; - - guint16_get(b, &id); - guint32_get(b, &type); /* reuse type variable */ - guint32_get(b, &type); - - if(mwGetBuffer_error(b)) return; - - m = MEMBER_FIND(conf, id); - if(! m) { - g_warning("received message type 0x%04x from" - " unknown conference member %u", type, id); - return; - } - - switch(type) { - case 0x01: /* type is text */ - text_recv(srvc, conf, m, b); - break; - - case 0x02: /* type is data */ - data_recv(srvc, conf, m, b); - break; - - default: - g_warning("unknown message type 0x%4x received in conference", type); - } -} - - -static void recv(struct mwService *srvc, struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc; - struct mwConference *conf = conf_find(srvc_conf, chan); - struct mwGetBuffer *b; - - g_return_if_fail(conf != NULL); - - b = mwGetBuffer_wrap(data); - - switch(type) { - case msg_WELCOME: - WELCOME_recv(srvc_conf, conf, b); - break; - - case msg_JOIN: - JOIN_recv(srvc_conf, conf, b); - break; - - case msg_PART: - PART_recv(srvc_conf, conf, b); - break; - - case msg_MESSAGE: - MESSAGE_recv(srvc_conf, conf, b); - break; - - default: - ; /* hrm. should log this. TODO */ - } -} - - -static void clear(struct mwServiceConference *srvc) { - struct mwConferenceHandler *h; - - while(srvc->confs) - conf_free(srvc->confs->data); - - h = srvc->handler; - if(h && h->clear) - h->clear(srvc); - srvc->handler = NULL; -} - - -static const char *name(struct mwService *srvc) { - return "Basic Conferencing"; -} - - -static const char *desc(struct mwService *srvc) { - return "Multi-user plain-text conferencing"; -} - - -static void start(struct mwService *srvc) { - mwService_started(srvc); -} - - -static void stop(struct mwServiceConference *srvc) { - while(srvc->confs) - mwConference_destroy(srvc->confs->data, ERR_SUCCESS, NULL); - - mwService_stopped(MW_SERVICE(srvc)); -} - - -struct mwServiceConference * -mwServiceConference_new(struct mwSession *session, - struct mwConferenceHandler *handler) { - - struct mwServiceConference *srvc_conf; - struct mwService *srvc; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(handler != NULL, NULL); - - srvc_conf = g_new0(struct mwServiceConference, 1); - srvc = &srvc_conf->service; - - mwService_init(srvc, session, mwService_CONFERENCE); - srvc->start = start; - srvc->stop = (mwService_funcStop) stop; - srvc->recv_create = recv_channelCreate; - srvc->recv_accept = recv_channelAccept; - srvc->recv_destroy = recv_channelDestroy; - srvc->recv = recv; - srvc->clear = (mwService_funcClear) clear; - srvc->get_name = name; - srvc->get_desc = desc; - - srvc_conf->handler = handler; - - return srvc_conf; -} - - -struct mwConference *mwConference_new(struct mwServiceConference *srvc, - const char *title) { - struct mwConference *conf; - - g_return_val_if_fail(srvc != NULL, NULL); - - conf = conf_new(srvc); - conf->title = g_strdup(title); - - return conf; -} - - -struct mwServiceConference * -mwConference_getService(struct mwConference *conf) { - g_return_val_if_fail(conf != NULL, NULL); - return conf->service; -} - - -const char *mwConference_getName(struct mwConference *conf) { - g_return_val_if_fail(conf != NULL, NULL); - return conf->name; -} - - -const char *mwConference_getTitle(struct mwConference *conf) { - g_return_val_if_fail(conf != NULL, NULL); - return conf->title; -} - - -GList *mwConference_memebers(struct mwConference *conf) { - g_return_val_if_fail(conf != NULL, NULL); - g_return_val_if_fail(conf->members != NULL, NULL); - - return map_collect_values(conf->members); -} - - -int mwConference_open(struct mwConference *conf) { - struct mwSession *session; - struct mwChannel *chan; - struct mwPutBuffer *b; - int ret; - - g_return_val_if_fail(conf != NULL, -1); - g_return_val_if_fail(conf->service != NULL, -1); - g_return_val_if_fail(conf->state == mwConference_NEW, -1); - g_return_val_if_fail(conf->channel == NULL, -1); - - session = mwService_getSession(MW_SERVICE(conf->service)); - g_return_val_if_fail(session != NULL, -1); - - if(! conf->name) { - char *user = mwSession_getProperty(session, mwSession_AUTH_USER_ID); - conf->name = conf_generate_name(user? user: "meanwhile"); - } - - chan = mwChannel_newOutgoing(mwSession_getChannels(session)); - mwChannel_setService(chan, MW_SERVICE(conf->service)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - /* offer all known ciphers */ - mwChannel_populateSupportedCipherInstances(chan); - - b = mwPutBuffer_new(); - mwString_put(b, conf->name); - mwString_put(b, conf->title); - guint32_put(b, 0x00); - mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); - - ret = mwChannel_create(chan); - if(ret) { - conf_state(conf, mwConference_ERROR); - } else { - conf_state(conf, mwConference_PENDING); - conf->channel = chan; - } - - return ret; -} - - -int mwConference_destroy(struct mwConference *conf, - guint32 reason, const char *text) { - - struct mwServiceConference *srvc; - struct mwOpaque info = { 0, 0 }; - int ret = 0; - - g_return_val_if_fail(conf != NULL, -1); - - srvc = conf->service; - g_return_val_if_fail(srvc != NULL, -1); - - /* remove conference from the service */ - srvc->confs = g_list_remove_all(srvc->confs, conf); - - /* close the channel if applicable */ - if(conf->channel) { - if(text && *text) { - info.len = strlen(text); - info.data = (guchar *) text; - } - - ret = mwChannel_destroy(conf->channel, reason, &info); - } - - /* free the conference */ - conf_free(conf); - - return ret; -} - - -int mwConference_accept(struct mwConference *conf) { - /* - if conference is not INVITED, return -1 - - accept the conference channel - - send an empty JOIN message - */ - - struct mwChannel *chan; - int ret; - - g_return_val_if_fail(conf != NULL, -1); - g_return_val_if_fail(conf->state == mwConference_INVITED, -1); - - chan = conf->channel; - ret = mwChannel_accept(chan); - - if(! ret) - ret = mwChannel_sendEncrypted(chan, msg_JOIN, NULL, FALSE); - - return ret; -} - - -int mwConference_invite(struct mwConference *conf, - struct mwIdBlock *who, - const char *text) { - - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(conf != NULL, -1); - g_return_val_if_fail(conf->channel != NULL, -1); - g_return_val_if_fail(who != NULL, -1); - - b = mwPutBuffer_new(); - - mwIdBlock_put(b, who); - guint16_put(b, 0x00); - guint32_put(b, 0x00); - mwString_put(b, text); - mwString_put(b, who->user); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_sendEncrypted(conf->channel, msg_INVITE, &o, FALSE); - mwOpaque_clear(&o); - - return ret; -} - - -int mwConference_sendText(struct mwConference *conf, const char *text) { - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(conf != NULL, -1); - g_return_val_if_fail(conf->channel != NULL, -1); - - b = mwPutBuffer_new(); - - guint32_put(b, 0x01); - mwString_put(b, text); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE); - mwOpaque_clear(&o); - - return ret; -} - - -int mwConference_sendTyping(struct mwConference *conf, gboolean typing) { - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(conf != NULL, -1); - g_return_val_if_fail(conf->channel != NULL, -1); - g_return_val_if_fail(conf->state == mwConference_OPEN, -1); - - b = mwPutBuffer_new(); - - guint32_put(b, 0x02); - guint32_put(b, 0x01); - guint32_put(b, !typing); - mwOpaque_put(b, NULL); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE); - mwOpaque_clear(&o); - - return ret; -} - - -void mwConference_setClientData(struct mwConference *conference, - gpointer data, GDestroyNotify clear) { - - g_return_if_fail(conference != NULL); - mw_datum_set(&conference->client_data, data, clear); -} - - -gpointer mwConference_getClientData(struct mwConference *conference) { - g_return_val_if_fail(conference != NULL, NULL); - return mw_datum_get(&conference->client_data); -} - - -void mwConference_removeClientData(struct mwConference *conference) { - g_return_if_fail(conference != NULL); - mw_datum_clear(&conference->client_data); -} - - -struct mwConferenceHandler * -mwServiceConference_getHandler(struct mwServiceConference *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->handler; -} - - -GList *mwServiceConference_getConferences(struct mwServiceConference *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return g_list_copy(srvc->confs); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_dir.c --- a/src/protocols/sametime/meanwhile/srvc_dir.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,664 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -#include "mw_channel.h" -#include "mw_common.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_dir.h" -#include "mw_util.h" - - -#define PROTOCOL_TYPE 0x0000001c -#define PROTOCOL_VER 0x00000005 - - -enum dir_action { - action_list = 0x0000, /**< list address books */ - action_open = 0x0001, /**< open an addressbook as a directory */ - action_close = 0x0002, /**< close a directory */ - action_search = 0x0003, /**< search an open directory */ -}; - - -struct mwServiceDirectory { - struct mwService service; - - struct mwDirectoryHandler *handler; - - struct mwChannel *channel; - - guint32 counter; /**< counter of request IDs */ - GHashTable *requests; /**< map of request ID:directory */ - GHashTable *books; /**< book->name:mwAddressBook */ -}; - - -struct mwAddressBook { - struct mwServiceDirectory *service; - - guint32 id; /**< id or type or something */ - char *name; /**< name of address book */ - GHashTable *dirs; /**< dir->id:mwDirectory */ -}; - - -struct mwDirectory { - struct mwServiceDirectory *service; - struct mwAddressBook *book; - - enum mwDirectoryState state; - - guint32 id; /**< id of directory, assigned by server */ - guint32 search_id; /**< id of current search, from srvc->counter++ */ - - mwSearchHandler handler; - struct mw_datum client_data; -}; - - -#define next_request_id(srvc) ( ++((srvc)->counter) ) - - -static guint32 map_request(struct mwDirectory *dir) { - struct mwServiceDirectory *srvc = dir->service; - guint32 id = next_request_id(srvc); - - dir->search_id = id; - map_guint_insert(srvc->requests, id, dir); - - return id; -} - - -/** called when directory is removed from the service directory map */ -static void dir_free(struct mwDirectory *dir) { - map_guint_remove(dir->service->requests, dir->search_id); - g_free(dir); -} - - -/** remove the directory from the service list and its owning address - book, then frees the directory */ -static void dir_remove(struct mwDirectory *dir) { - struct mwAddressBook *book = dir->book; - map_guint_remove(book->dirs, dir->id); -} - - -__attribute__((used)) -static struct mwDirectory *dir_new(struct mwAddressBook *book, guint32 id) { - struct mwDirectory *dir = g_new0(struct mwDirectory, 1); - dir->service = book->service; - dir->book = book; - dir->id = id; - map_guint_insert(book->dirs, id, dir); - return dir; -} - - -/** called when book is removed from the service book map. Removed all - directories as well */ -static void book_free(struct mwAddressBook *book) { - g_hash_table_destroy(book->dirs); - g_free(book->name); -} - - -__attribute__((used)) -static void book_remove(struct mwAddressBook *book) { - struct mwServiceDirectory *srvc = book->service; - g_hash_table_remove(srvc->books, book->name); -} - - -static struct mwAddressBook *book_new(struct mwServiceDirectory *srvc, - const char *name, guint32 id) { - struct mwAddressBook *book = g_new0(struct mwAddressBook, 1); - book->service = srvc; - book->id = id; - book->name = g_strdup(name); - book->dirs = map_guint_new_full((GDestroyNotify) dir_free); - g_hash_table_insert(srvc->books, book->name, book); - return book; -} - - -static const char *getName(struct mwService *srvc) { - return "Address Book and Directory"; -} - - -static const char *getDesc(struct mwService *srvc) { - return "Address book directory service for user and group lookups"; -} - - -static struct mwChannel *make_channel(struct mwServiceDirectory *srvc) { - struct mwSession *session; - struct mwChannelSet *cs; - struct mwChannel *chan; - - session = mwService_getSession(MW_SERVICE(srvc)); - cs = mwSession_getChannels(session); - chan = mwChannel_newOutgoing(cs); - - mwChannel_setService(chan, MW_SERVICE(srvc)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - return mwChannel_create(chan)? NULL: chan; -} - - -static void start(struct mwServiceDirectory *srvc) { - struct mwChannel *chan; - - chan = make_channel(srvc); - if(chan) { - srvc->channel = chan; - } else { - mwService_stopped(MW_SERVICE(srvc)); - return; - } -} - - -static void stop(struct mwServiceDirectory *srvc) { - /* XXX */ - - if(srvc->channel) { - mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL); - srvc->channel = NULL; - } -} - - -static void clear(struct mwServiceDirectory *srvc) { - struct mwDirectoryHandler *handler; - - if(srvc->books) { - g_hash_table_destroy(srvc->books); - srvc->books = NULL; - } - - /* clear the handler */ - handler = srvc->handler; - if(handler && handler->clear) - handler->clear(srvc); - srvc->handler = NULL; -} - - -static void recv_create(struct mwServiceDirectory *srvc, - struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - /* no way man, we call the shots around here */ - mwChannel_destroy(chan, ERR_FAILURE, NULL); -} - - -static void recv_accept(struct mwServiceDirectory *srvc, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - g_return_if_fail(srvc->channel != NULL); - g_return_if_fail(srvc->channel == chan); - - if(MW_SERVICE_IS_STARTING(srvc)) { - mwService_started(MW_SERVICE(srvc)); - - } else { - mwChannel_destroy(chan, ERR_FAILURE, NULL); - } -} - - -static void recv_destroy(struct mwServiceDirectory *srvc, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - srvc->channel = NULL; - mwService_stop(MW_SERVICE(srvc)); - /** @todo session sense service */ -} - - -static void recv_list(struct mwServiceDirectory *srvc, - struct mwOpaque *data) { - - struct mwGetBuffer *b; - guint32 request, code, count; - gboolean foo_1; - guint16 foo_2; - - b = mwGetBuffer_wrap(data); - - guint32_get(b, &request); - guint32_get(b, &code); - guint32_get(b, &count); - - gboolean_get(b, &foo_1); - guint16_get(b, &foo_2); - - if(foo_1 || foo_2) { - mw_debug_mailme(data, "received strange address book list"); - mwGetBuffer_free(b); - return; - } - - while(!mwGetBuffer_error(b) && count--) { - guint32 id; - char *name = NULL; - - guint32_get(b, &id); - mwString_get(b, &name); - - book_new(srvc, name, id); - g_free(name); - } -} - - -static void recv_open(struct mwServiceDirectory *srvc, - struct mwOpaque *data) { - - /* look up the directory associated with this request id, - mark it as open, and trigger the event */ -} - - -static void recv_search(struct mwServiceDirectory *srvc, - struct mwOpaque *data) { - - /* look up the directory associated with this request id, - trigger the event */ -} - - -static void recv(struct mwServiceDirectory *srvc, - struct mwChannel *chan, - guint16 msg_type, struct mwOpaque *data) { - - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc->channel); - g_return_if_fail(data != NULL); - - switch(msg_type) { - case action_list: - recv_list(srvc, data); - break; - - case action_open: - recv_open(srvc, data); - break; - - case action_close: - ; /* I don't think we should receive these */ - break; - - case action_search: - recv_search(srvc, data); - break; - - default: - mw_debug_mailme(data, "msg type 0x%04x in directory service", msg_type); - } -} - - -struct mwServiceDirectory * -mwServiceDirectory_new(struct mwSession *session, - struct mwDirectoryHandler *handler) { - - struct mwServiceDirectory *srvc; - struct mwService *service; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(handler != NULL, NULL); - - srvc = g_new0(struct mwServiceDirectory, 1); - service = MW_SERVICE(srvc); - - mwService_init(service, session, SERVICE_DIRECTORY); - service->get_name = getName; - service->get_desc = getDesc; - service->start = (mwService_funcStart) start; - service->stop = (mwService_funcStop) stop; - service->clear = (mwService_funcClear) clear; - service->recv_create = (mwService_funcRecvCreate) recv_create; - service->recv_accept = (mwService_funcRecvAccept) recv_accept; - service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy; - service->recv = (mwService_funcRecv) recv; - - srvc->handler = handler; - srvc->requests = map_guint_new(); - srvc->books = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, (GDestroyNotify) book_free); - return srvc; -} - - -struct mwDirectoryHandler * -mwServiceDirectory_getHandler(struct mwServiceDirectory *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->handler; -} - - -int mwServiceDirectory_refreshAddressBooks(struct mwServiceDirectory *srvc) { - struct mwChannel *chan; - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(srvc != NULL, -1); - - chan = srvc->channel; - g_return_val_if_fail(chan != NULL, -1); - - b = mwPutBuffer_new(); - guint32_put(b, next_request_id(srvc)); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, action_list, &o); - mwOpaque_clear(&o); - - return ret; -} - - -GList *mwServiceDirectory_getAddressBooks(struct mwServiceDirectory *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(srvc->books != NULL, NULL); - - return map_collect_values(srvc->books); -} - - -GList *mwServiceDirectory_getDirectories(struct mwServiceDirectory *srvc) { - GList *bl, *ret = NULL; - - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(srvc->books != NULL, NULL); - - bl = map_collect_values(srvc->books); - for( ; bl; bl = g_list_delete_link(bl, bl)) { - struct mwAddressBook *book = bl->data; - ret = g_list_concat(ret, map_collect_values(book->dirs)); - } - - return ret; -} - - -GList *mwAddressBook_getDirectories(struct mwAddressBook *book) { - g_return_val_if_fail(book != NULL, NULL); - g_return_val_if_fail(book->dirs != NULL, NULL); - - return map_collect_values(book->dirs); -} - - -const char *mwAddressBook_getName(struct mwAddressBook *book) { - g_return_val_if_fail(book != NULL, NULL); - return book->name; -} - - -struct mwDirectory *mwDirectory_new(struct mwAddressBook *book) { - struct mwDirectory *dir; - - g_return_val_if_fail(book != NULL, NULL); - g_return_val_if_fail(book->service != NULL, NULL); - - dir = g_new0(struct mwDirectory, 1); - dir->service = book->service; - dir->book = book; - dir->state = mwDirectory_NEW; - - return dir; -} - - -enum mwDirectoryState mwDirectory_getState(struct mwDirectory *dir) { - g_return_val_if_fail(dir != NULL, mwDirectory_UNKNOWN); - return dir->state; -} - - -void mwDirectory_setClientData(struct mwDirectory *dir, - gpointer data, GDestroyNotify clear) { - - g_return_if_fail(dir != NULL); - mw_datum_set(&dir->client_data, data, clear); -} - - -gpointer mwDirectory_getClientData(struct mwDirectory *dir) { - g_return_val_if_fail(dir != NULL, NULL); - return mw_datum_get(&dir->client_data); -} - - -void mwDirectory_removeClientData(struct mwDirectory *dir) { - g_return_if_fail(dir != NULL); - mw_datum_clear(&dir->client_data); -} - - -struct mwServiceDirectory *mwDirectory_getService(struct mwDirectory *dir) { - g_return_val_if_fail(dir != NULL, NULL); - g_return_val_if_fail(dir->book != NULL, NULL); - return dir->book->service; -} - - -struct mwAddressBook *mwDirectory_getAddressBook(struct mwDirectory *dir) { - g_return_val_if_fail(dir != NULL, NULL); - return dir->book; -} - - -static int dir_open(struct mwDirectory *dir) { - struct mwServiceDirectory *srvc; - struct mwChannel *chan; - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(dir != NULL, -1); - - srvc = dir->service; - g_return_val_if_fail(srvc != NULL, -1); - - chan = srvc->channel; - g_return_val_if_fail(chan != NULL, -1); - - b = mwPutBuffer_new(); - guint32_put(b, map_request(dir)); - - /* unsure about these three bytes */ - gboolean_put(b, FALSE); - guint16_put(b, 0x0000); - - guint32_put(b, dir->book->id); - mwString_put(b, dir->book->name); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, action_open, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwDirectory_open(struct mwDirectory *dir, mwSearchHandler cb) { - g_return_val_if_fail(dir != NULL, -1); - g_return_val_if_fail(cb != NULL, -1); - g_return_val_if_fail(MW_DIRECTORY_IS_NEW(dir), -1); - - dir->state = mwDirectory_PENDING; - dir->handler = cb; - - return dir_open(dir); -} - - -int mwDirectory_next(struct mwDirectory *dir) { - struct mwServiceDirectory *srvc; - struct mwChannel *chan; - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(dir != NULL, -1); - g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1); - - srvc = dir->service; - g_return_val_if_fail(srvc != NULL, -1); - - chan = srvc->channel; - g_return_val_if_fail(chan != NULL, -1); - - b = mwPutBuffer_new(); - guint32_put(b, map_request(dir)); - guint32_put(b, dir->id); - guint16_put(b, 0xffff); /* some magic? */ - guint32_put(b, 0x00000000); /* next results */ - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, action_search, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwDirectory_previous(struct mwDirectory *dir) { - struct mwServiceDirectory *srvc; - struct mwChannel *chan; - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(dir != NULL, -1); - g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1); - - srvc = dir->service; - g_return_val_if_fail(srvc != NULL, -1); - - chan = srvc->channel; - g_return_val_if_fail(chan != NULL, -1); - - b = mwPutBuffer_new(); - guint32_put(b, map_request(dir)); - guint32_put(b, dir->id); - guint16_put(b, 0x0061); /* some magic? */ - guint32_put(b, 0x00000001); /* prev results */ - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, action_search, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwDirectory_search(struct mwDirectory *dir, const char *query) { - struct mwServiceDirectory *srvc; - struct mwChannel *chan; - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(dir != NULL, -1); - g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1); - g_return_val_if_fail(query != NULL, -1); - g_return_val_if_fail(*query != '\0', -1); - - srvc = dir->service; - g_return_val_if_fail(srvc != NULL, -1); - - chan = srvc->channel; - g_return_val_if_fail(chan != NULL, -1); - - b = mwPutBuffer_new(); - guint32_put(b, map_request(dir)); - guint32_put(b, dir->id); - guint16_put(b, 0x0061); /* some magic? */ - guint32_put(b, 0x00000008); /* seek results */ - mwString_put(b, query); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, action_search, &o); - mwOpaque_clear(&o); - - return ret; -} - - -static int dir_close(struct mwDirectory *dir) { - struct mwServiceDirectory *srvc; - struct mwChannel *chan; - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - g_return_val_if_fail(dir != NULL, -1); - - srvc = dir->service; - g_return_val_if_fail(srvc != NULL, -1); - - chan = srvc->channel; - g_return_val_if_fail(chan != NULL, -1); - - b = mwPutBuffer_new(); - guint32_put(b, next_request_id(dir->service)); - guint32_put(b, dir->id); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, action_close, &o); - mwOpaque_clear(&o); - - return ret; -} - - -int mwDirectory_destroy(struct mwDirectory *dir) { - int ret = 0; - - g_return_val_if_fail(dir != NULL, -1); - - if(MW_DIRECTORY_IS_OPEN(dir) || MW_DIRECTORY_IS_PENDING(dir)) { - ret = dir_close(dir); - } - dir_remove(dir); - - return ret; -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_ft.c --- a/src/protocols/sametime/meanwhile/srvc_ft.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,654 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -#include - -#include "mw_channel.h" -#include "mw_common.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_ft.h" -#include "mw_util.h" - - -#define PROTOCOL_TYPE 0x00000000 -#define PROTOCOL_VER 0x00000001 - - -/** send-on-channel type: FT transfer data */ -#define msg_TRANSFER 0x0001 - - -/** ack received transfer data */ -#define msg_RECEIVED 0x0002 - - -struct mwServiceFileTransfer { - struct mwService service; - - struct mwFileTransferHandler *handler; - GList *transfers; -}; - - -struct mwFileTransfer { - struct mwServiceFileTransfer *service; - - struct mwChannel *channel; - struct mwIdBlock who; - - enum mwFileTransferState state; - - char *filename; - char *message; - - guint32 size; - guint32 remaining; - - struct mw_datum client_data; -}; - - -/** momentarily places a mwLoginInfo into a mwIdBlock */ -static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) { - to->user = from->user_id; - to->community = from->community; -} - - -static const char *ft_state_str(enum mwFileTransferState state) { - switch(state) { - case mwFileTransfer_NEW: - return "new"; - - case mwFileTransfer_PENDING: - return "pending"; - - case mwFileTransfer_OPEN: - return "open"; - - case mwFileTransfer_CANCEL_LOCAL: - return "cancelled locally"; - - case mwFileTransfer_CANCEL_REMOTE: - return "cancelled remotely"; - - case mwFileTransfer_DONE: - return "done"; - - case mwFileTransfer_ERROR: - return "error"; - - case mwFileTransfer_UNKNOWN: - default: - return "UNKNOWN"; - } -} - - -static void ft_state(struct mwFileTransfer *ft, - enum mwFileTransferState state) { - - g_return_if_fail(ft != NULL); - - if(ft->state == state) return; - - g_info("setting ft (%s, %s) state: %s", - NSTR(ft->who.user), NSTR(ft->who.community), - ft_state_str(state)); - - ft->state = state; -} - - -static void recv_channelCreate(struct mwServiceFileTransfer *srvc, - struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - struct mwFileTransferHandler *handler; - struct mwGetBuffer *b; - - char *fnm, *txt; - guint32 size, junk; - gboolean b_err; - - g_return_if_fail(srvc->handler != NULL); - handler = srvc->handler; - - b = mwGetBuffer_wrap(&msg->addtl); - - guint32_get(b, &junk); /* unknown */ - mwString_get(b, &fnm); /* offered filename */ - mwString_get(b, &txt); /* offering message */ - guint32_get(b, &size); /* size of offered file */ - guint32_get(b, &junk); /* unknown */ - /* and we just skip an unknown guint16 at the end */ - - b_err = mwGetBuffer_error(b); - mwGetBuffer_free(b); - - if(b_err) { - g_warning("bad/malformed addtl in File Transfer service"); - mwChannel_destroy(chan, ERR_FAILURE, NULL); - - } else { - struct mwIdBlock idb; - struct mwFileTransfer *ft; - - login_into_id(&idb, mwChannel_getUser(chan)); - ft = mwFileTransfer_new(srvc, &idb, txt, fnm, size); - ft->channel = chan; - ft_state(ft, mwFileTransfer_PENDING); - - mwChannel_setServiceData(chan, ft, NULL); - - if(handler->ft_offered) - handler->ft_offered(ft); - } - - g_free(fnm); - g_free(txt); -} - - -static void recv_channelAccept(struct mwServiceFileTransfer *srvc, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - struct mwFileTransferHandler *handler; - struct mwFileTransfer *ft; - - g_return_if_fail(srvc->handler != NULL); - handler = srvc->handler; - - ft = mwChannel_getServiceData(chan); - g_return_if_fail(ft != NULL); - - ft_state(ft, mwFileTransfer_OPEN); - - if(handler->ft_opened) - handler->ft_opened(ft); -} - - -static void recv_channelDestroy(struct mwServiceFileTransfer *srvc, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - struct mwFileTransferHandler *handler; - struct mwFileTransfer *ft; - guint32 code; - - code = msg->reason; - - g_return_if_fail(srvc->handler != NULL); - handler = srvc->handler; - - ft = mwChannel_getServiceData(chan); - g_return_if_fail(ft != NULL); - - ft->channel = NULL; - - if(! mwFileTransfer_isDone(ft)) - ft_state(ft, mwFileTransfer_CANCEL_REMOTE); - - mwFileTransfer_close(ft, code); -} - - -static void recv_TRANSFER(struct mwFileTransfer *ft, - struct mwOpaque *data) { - - struct mwServiceFileTransfer *srvc; - struct mwFileTransferHandler *handler; - - srvc = ft->service; - handler = srvc->handler; - - g_return_if_fail(mwFileTransfer_isOpen(ft)); - - if(data->len > ft->remaining) { - /* @todo handle error */ - - } else { - ft->remaining -= data->len; - - if(! ft->remaining) - ft_state(ft, mwFileTransfer_DONE); - - if(handler->ft_recv) - handler->ft_recv(ft, data); - } -} - - -static void recv_RECEIVED(struct mwFileTransfer *ft, - struct mwOpaque *data) { - - struct mwServiceFileTransfer *srvc; - struct mwFileTransferHandler *handler; - - srvc = ft->service; - handler = srvc->handler; - - if(! ft->remaining) - ft_state(ft, mwFileTransfer_DONE); - - if(handler->ft_ack) - handler->ft_ack(ft); - - if(! ft->remaining) - mwFileTransfer_close(ft, mwFileTransfer_SUCCESS); -} - - -static void recv(struct mwService *srvc, struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - struct mwFileTransfer *ft; - - ft = mwChannel_getServiceData(chan); - g_return_if_fail(ft != NULL); - - switch(type) { - case msg_TRANSFER: - recv_TRANSFER(ft, data); - break; - - case msg_RECEIVED: - recv_RECEIVED(ft, data); - break; - - default: - mw_mailme_opaque(data, "unknown message in ft service: 0x%04x", type); - } -} - - -static void clear(struct mwServiceFileTransfer *srvc) { - struct mwFileTransferHandler *h; - - h = srvc->handler; - if(h && h->clear) - h->clear(srvc); - srvc->handler = NULL; -} - - -static const char *name(struct mwService *srvc) { - return "File Transfer"; -} - - -static const char *desc(struct mwService *srvc) { - return "Provides file transfer capabilities through the community server"; -} - - -static void start(struct mwService *srvc) { - mwService_started(srvc); -} - - -static void stop(struct mwServiceFileTransfer *srvc) { - while(srvc->transfers) { - mwFileTransfer_free(srvc->transfers->data); - } - - mwService_stopped(MW_SERVICE(srvc)); -} - - -struct mwServiceFileTransfer * -mwServiceFileTransfer_new(struct mwSession *session, - struct mwFileTransferHandler *handler) { - - struct mwServiceFileTransfer *srvc_ft; - struct mwService *srvc; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(handler != NULL, NULL); - - srvc_ft = g_new0(struct mwServiceFileTransfer, 1); - srvc = MW_SERVICE(srvc_ft); - - mwService_init(srvc, session, mwService_FILE_TRANSFER); - srvc->recv_create = (mwService_funcRecvCreate) recv_channelCreate; - srvc->recv_accept = (mwService_funcRecvAccept) recv_channelAccept; - srvc->recv_destroy = (mwService_funcRecvDestroy) recv_channelDestroy; - srvc->recv = recv; - srvc->clear = (mwService_funcClear) clear; - srvc->get_name = name; - srvc->get_desc = desc; - srvc->start = start; - srvc->stop = (mwService_funcStop) stop; - - srvc_ft->handler = handler; - - return srvc_ft; -} - - -struct mwFileTransferHandler * -mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->handler; -} - - -const GList * -mwServiceFileTransfer_getTransfers(struct mwServiceFileTransfer *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->transfers; -} - - -struct mwFileTransfer * -mwFileTransfer_new(struct mwServiceFileTransfer *srvc, - const struct mwIdBlock *who, const char *msg, - const char *filename, guint32 filesize) { - - struct mwFileTransfer *ft; - - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(who != NULL, NULL); - - ft = g_new0(struct mwFileTransfer, 1); - ft->service = srvc; - mwIdBlock_clone(&ft->who, who); - ft->filename = g_strdup(filename); - ft->message = g_strdup(msg); - ft->size = ft->remaining = filesize; - - ft_state(ft, mwFileTransfer_NEW); - - /* stick a reference in the service */ - srvc->transfers = g_list_prepend(srvc->transfers, ft); - - return ft; -} - - -struct mwServiceFileTransfer * -mwFileTransfer_getService(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, NULL); - return ft->service; -} - - -enum mwFileTransferState -mwFileTransfer_getState(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, mwFileTransfer_UNKNOWN); - return ft->state; -} - - -const struct mwIdBlock * -mwFileTransfer_getUser(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, NULL); - return &ft->who; -} - - -const char * -mwFileTransfer_getMessage(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, NULL); - return ft->message; -} - - -const char * -mwFileTransfer_getFileName(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, NULL); - return ft->filename; -} - - -guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, 0); - return ft->size; -} - - -guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, 0); - return ft->remaining; -} - - -int mwFileTransfer_accept(struct mwFileTransfer *ft) { - struct mwServiceFileTransfer *srvc; - struct mwFileTransferHandler *handler; - int ret; - - g_return_val_if_fail(ft != NULL, -1); - g_return_val_if_fail(ft->channel != NULL, -1); - g_return_val_if_fail(mwFileTransfer_isPending(ft), -1); - g_return_val_if_fail(mwChannel_isIncoming(ft->channel), -1); - g_return_val_if_fail(mwChannel_isState(ft->channel, mwChannel_WAIT), -1); - - g_return_val_if_fail(ft->service != NULL, -1); - srvc = ft->service; - - g_return_val_if_fail(srvc->handler != NULL, -1); - handler = srvc->handler; - - ret = mwChannel_accept(ft->channel); - - if(ret) { - mwFileTransfer_close(ft, ERR_FAILURE); - - } else { - ft_state(ft, mwFileTransfer_OPEN); - if(handler->ft_opened) - handler->ft_opened(ft); - } - - return ret; -} - - -static void ft_create_chan(struct mwFileTransfer *ft) { - struct mwSession *s; - struct mwChannelSet *cs; - struct mwChannel *chan; - struct mwLoginInfo *login; - struct mwPutBuffer *b; - - /* we only should be calling this if there isn't a channel already - associated with the conversation */ - g_return_if_fail(ft != NULL); - g_return_if_fail(mwFileTransfer_isNew(ft)); - g_return_if_fail(ft->channel == NULL); - - s = mwService_getSession(MW_SERVICE(ft->service)); - cs = mwSession_getChannels(s); - - chan = mwChannel_newOutgoing(cs); - mwChannel_setService(chan, MW_SERVICE(ft->service)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - /* offer all known ciphers */ - mwChannel_populateSupportedCipherInstances(chan); - - /* set the target */ - login = mwChannel_getUser(chan); - login->user_id = g_strdup(ft->who.user); - login->community = g_strdup(ft->who.community); - - /* compose the addtl create */ - b = mwPutBuffer_new(); - guint32_put(b, 0x00); - mwString_put(b, ft->filename); - mwString_put(b, ft->message); - guint32_put(b, ft->size); - guint32_put(b, 0x00); - guint16_put(b, 0x00); - - mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); - - ft->channel = mwChannel_create(chan)? NULL: chan; - if(ft->channel) { - mwChannel_setServiceData(ft->channel, ft, NULL); - } -} - - -int mwFileTransfer_offer(struct mwFileTransfer *ft) { - struct mwServiceFileTransfer *srvc; - struct mwFileTransferHandler *handler; - - g_return_val_if_fail(ft != NULL, -1); - g_return_val_if_fail(ft->channel == NULL, -1); - g_return_val_if_fail(mwFileTransfer_isNew(ft), -1); - - g_return_val_if_fail(ft->service != NULL, -1); - srvc = ft->service; - - g_return_val_if_fail(srvc->handler != NULL, -1); - handler = srvc->handler; - - ft_create_chan(ft); - if(ft->channel) { - ft_state(ft, mwFileTransfer_PENDING); - } else { - ft_state(ft, mwFileTransfer_ERROR); - mwFileTransfer_close(ft, ERR_FAILURE); - } - - return 0; -} - - -int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code) { - struct mwServiceFileTransfer *srvc; - struct mwFileTransferHandler *handler; - int ret = 0; - - g_return_val_if_fail(ft != NULL, -1); - - if(mwFileTransfer_isOpen(ft)) - ft_state(ft, mwFileTransfer_CANCEL_LOCAL); - - if(ft->channel) { - ret = mwChannel_destroy(ft->channel, code, NULL); - ft->channel = NULL; - } - - srvc = ft->service; - g_return_val_if_fail(srvc != NULL, ret); - - handler = srvc->handler; - g_return_val_if_fail(handler != NULL, ret); - - if(handler->ft_closed) - handler->ft_closed(ft, code); - - return ret; -} - - -void mwFileTransfer_free(struct mwFileTransfer *ft) { - struct mwServiceFileTransfer *srvc; - - if(! ft) return; - - srvc = ft->service; - if(srvc) - srvc->transfers = g_list_remove(srvc->transfers, ft); - - if(ft->channel) { - mwChannel_destroy(ft->channel, mwFileTransfer_SUCCESS, NULL); - ft->channel = NULL; - } - - mwFileTransfer_removeClientData(ft); - - mwIdBlock_clear(&ft->who); - g_free(ft->filename); - g_free(ft->message); - g_free(ft); -} - - -int mwFileTransfer_send(struct mwFileTransfer *ft, - struct mwOpaque *data) { - - struct mwChannel *chan; - int ret; - - g_return_val_if_fail(ft != NULL, -1); - g_return_val_if_fail(mwFileTransfer_isOpen(ft), -1); - g_return_val_if_fail(ft->channel != NULL, -1); - chan = ft->channel; - - g_return_val_if_fail(mwChannel_isOutgoing(chan), -1); - - if(data->len > ft->remaining) { - /* @todo handle error */ - return -1; - } - - ret = mwChannel_send(chan, msg_TRANSFER, data); - if(! ret) ft->remaining -= data->len; - - /* we're not done until we receive an ACK for the last piece of - outgoing data */ - - return ret; -} - - -int mwFileTransfer_ack(struct mwFileTransfer *ft) { - struct mwChannel *chan; - - g_return_val_if_fail(ft != NULL, -1); - - chan = ft->channel; - g_return_val_if_fail(chan != NULL, -1); - g_return_val_if_fail(mwChannel_isIncoming(chan), -1); - - return mwChannel_sendEncrypted(chan, msg_RECEIVED, NULL, FALSE); -} - - -void mwFileTransfer_setClientData(struct mwFileTransfer *ft, - gpointer data, GDestroyNotify clean) { - g_return_if_fail(ft != NULL); - mw_datum_set(&ft->client_data, data, clean); -} - - -gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft) { - g_return_val_if_fail(ft != NULL, NULL); - return mw_datum_get(&ft->client_data); -} - - -void mwFileTransfer_removeClientData(struct mwFileTransfer *ft) { - g_return_if_fail(ft != NULL); - mw_datum_clear(&ft->client_data); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_im.c --- a/src/protocols/sametime/meanwhile/srvc_im.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1055 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include - -#include "mw_channel.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_im.h" -#include "mw_util.h" - - -#define PROTOCOL_TYPE 0x00001000 -#define PROTOCOL_VER 0x00000003 - - -/* data for the addtl blocks of channel creation */ -#define mwImAddtlA_NORMAL 0x00000001 - -#define mwImAddtlB_NORMAL 0x00000001 /**< standard */ -#define mwImAddtlB_PRECONF 0x00000019 /**< pre-conference chat */ -#define mwImAddtlB_NOTESBUDDY 0x00033453 /**< notesbuddy */ - -#define mwImAddtlC_NORMAL 0x00000002 - - -/* send-on-channel message type */ -#define msg_MESSAGE 0x0064 /**< IM message */ - - -#define BREAKUP 2048 - - -/* which type of im? */ -enum mwImType { - mwIm_TEXT = 0x00000001, /**< text message */ - mwIm_DATA = 0x00000002, /**< status message (usually) */ -}; - - -/* which type of data im? */ -enum mwImDataType { - mwImData_TYPING = 0x00000001, /**< common use typing indicator */ - mwImData_SUBJECT = 0x00000003, /**< notesbuddy IM topic */ - mwImData_HTML = 0x00000004, /**< notesbuddy HTML message */ - mwImData_MIME = 0x00000005, /**< notesbuddy MIME message, w/image */ - mwImData_TIMESTAMP = 0x00000006, /**< notesbuddy timestamp */ - - mwImData_INVITE = 0x0000000a, /**< Places invitation */ - - mwImData_MULTI_START = 0x00001388, - mwImData_MULTI_STOP = 0x00001389, -}; - - -/** @todo might be appropriate to make a couple of hashtables to - reference conversations by channel and target */ -struct mwServiceIm { - struct mwService service; - - enum mwImClientType features; - - struct mwImHandler *handler; - GList *convs; /**< list of struct im_convo */ -}; - - -struct mwConversation { - struct mwServiceIm *service; /**< owning service */ - struct mwChannel *channel; /**< channel */ - struct mwIdBlock target; /**< conversation target */ - - gboolean ext_id; /**< special treatment, external ID */ - - /** state of the conversation, based loosely on the state of its - underlying channel */ - enum mwConversationState state; - - enum mwImClientType features; - - GString *multi; /**< buffer for multi-chunk message */ - enum mwImSendType multi_type; /**< type of incoming multi-chunk message */ - - struct mw_datum client_data; -}; - - -/** momentarily places a mwLoginInfo into a mwIdBlock */ -static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) { - to->user = from->user_id; - to->community = from->community; -} - - -static struct mwConversation *convo_find_by_user(struct mwServiceIm *srvc, - struct mwIdBlock *to) { - GList *l; - - for(l = srvc->convs; l; l = l->next) { - struct mwConversation *c = l->data; - if(mwIdBlock_equal(&c->target, to)) - return c; - } - - return NULL; -} - - -static const char *conv_state_str(enum mwConversationState state) { - switch(state) { - case mwConversation_CLOSED: - return "closed"; - - case mwConversation_OPEN: - return "open"; - - case mwConversation_PENDING: - return "pending"; - - case mwConversation_UNKNOWN: - default: - return "UNKNOWN"; - } -} - - -static void convo_set_state(struct mwConversation *conv, - enum mwConversationState state) { - - g_return_if_fail(conv != NULL); - - if(conv->state != state) { - g_info("setting conversation (%s, %s) state: %s", - NSTR(conv->target.user), NSTR(conv->target.community), - conv_state_str(state)); - conv->state = state; - } -} - - -struct mwConversation *mwServiceIm_findConversation(struct mwServiceIm *srvc, - struct mwIdBlock *to) { - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(to != NULL, NULL); - - return convo_find_by_user(srvc, to); -} - - -struct mwConversation *mwServiceIm_getConversation(struct mwServiceIm *srvc, - struct mwIdBlock *to) { - struct mwConversation *c; - - g_return_val_if_fail(srvc != NULL, NULL); - g_return_val_if_fail(to != NULL, NULL); - - c = convo_find_by_user(srvc, to); - if(! c) { - c = g_new0(struct mwConversation, 1); - c->service = srvc; - mwIdBlock_clone(&c->target, to); - c->state = mwConversation_CLOSED; - c->features = srvc->features; - - /* mark external users */ - /* c->ext_id = g_str_has_prefix(to->user, "@E "); */ - - srvc->convs = g_list_prepend(srvc->convs, c); - } - - return c; -} - - -static void convo_create_chan(struct mwConversation *c) { - struct mwSession *s; - struct mwChannelSet *cs; - struct mwChannel *chan; - struct mwLoginInfo *login; - struct mwPutBuffer *b; - - /* we only should be calling this if there isn't a channel already - associated with the conversation */ - g_return_if_fail(c != NULL); - g_return_if_fail(mwConversation_isPending(c)); - g_return_if_fail(c->channel == NULL); - - s = mwService_getSession(MW_SERVICE(c->service)); - cs = mwSession_getChannels(s); - - chan = mwChannel_newOutgoing(cs); - mwChannel_setService(chan, MW_SERVICE(c->service)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - /* offer all known ciphers */ - mwChannel_populateSupportedCipherInstances(chan); - - /* set the target */ - login = mwChannel_getUser(chan); - login->user_id = g_strdup(c->target.user); - login->community = g_strdup(c->target.community); - - /* compose the addtl create, with optional FANCY HTML! */ - b = mwPutBuffer_new(); - guint32_put(b, mwImAddtlA_NORMAL); - guint32_put(b, c->features); - mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); - - c->channel = mwChannel_create(chan)? NULL: chan; - if(c->channel) { - mwChannel_setServiceData(c->channel, c, NULL); - } -} - - -void mwConversation_open(struct mwConversation *conv) { - g_return_if_fail(conv != NULL); - g_return_if_fail(mwConversation_isClosed(conv)); - - convo_set_state(conv, mwConversation_PENDING); - convo_create_chan(conv); -} - - -static void convo_opened(struct mwConversation *conv) { - struct mwImHandler *h = NULL; - - g_return_if_fail(conv != NULL); - g_return_if_fail(conv->service != NULL); - - convo_set_state(conv, mwConversation_OPEN); - h = conv->service->handler; - - g_return_if_fail(h != NULL); - - if(h->conversation_opened) - h->conversation_opened(conv); -} - - -static void convo_free(struct mwConversation *conv) { - struct mwServiceIm *srvc; - - mwConversation_removeClientData(conv); - - srvc = conv->service; - srvc->convs = g_list_remove_all(srvc->convs, conv); - - mwIdBlock_clear(&conv->target); - g_free(conv); -} - - -static int send_accept(struct mwConversation *c) { - - struct mwChannel *chan = c->channel; - struct mwSession *s = mwChannel_getSession(chan); - struct mwUserStatus *stat = mwSession_getUserStatus(s); - - struct mwPutBuffer *b; - struct mwOpaque *o; - - b = mwPutBuffer_new(); - guint32_put(b, mwImAddtlA_NORMAL); - guint32_put(b, c->features); - guint32_put(b, mwImAddtlC_NORMAL); - mwUserStatus_put(b, stat); - - o = mwChannel_getAddtlAccept(chan); - mwOpaque_clear(o); - mwPutBuffer_finalize(o, b); - - return mwChannel_accept(chan); -} - - -static void recv_channelCreate(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - /* - ensure it's the right service,proto,and proto ver - - check the opaque for the right opaque junk - - if not, close channel - - compose & send a channel accept - */ - - struct mwServiceIm *srvc_im = (struct mwServiceIm *) srvc; - struct mwImHandler *handler; - struct mwSession *s; - struct mwUserStatus *stat; - guint32 x, y, z; - struct mwGetBuffer *b; - struct mwConversation *c = NULL; - struct mwIdBlock idb; - - handler = srvc_im->handler; - s = mwChannel_getSession(chan); - stat = mwSession_getUserStatus(s); - - /* ensure the appropriate service/proto/ver */ - x = mwChannel_getServiceId(chan); - y = mwChannel_getProtoType(chan); - z = mwChannel_getProtoVer(chan); - - if( (x != mwService_IM) || (y != PROTOCOL_TYPE) || (z != PROTOCOL_VER) ) { - g_warning("unacceptable service, proto, ver:" - " 0x%08x, 0x%08x, 0x%08x", x, y, z); - mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); - return; - } - - /* act upon the values in the addtl block */ - b = mwGetBuffer_wrap(&msg->addtl); - guint32_get(b, &x); - guint32_get(b, &y); - z = (guint) mwGetBuffer_error(b); - mwGetBuffer_free(b); - - if(z /* buffer error, BOOM! */ ) { - g_warning("bad/malformed addtl in IM service"); - mwChannel_destroy(chan, ERR_FAILURE, NULL); - return; - - } else if(x != mwImAddtlA_NORMAL) { - g_message("unknown params: 0x%08x, 0x%08x", x, y); - mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); - return; - - } else if(y == mwImAddtlB_PRECONF) { - if(! handler->place_invite) { - g_info("rejecting place-invite channel"); - mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); - return; - - } else { - g_info("accepting place-invite channel"); - } - - } else if(y != mwImClient_PLAIN && y != srvc_im->features) { - /** reject what we do not understand */ - mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); - return; - - } else if(stat->status == mwStatus_BUSY) { - g_info("rejecting IM channel due to DND status"); - mwChannel_destroy(chan, ERR_CLIENT_USER_DND, NULL); - return; - } - - login_into_id(&idb, mwChannel_getUser(chan)); - -#if 0 - c = convo_find_by_user(srvc_im, &idb); -#endif - - if(! c) { - c = g_new0(struct mwConversation, 1); - c->service = srvc_im; - srvc_im->convs = g_list_prepend(srvc_im->convs, c); - } - -#if 0 - /* we're going to re-associate any existing conversations with this - new channel. That means closing any existing ones */ - if(c->channel) { - g_info("closing existing IM channel 0x%08x", mwChannel_getId(c->channel)); - mwConversation_close(c, ERR_SUCCESS); - } -#endif - - /* set up the conversation with this channel, target, and be fancy - if the other side requested it */ - c->channel = chan; - mwIdBlock_clone(&c->target, &idb); - c->features = y; - convo_set_state(c, mwConversation_PENDING); - mwChannel_setServiceData(c->channel, c, NULL); - - if(send_accept(c)) { - g_warning("sending IM channel accept failed"); - mwConversation_free(c); - - } else { - convo_opened(c); - } -} - - -static void recv_channelAccept(struct mwService *srvc, struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - struct mwConversation *conv; - - conv = mwChannel_getServiceData(chan); - if(! conv) { - g_warning("received channel accept for non-existant conversation"); - mwChannel_destroy(chan, ERR_FAILURE, NULL); - return; - } - - convo_opened(conv); -} - - -static void recv_channelDestroy(struct mwService *srvc, struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - struct mwConversation *c; - - c = mwChannel_getServiceData(chan); - g_return_if_fail(c != NULL); - - c->channel = NULL; - - if(mwChannel_isState(chan, mwChannel_ERROR)) { - - /* checking for failure on the receiving end to accept html - messages. Fail-over to a non-html format on a new channel for - the convo */ - if(c->features != mwImClient_PLAIN - && (msg->reason == ERR_IM_NOT_REGISTERED || - msg->reason == ERR_SERVICE_NO_SUPPORT)) { - - g_debug("falling back on a plaintext conversation"); - c->features = mwImClient_PLAIN; - convo_create_chan(c); - return; - } - } - - mwConversation_close(c, msg->reason); -} - - -static void convo_recv(struct mwConversation *conv, enum mwImSendType type, - gconstpointer msg) { - - struct mwServiceIm *srvc; - struct mwImHandler *handler; - - g_return_if_fail(conv != NULL); - - srvc = conv->service; - g_return_if_fail(srvc != NULL); - - handler = srvc->handler; - if(handler && handler->conversation_recv) - handler->conversation_recv(conv, type, msg); -} - - -static void convo_multi_start(struct mwConversation *conv) { - g_return_if_fail(conv->multi == NULL); - conv->multi = g_string_new(NULL); -} - - -static void convo_multi_stop(struct mwConversation *conv) { - - g_return_if_fail(conv->multi != NULL); - - /* actually send it */ - convo_recv(conv, conv->multi_type, conv->multi->str); - - /* clear up the multi buffer */ - g_string_free(conv->multi, TRUE); - conv->multi = NULL; -} - - -static void recv_text(struct mwServiceIm *srvc, struct mwChannel *chan, - struct mwGetBuffer *b) { - - struct mwConversation *c; - char *text = NULL; - - mwString_get(b, &text); - - if(! text) return; - - c = mwChannel_getServiceData(chan); - if(c) { - if(c->multi) { - g_string_append(c->multi, text); - - } else { - convo_recv(c, mwImSend_PLAIN, text); - } - } - - g_free(text); -} - - -static void convo_invite(struct mwConversation *conv, - struct mwOpaque *o) { - - struct mwServiceIm *srvc; - struct mwImHandler *handler; - - struct mwGetBuffer *b; - char *title, *name, *msg; - - g_info("convo_invite"); - - srvc = conv->service; - handler = srvc->handler; - - g_return_if_fail(handler != NULL); - g_return_if_fail(handler->place_invite != NULL); - - b = mwGetBuffer_wrap(o); - mwGetBuffer_advance(b, 4); - mwString_get(b, &title); - mwString_get(b, &msg); - mwGetBuffer_advance(b, 19); - mwString_get(b, &name); - - if(! mwGetBuffer_error(b)) { - handler->place_invite(conv, msg, title, name); - } - - mwGetBuffer_free(b); - g_free(msg); - g_free(title); - g_free(name); -} - - -static void recv_data(struct mwServiceIm *srvc, struct mwChannel *chan, - struct mwGetBuffer *b) { - - struct mwConversation *conv; - guint32 type, subtype; - struct mwOpaque o = { 0, 0 }; - char *x; - - guint32_get(b, &type); - guint32_get(b, &subtype); - mwOpaque_get(b, &o); - - if(mwGetBuffer_error(b)) { - mwOpaque_clear(&o); - return; - } - - conv = mwChannel_getServiceData(chan); - if(! conv) return; - - switch(type) { - case mwImData_TYPING: - convo_recv(conv, mwImSend_TYPING, GINT_TO_POINTER(! subtype)); - break; - - case mwImData_HTML: - if(o.len) { - if(conv->multi) { - g_string_append_len(conv->multi, (char *) o.data, o.len); - conv->multi_type = mwImSend_HTML; - - } else { - x = g_strndup((char *) o.data, o.len); - convo_recv(conv, mwImSend_HTML, x); - g_free(x); - } - } - break; - - case mwImData_SUBJECT: - x = g_strndup((char *) o.data, o.len); - convo_recv(conv, mwImSend_SUBJECT, x); - g_free(x); - break; - - case mwImData_MIME: - if(conv->multi) { - g_string_append_len(conv->multi, (char *) o.data, o.len); - conv->multi_type = mwImSend_MIME; - - } else { - x = g_strndup((char *) o.data, o.len); - convo_recv(conv, mwImSend_MIME, x); - g_free(x); - } - break; - - case mwImData_TIMESTAMP: - /* todo */ - break; - - case mwImData_INVITE: - convo_invite(conv, &o); - break; - - case mwImData_MULTI_START: - convo_multi_start(conv); - break; - - case mwImData_MULTI_STOP: - convo_multi_stop(conv); - break; - - default: - - mw_mailme_opaque(&o, "unknown data message type in IM service:" - " (0x%08x, 0x%08x)", type, subtype); - } - - mwOpaque_clear(&o); -} - - -static void recv(struct mwService *srvc, struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - /* - ensure message type is something we want - - parse message type into either mwIMText or mwIMData - - handle - */ - - struct mwGetBuffer *b; - guint32 mt; - - g_return_if_fail(type == msg_MESSAGE); - - b = mwGetBuffer_wrap(data); - guint32_get(b, &mt); - - if(mwGetBuffer_error(b)) { - g_warning("failed to parse message for IM service"); - mwGetBuffer_free(b); - return; - } - - switch(mt) { - case mwIm_TEXT: - recv_text((struct mwServiceIm *) srvc, chan, b); - break; - - case mwIm_DATA: - recv_data((struct mwServiceIm *) srvc, chan, b); - break; - - default: - g_warning("unknown message type 0x%08x for IM service", mt); - } - - if(mwGetBuffer_error(b)) - g_warning("failed to parse message type 0x%08x for IM service", mt); - - mwGetBuffer_free(b); -} - - -static void clear(struct mwServiceIm *srvc) { - struct mwImHandler *h; - - while(srvc->convs) - convo_free(srvc->convs->data); - - h = srvc->handler; - if(h && h->clear) - h->clear(srvc); - srvc->handler = NULL; -} - - -static const char *name(struct mwService *srvc) { - return "Instant Messaging"; -} - - -static const char *desc(struct mwService *srvc) { - return "IM service with Standard and NotesBuddy features"; -} - - -static void start(struct mwService *srvc) { - mwService_started(srvc); -} - - -static void stop(struct mwServiceIm *srvc) { - - while(srvc->convs) - mwConversation_free(srvc->convs->data); - - mwService_stopped(MW_SERVICE(srvc)); -} - - -struct mwServiceIm *mwServiceIm_new(struct mwSession *session, - struct mwImHandler *hndl) { - - struct mwServiceIm *srvc_im; - struct mwService *srvc; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(hndl != NULL, NULL); - - srvc_im = g_new0(struct mwServiceIm, 1); - srvc = MW_SERVICE(srvc_im); - - mwService_init(srvc, session, mwService_IM); - srvc->recv_create = recv_channelCreate; - srvc->recv_accept = recv_channelAccept; - srvc->recv_destroy = recv_channelDestroy; - srvc->recv = recv; - srvc->clear = (mwService_funcClear) clear; - srvc->get_name = name; - srvc->get_desc = desc; - srvc->start = start; - srvc->stop = (mwService_funcStop) stop; - - srvc_im->features = mwImClient_PLAIN; - srvc_im->handler = hndl; - - return srvc_im; -} - - -struct mwImHandler *mwServiceIm_getHandler(struct mwServiceIm *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->handler; -} - - -gboolean mwServiceIm_supports(struct mwServiceIm *srvc, - enum mwImSendType type) { - - g_return_val_if_fail(srvc != NULL, FALSE); - - switch(type) { - case mwImSend_PLAIN: - case mwImSend_TYPING: - return TRUE; - - case mwImSend_SUBJECT: - case mwImSend_HTML: - case mwImSend_MIME: - case mwImSend_TIMESTAMP: - return srvc->features == mwImClient_NOTESBUDDY; - - default: - return FALSE; - } -} - - -void mwServiceIm_setClientType(struct mwServiceIm *srvc, - enum mwImClientType type) { - - g_return_if_fail(srvc != NULL); - srvc->features = type; -} - - -enum mwImClientType mwServiceIm_getClientType(struct mwServiceIm *srvc) { - g_return_val_if_fail(srvc != NULL, mwImClient_UNKNOWN); - return srvc->features; -} - - -static int convo_send_data(struct mwConversation *conv, - guint32 type, guint32 subtype, - struct mwOpaque *data) { - struct mwPutBuffer *b; - struct mwOpaque o; - struct mwChannel *chan; - int ret; - - chan = conv->channel; - g_return_val_if_fail(chan != NULL, -1); - - b = mwPutBuffer_new(); - - guint32_put(b, mwIm_DATA); - guint32_put(b, type); - guint32_put(b, subtype); - mwOpaque_put(b, data); - - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_sendEncrypted(chan, msg_MESSAGE, &o, !conv->ext_id); - mwOpaque_clear(&o); - - return ret; -} - - -static int convo_send_multi_start(struct mwConversation *conv) { - return convo_send_data(conv, mwImData_MULTI_START, 0x00, NULL); -} - - -static int convo_send_multi_stop(struct mwConversation *conv) { - return convo_send_data(conv, mwImData_MULTI_STOP, 0x00, NULL); -} - - -/* breaks up a large message into segments, sends a start_segment - message, then sends each segment in turn, then sends a stop_segment - message */ -static int -convo_sendSegmented(struct mwConversation *conv, const char *message, - int (*send)(struct mwConversation *conv, - const char *msg)) { - char *buf = (char *) message; - gsize len; - int ret = 0; - - len = strlen(buf); - ret = convo_send_multi_start(conv); - - while(len && !ret) { - char tail; - gsize seg; - - seg = BREAKUP; - if(len < BREAKUP) - seg = len; - - /* temporarily NUL-terminate this segment */ - tail = buf[seg]; - buf[seg] = 0x00; - - ret = send(conv, buf); - - /* restore this segment */ - buf[seg] = tail; - - buf += seg; - len -= seg; - } - - if(! ret) - ret = convo_send_multi_stop(conv); - - return ret; -} - - -static int convo_sendText(struct mwConversation *conv, const char *text) { - struct mwPutBuffer *b; - struct mwOpaque o; - int ret; - - b = mwPutBuffer_new(); - - guint32_put(b, mwIm_TEXT); - mwString_put(b, text); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_sendEncrypted(conv->channel, msg_MESSAGE, &o, !conv->ext_id); - mwOpaque_clear(&o); - - return ret; -} - - -static int convo_sendTyping(struct mwConversation *conv, gboolean typing) { - return convo_send_data(conv, mwImData_TYPING, !typing, NULL); -} - - -static int convo_sendSubject(struct mwConversation *conv, - const char *subject) { - struct mwOpaque o; - - o.len = strlen(subject); - o.data = (guchar *) subject; - - return convo_send_data(conv, mwImData_SUBJECT, 0x00, &o); -} - - -static int convo_sendHtml(struct mwConversation *conv, const char *html) { - struct mwOpaque o; - - o.len = strlen(html); - o.data = (guchar *) html; - - if(o.len > BREAKUP) { - return convo_sendSegmented(conv, html, convo_sendHtml); - } else { - return convo_send_data(conv, mwImData_HTML, 0x00, &o); - } -} - - -static int convo_sendMime(struct mwConversation *conv, const char *mime) { - struct mwOpaque o; - - o.len = strlen(mime); - o.data = (guchar *) mime; - - if(o.len > BREAKUP) { - return convo_sendSegmented(conv, mime, convo_sendMime); - } else { - return convo_send_data(conv, mwImData_MIME, 0x00, &o); - } -} - - -int mwConversation_send(struct mwConversation *conv, enum mwImSendType type, - gconstpointer msg) { - - g_return_val_if_fail(conv != NULL, -1); - g_return_val_if_fail(mwConversation_isOpen(conv), -1); - g_return_val_if_fail(conv->channel != NULL, -1); - - switch(type) { - case mwImSend_PLAIN: - return convo_sendText(conv, msg); - case mwImSend_TYPING: - return convo_sendTyping(conv, GPOINTER_TO_INT(msg)); - case mwImSend_SUBJECT: - return convo_sendSubject(conv, msg); - case mwImSend_HTML: - return convo_sendHtml(conv, msg); - case mwImSend_MIME: - return convo_sendMime(conv, msg); - - default: - g_warning("unsupported IM Send Type, 0x%x", type); - return -1; - } -} - - -enum mwConversationState mwConversation_getState(struct mwConversation *conv) { - g_return_val_if_fail(conv != NULL, mwConversation_UNKNOWN); - return conv->state; -} - - -struct mwServiceIm *mwConversation_getService(struct mwConversation *conv) { - g_return_val_if_fail(conv != NULL, NULL); - return conv->service; -} - - -gboolean mwConversation_supports(struct mwConversation *conv, - enum mwImSendType type) { - g_return_val_if_fail(conv != NULL, FALSE); - - switch(type) { - case mwImSend_PLAIN: - case mwImSend_TYPING: - return TRUE; - - case mwImSend_SUBJECT: - case mwImSend_HTML: - case mwImSend_MIME: - return conv->features == mwImClient_NOTESBUDDY; - - default: - return FALSE; - } -} - - -enum mwImClientType -mwConversation_getClientType(struct mwConversation *conv) { - g_return_val_if_fail(conv != NULL, mwImClient_UNKNOWN); - return conv->features; -} - - -struct mwIdBlock *mwConversation_getTarget(struct mwConversation *conv) { - g_return_val_if_fail(conv != NULL, NULL); - return &conv->target; -} - - -struct mwLoginInfo *mwConversation_getTargetInfo(struct mwConversation *conv) { - g_return_val_if_fail(conv != NULL, NULL); - g_return_val_if_fail(conv->channel != NULL, NULL); - return mwChannel_getUser(conv->channel); -} - - -void mwConversation_setClientData(struct mwConversation *conv, - gpointer data, GDestroyNotify clean) { - g_return_if_fail(conv != NULL); - mw_datum_set(&conv->client_data, data, clean); -} - - -gpointer mwConversation_getClientData(struct mwConversation *conv) { - g_return_val_if_fail(conv != NULL, NULL); - return mw_datum_get(&conv->client_data); -} - - -void mwConversation_removeClientData(struct mwConversation *conv) { - g_return_if_fail(conv != NULL); - mw_datum_clear(&conv->client_data); -} - - -void mwConversation_close(struct mwConversation *conv, guint32 reason) { - struct mwServiceIm *srvc; - struct mwImHandler *h; - - g_return_if_fail(conv != NULL); - - convo_set_state(conv, mwConversation_CLOSED); - - srvc = conv->service; - g_return_if_fail(srvc != NULL); - - h = srvc->handler; - if(h && h->conversation_closed) - h->conversation_closed(conv, reason); - - if(conv->channel) { - mwChannel_destroy(conv->channel, reason, NULL); - conv->channel = NULL; - } -} - - -void mwConversation_free(struct mwConversation *conv) { - g_return_if_fail(conv != NULL); - - if(! mwConversation_isClosed(conv)) - mwConversation_close(conv, ERR_SUCCESS); - - convo_free(conv); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_place.c --- a/src/protocols/sametime/meanwhile/srvc_place.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1075 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include - -#include -#include - -#include "mw_channel.h" -#include "mw_common.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_place.h" -#include "mw_util.h" - - -#define PROTOCOL_TYPE 0x00 -#define PROTOCOL_VER 0x05 - - -enum incoming_msg { - msg_in_JOIN_RESPONSE = 0x0000, /* ? */ - msg_in_INFO = 0x0002, - msg_in_MESSAGE = 0x0004, - msg_in_SECTION = 0x0014, /* see in_section_subtype */ - msg_in_UNKNOWNa = 0x0015, -}; - - -enum in_section_subtype { - msg_in_SECTION_LIST = 0x0000, /* list of section members */ - msg_in_SECTION_PEER = 0x0001, /* see in_section_peer_subtye */ - msg_in_SECTION_PART = 0x0003, -}; - - -enum in_section_peer_subtype { - msg_in_SECTION_PEER_JOIN = 0x0000, - msg_in_SECTION_PEER_PART = 0x0001, /* after msg_in_SECTION_PART */ - msg_in_SECTION_PEER_CLEAR_ATTR = 0x0003, - msg_in_SECTION_PEER_SET_ATTR = 0x0004, -}; - - -enum outgoing_msg { - msg_out_JOIN_PLACE = 0x0000, /* ? */ - msg_out_PEER_INFO = 0x0002, /* ? */ - msg_out_MESSAGE = 0x0003, - msg_out_OLD_INVITE = 0x0005, /* old-style conf. invitation */ - msg_out_SET_ATTR = 0x000a, - msg_out_CLEAR_ATTR = 0x000b, - msg_out_SECTION = 0x0014, /* see out_section_subtype */ - msg_out_UNKNOWNb = 0x001e, /* ? maybe enter stage ? */ -}; - - -enum out_section_subtype { - msg_out_SECTION_LIST = 0x0002, /* req list of members */ - msg_out_SECTION_PART = 0x0003, -}; - - -/* - : allocate section - : state = NEW - - : create channel - : state = PENDING - - : channel accepted - : msg_out_JOIN_PLACE (maybe create?) - : state = JOINING - - : msg_in_JOIN_RESPONSE (contains our place member ID and section ID) - : msg_in_INFO (for place, not peer) - : state = JOINED - - : msg_out_SECTION_LIST (asking for all sections) (optional) - : msg_in_SECTION_LIST (listing all sections, as requested above) - - : msg_out_PEER_INFO (with our place member ID) (optional) - : msg_in_INFO (peer info as requested above) - - : msg_out_SECTION_LIST (with our section ID) (sorta optional) - : msg_in_SECTION_LIST (section listing as requested above) - - : msg_out_UNKNOWNb - : msg_in_SECTION_PEER_JOINED (empty, with our place member ID) - : state = OPEN - - : stuff... (invites, joins, parts, messages, attr) - - : state = CLOSING - : msg_out_SECTION_PART - : destroy channel - : deallocate section -*/ - - -struct mwServicePlace { - struct mwService service; - struct mwPlaceHandler *handler; - GList *places; -}; - - -enum mwPlaceState { - mwPlace_NEW, - mwPlace_PENDING, - mwPlace_JOINING, - mwPlace_JOINED, - mwPlace_OPEN, - mwPlace_CLOSING, - mwPlace_ERROR, - mwPlace_UNKNOWN, -}; - - -struct mwPlace { - struct mwServicePlace *service; - - enum mwPlaceState state; - struct mwChannel *channel; - - char *name; - char *title; - GHashTable *members; /* mapping of member ID: place_member */ - guint32 our_id; /* our member ID */ - guint32 section; /* the section we're using */ - - guint32 requests; /* counter for requests */ - - struct mw_datum client_data; -}; - - -struct place_member { - guint32 place_id; - guint16 member_type; - struct mwIdBlock idb; - char *login_id; - char *name; - guint16 login_type; - guint32 unknown_a; - guint32 unknown_b; -}; - - -#define GET_MEMBER(place, id) \ - (g_hash_table_lookup(place->members, GUINT_TO_POINTER(id))) - - -#define PUT_MEMBER(place, member) \ - (g_hash_table_insert(place->members, \ - GUINT_TO_POINTER(member->place_id), member)) - - -#define REMOVE_MEMBER_ID(place, id) \ - (g_hash_table_remove(place->members, GUINT_TO_POINTER(id))) - - -#define REMOVE_MEMBER(place, member) \ - REMOVE_MEMBER_ID(place, member->place_id) - - -static void member_free(struct place_member *p) { - mwIdBlock_clear(&p->idb); - g_free(p->login_id); - g_free(p->name); - g_free(p); -} - - -__attribute__((used)) -static const struct mwLoginInfo * -member_as_login_info(struct place_member *p) { - static struct mwLoginInfo li; - - li.login_id = p->login_id; - li.type = p->login_type; - li.user_id = p->idb.user; - li.user_name = p->name; - li.community = p->idb.community; - li.full = FALSE; - - return &li; -} - - -static const char *place_state_str(enum mwPlaceState s) { - switch(s) { - case mwPlace_NEW: return "new"; - case mwPlace_PENDING: return "pending"; - case mwPlace_JOINING: return "joining"; - case mwPlace_JOINED: return "joined"; - case mwPlace_OPEN: return "open"; - case mwPlace_CLOSING: return "closing"; - case mwPlace_ERROR: return "error"; - - case mwPlace_UNKNOWN: /* fall-through */ - default: return "UNKNOWN"; - } -} - - -static void place_state(struct mwPlace *place, enum mwPlaceState s) { - g_return_if_fail(place != NULL); - - if(place->state == s) return; - - place->state = s; - g_message("place %s state: %s", NSTR(place->name), place_state_str(s)); -} - - -static void place_free(struct mwPlace *place) { - struct mwServicePlace *srvc; - - if(! place) return; - - srvc = place->service; - g_return_if_fail(srvc != NULL); - - srvc->places = g_list_remove_all(srvc->places, place); - - mw_datum_clear(&place->client_data); - - g_hash_table_destroy(place->members); - - g_free(place->name); - g_free(place->title); - g_free(place); -} - - -static int recv_JOIN_RESPONSE(struct mwPlace *place, - struct mwGetBuffer *b) { - - int ret = 0; - guint32 our_id, section; - - guint32_get(b, &our_id); - guint32_get(b, §ion); - - place->our_id = our_id; - place->section = section; - - return ret; -} - - -static int send_SECTION_LIST(struct mwPlace *place, guint32 section) { - int ret = 0; - struct mwOpaque o = {0, 0}; - struct mwPutBuffer *b; - - b = mwPutBuffer_new(); - guint16_put(b, msg_out_SECTION_LIST); - guint32_put(b, section); - gboolean_put(b, FALSE); - guint32_put(b, ++place->requests); - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_send(place->channel, msg_out_SECTION, &o); - mwOpaque_clear(&o); - - return ret; -} - - -static int recv_INFO(struct mwPlace *place, - struct mwGetBuffer *b) { - - int ret = 0; - guint32 skip = 0; - guint32 section = 0; - - guint32_get(b, &skip); - guint32_get(b, §ion); - mwGetBuffer_advance(b, skip); - - if(! section) { - /* this is a place info rather than member info */ - if(place->title) g_free(place->title); - mwGetBuffer_advance(b, 2); - mwString_get(b, &place->title); - - place_state(place, mwPlace_JOINED); - ret = send_SECTION_LIST(place, place->section); - } - - return ret; -} - - -static int recv_MESSAGE(struct mwPlace *place, - struct mwGetBuffer *b) { - - struct mwServicePlace *srvc; - guint32 pm_id; - guint32 unkn_a, unkn_b, ign; - struct place_member *pm; - char *msg = NULL; - int ret = 0; - - srvc = place->service; - - /* no messages before becoming fully open, please */ - g_return_val_if_fail(place->state == mwPlace_OPEN, -1); - - /* regarding unkn_a and unkn_b: - - they're probably a section indicator and a message count, I'm - just not sure which is which. Until this implementation supports - place sections in the API, it really doesn't matter. */ - - guint32_get(b, &pm_id); - pm = GET_MEMBER(place, pm_id); - g_return_val_if_fail(pm != NULL, -1); - - guint32_get(b, &unkn_a); - guint32_get(b, &ign); /* actually an opaque length */ - - if(! ign) return ret; - - guint32_get(b, &unkn_b); - mwString_get(b, &msg); - - if(srvc->handler && srvc->handler->message) - srvc->handler->message(place, &pm->idb, msg); - - g_free(msg); - - return ret; -} - - -static void place_opened(struct mwPlace *place) { - struct mwServicePlace *srvc; - - place_state(place, mwPlace_OPEN); - - srvc = place->service; - if(srvc->handler && srvc->handler->opened) - srvc->handler->opened(place); -} - - -static int recv_SECTION_PEER_JOIN(struct mwPlace *place, - struct mwGetBuffer *b) { - struct mwServicePlace *srvc; - struct place_member *pm; - guint32 section; - int ret = 0; - - srvc = place->service; - - guint32_get(b, §ion); - if(! section) { - g_info("SECTION_PEER_JOIN with section 0x00"); - return 0; - } - - mwGetBuffer_advance(b, 4); - - pm = g_new0(struct place_member, 1); - guint32_get(b, &pm->place_id); - guint16_get(b, &pm->member_type); - mwIdBlock_get(b, &pm->idb); - mwString_get(b, &pm->login_id); - mwString_get(b, &pm->name); - guint16_get(b, &pm->login_type); - guint32_get(b, &pm->unknown_a); - guint32_get(b, &pm->unknown_b); - - PUT_MEMBER(place, pm); - if(srvc->handler && srvc->handler->peerJoined) - srvc->handler->peerJoined(place, &pm->idb); - - if(pm->place_id == place->our_id) - place_opened(place); - - return ret; -} - - -static int recv_SECTION_PEER_PART(struct mwPlace *place, - struct mwGetBuffer *b) { - struct mwServicePlace *srvc; - int ret = 0; - guint32 section, id; - struct place_member *pm; - - srvc = place->service; - - guint32_get(b, §ion); - g_return_val_if_fail(section == place->section, 0); - - guint32_get(b, &id); - pm = GET_MEMBER(place, id); - - /* SECTION_PART may have been called already */ - if(! pm) return 0; - - if(srvc->handler && srvc->handler->peerParted) - srvc->handler->peerParted(place, &pm->idb); - - REMOVE_MEMBER(place, pm); - - return ret; -} - - -static int recv_SECTION_PEER_CLEAR_ATTR(struct mwPlace *place, - struct mwGetBuffer *b) { - struct mwServicePlace *srvc; - int ret = 0; - guint32 id, attr; - struct place_member *pm; - - srvc = place->service; - - guint32_get(b, &id); - guint32_get(b, &attr); - - pm = GET_MEMBER(place, id); - g_return_val_if_fail(pm != NULL, -1); - - if(srvc->handler && srvc->handler->peerUnsetAttribute) - srvc->handler->peerUnsetAttribute(place, &pm->idb, attr); - - return ret; -} - - -static int recv_SECTION_PEER_SET_ATTR(struct mwPlace *place, - struct mwGetBuffer *b) { - struct mwServicePlace *srvc; - int ret = 0; - guint32 id, attr; - struct mwOpaque o = {0,0}; - struct place_member *pm; - - srvc = place->service; - - guint32_get(b, &id); - mwGetBuffer_advance(b, 4); - mwOpaque_get(b, &o); - mwGetBuffer_advance(b, 4); - guint32_get(b, &attr); - - pm = GET_MEMBER(place, id); - g_return_val_if_fail(pm != NULL, -1); - - if(srvc->handler && srvc->handler->peerSetAttribute) - srvc->handler->peerSetAttribute(place, &pm->idb, attr, &o); - - mwOpaque_clear(&o); - - return ret; -} - - -static int recv_SECTION_PEER(struct mwPlace *place, - struct mwGetBuffer *b) { - guint16 subtype; - int res; - - guint16_get(b, &subtype); - - g_return_val_if_fail(! mwGetBuffer_error(b), -1); - - switch(subtype) { - case msg_in_SECTION_PEER_JOIN: - res = recv_SECTION_PEER_JOIN(place, b); - break; - - case msg_in_SECTION_PEER_PART: - res = recv_SECTION_PEER_PART(place, b); - break; - - case msg_in_SECTION_PEER_CLEAR_ATTR: - res = recv_SECTION_PEER_CLEAR_ATTR(place, b); - break; - - case msg_in_SECTION_PEER_SET_ATTR: - res = recv_SECTION_PEER_SET_ATTR(place, b); - break; - - default: - res = -1; - } - - return res; -} - - -static int recv_SECTION_LIST(struct mwPlace *place, - struct mwGetBuffer *b) { - int ret = 0; - guint32 sec, count; - - mwGetBuffer_advance(b, 4); - guint32_get(b, &sec); - - g_return_val_if_fail(sec == place->section, -1); - - mwGetBuffer_advance(b, 8); - guint32_get(b, &count); - mwGetBuffer_advance(b, 8); - - while(count--) { - struct place_member *m; - - m = g_new0(struct place_member, 1); - mwGetBuffer_advance(b, 4); - guint32_get(b, &m->place_id); - guint16_get(b, &m->member_type); - mwIdBlock_get(b, &m->idb); - mwString_get(b, &m->login_id); - mwString_get(b, &m->name); - guint16_get(b, &m->login_type); - guint32_get(b, &m->unknown_a); - guint32_get(b, &m->unknown_b); - - PUT_MEMBER(place, m); - } - - if(place->state != mwPlace_OPEN) - place_opened(place); - - return ret; -} - - -static int recv_SECTION_PART(struct mwPlace *place, - struct mwGetBuffer *b) { - /* look up user in place - remove user from place - trigger event */ - - struct mwServicePlace *srvc; - guint32 pm_id; - struct place_member *pm; - - srvc = place->service; - - guint32_get(b, &pm_id); - pm = GET_MEMBER(place, pm_id); - - /* SECTION_PEER_PART may have been called already */ - if(! pm) return 0; - - if(srvc->handler && srvc->handler->peerParted) - srvc->handler->peerParted(place, &pm->idb); - - REMOVE_MEMBER(place, pm); - - return 0; -} - - -static int recv_SECTION(struct mwPlace *place, struct mwGetBuffer *b) { - guint16 subtype; - int res; - - guint16_get(b, &subtype); - - g_return_val_if_fail(! mwGetBuffer_error(b), -1); - - switch(subtype) { - case msg_in_SECTION_LIST: - res = recv_SECTION_LIST(place, b); - break; - - case msg_in_SECTION_PEER: - res = recv_SECTION_PEER(place, b); - break; - - case msg_in_SECTION_PART: - res = recv_SECTION_PART(place, b); - break; - - default: - res = -1; - } - - return res; -} - - -static int recv_UNKNOWNa(struct mwPlace *place, struct mwGetBuffer *b) { - int res = 0; - - if(place->state == mwPlace_JOINING) { - ; - /* place_state(place, mwPlace_JOINED); - res = send_SECTION_LIST(place, place->section); */ - - } else if(place->state == mwPlace_JOINED) { - ; - /* if(GET_MEMBER(place, place->our_id)) - place_opened(place); */ - } - - return res; -} - - -static void recv(struct mwService *service, struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - struct mwPlace *place; - struct mwGetBuffer *b; - int res = 0; - - place = mwChannel_getServiceData(chan); - g_return_if_fail(place != NULL); - - b = mwGetBuffer_wrap(data); - switch(type) { - case msg_in_JOIN_RESPONSE: - res = recv_JOIN_RESPONSE(place, b); - break; - - case msg_in_INFO: - res = recv_INFO(place, b); - break; - - case msg_in_MESSAGE: - res = recv_MESSAGE(place, b); - break; - - case msg_in_SECTION: - res = recv_SECTION(place, b); - break; - - case msg_in_UNKNOWNa: - res = recv_UNKNOWNa(place, b); - break; - - default: - mw_mailme_opaque(data, "Received unknown message type 0x%x on place %s", - type, NSTR(place->name)); - } - - if(res) { - mw_mailme_opaque(data, "Troubling parsing message type 0x0%x on place %s", - type, NSTR(place->name)); - } - - mwGetBuffer_free(b); -} - - -static void stop(struct mwServicePlace *srvc) { - while(srvc->places) - mwPlace_destroy(srvc->places->data, ERR_SUCCESS); - - mwService_stopped(MW_SERVICE(srvc)); -} - - -static int send_JOIN_PLACE(struct mwPlace *place) { - struct mwOpaque o = {0, 0}; - struct mwPutBuffer *b; - int ret; - - b = mwPutBuffer_new(); - gboolean_put(b, FALSE); - guint16_put(b, 0x01); - guint16_put(b, 0x02); /* 0x01 */ - guint16_put(b, 0x01); /* 0x00 */ - - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_send(place->channel, msg_out_JOIN_PLACE, &o); - - mwOpaque_clear(&o); - - if(ret) { - place_state(place, mwPlace_ERROR); - } else { - place_state(place, mwPlace_JOINING); - } - - return ret; -} - - -static void recv_channelAccept(struct mwService *service, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - struct mwServicePlace *srvc; - struct mwPlace *place; - int res; - - srvc = (struct mwServicePlace *) service; - g_return_if_fail(srvc != NULL); - - place = mwChannel_getServiceData(chan); - g_return_if_fail(place != NULL); - - res = send_JOIN_PLACE(place); -} - - -static void recv_channelDestroy(struct mwService *service, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - struct mwServicePlace *srvc; - struct mwPlace *place; - - srvc = (struct mwServicePlace *) service; - g_return_if_fail(srvc != NULL); - - place = mwChannel_getServiceData(chan); - g_return_if_fail(place != NULL); - - place_state(place, mwPlace_ERROR); - - place->channel = NULL; - - if(srvc->handler && srvc->handler->closed) - srvc->handler->closed(place, msg->reason); - - mwPlace_destroy(place, msg->reason); -} - - -static void clear(struct mwServicePlace *srvc) { - - if(srvc->handler && srvc->handler->clear) - srvc->handler->clear(srvc); - - while(srvc->places) - place_free(srvc->places->data); -} - - -static const char *get_name(struct mwService *srvc) { - return "Places Conferencing"; -} - - -static const char *get_desc(struct mwService *srvc) { - return "Barebones conferencing via Places"; -} - - -struct mwServicePlace * -mwServicePlace_new(struct mwSession *session, - struct mwPlaceHandler *handler) { - - struct mwServicePlace *srvc_place; - struct mwService *srvc; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(handler != NULL, NULL); - - srvc_place = g_new0(struct mwServicePlace, 1); - srvc_place->handler = handler; - - srvc = MW_SERVICE(srvc_place); - mwService_init(srvc, session, mwService_PLACE); - srvc->start = NULL; - srvc->stop = (mwService_funcStop) stop; - srvc->recv_create = NULL; - srvc->recv_accept = recv_channelAccept; - srvc->recv_destroy = recv_channelDestroy; - srvc->recv = recv; - srvc->clear = (mwService_funcClear) clear; - srvc->get_name = get_name; - srvc->get_desc = get_desc; - - return srvc_place; -} - - -struct mwPlaceHandler * -mwServicePlace_getHandler(struct mwServicePlace *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->handler; -} - - -const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc) { - g_return_val_if_fail(srvc != NULL, NULL); - return srvc->places; -} - - -struct mwPlace *mwPlace_new(struct mwServicePlace *srvc, - const char *name, const char *title) { - struct mwPlace *place; - - g_return_val_if_fail(srvc != NULL, NULL); - - place = g_new0(struct mwPlace, 1); - place->service = srvc; - place->name = g_strdup(name); - place->title = g_strdup(title); - place->state = mwPlace_NEW; - - place->members = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) member_free); - - srvc->places = g_list_prepend(srvc->places, place); - - return place; -} - - -struct mwServicePlace *mwPlace_getService(struct mwPlace *place) { - g_return_val_if_fail(place != NULL, NULL); - return place->service; -} - - -static char *place_generate_name(const char *user) { - guint a, b; - char *ret; - - user = user? user: "meanwhile"; - - srand(clock() + rand()); - a = ((rand() & 0xff) << 8) | (rand() & 0xff); - b = time(NULL); - - ret = g_strdup_printf("%s(%08x,%04x)", user, b, a); - g_debug("generated random conference name: '%s'", ret); - return ret; -} - - -const char *mwPlace_getName(struct mwPlace *place) { - g_return_val_if_fail(place != NULL, NULL); - - if(! place->name) { - struct mwSession *session; - struct mwLoginInfo *li; - - session = mwService_getSession(MW_SERVICE(place->service)); - li = mwSession_getLoginInfo(session); - - place->name = place_generate_name(li? li->user_id: NULL); - } - - return place->name; -} - - -static char *place_generate_title(const char *user) { - char *ret; - - user = user? user: "Meanwhile"; - ret = g_strdup_printf("%s's Conference", user); - g_debug("generated conference title: %s", ret); - - return ret; -} - - -const char *mwPlace_getTitle(struct mwPlace *place) { - g_return_val_if_fail(place != NULL, NULL); - - if(! place->title) { - struct mwSession *session; - struct mwLoginInfo *li; - - session = mwService_getSession(MW_SERVICE(place->service)); - li = mwSession_getLoginInfo(session); - - place->title = place_generate_title(li? li->user_name: NULL); - } - - return place->title; -} - - -int mwPlace_open(struct mwPlace *p) { - struct mwSession *session; - struct mwChannelSet *cs; - struct mwChannel *chan; - struct mwPutBuffer *b; - int ret; - - g_return_val_if_fail(p != NULL, -1); - g_return_val_if_fail(p->service != NULL, -1); - - session = mwService_getSession(MW_SERVICE(p->service)); - g_return_val_if_fail(session != NULL, -1); - - cs = mwSession_getChannels(session); - g_return_val_if_fail(cs != NULL, -1); - - chan = mwChannel_newOutgoing(cs); - mwChannel_setService(chan, MW_SERVICE(p->service)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - mwChannel_populateSupportedCipherInstances(chan); - - b = mwPutBuffer_new(); - mwString_put(b, mwPlace_getName(p)); - mwString_put(b, mwPlace_getTitle(p)); - guint32_put(b, 0x00); /* ? */ - - mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); - - ret = mwChannel_create(chan); - if(ret) { - place_state(p, mwPlace_ERROR); - } else { - place_state(p, mwPlace_PENDING); - p->channel = chan; - mwChannel_setServiceData(chan, p, NULL); - } - - return ret; -} - - -int mwPlace_destroy(struct mwPlace *p, guint32 code) { - int ret = 0; - - place_state(p, mwPlace_CLOSING); - - if(p->channel) { - ret = mwChannel_destroy(p->channel, code, NULL); - p->channel = NULL; - } - - place_free(p); - - return ret; -} - - -GList *mwPlace_getMembers(struct mwPlace *place) { - GList *l, *ll; - - g_return_val_if_fail(place != NULL, NULL); - g_return_val_if_fail(place->members != NULL, NULL); - - ll = map_collect_values(place->members); - for(l = ll; l; l = l->next) { - struct place_member *pm = l->data; - l->data = &pm->idb; - g_info("collected member %u: %s, %s", pm->place_id, - NSTR(pm->idb.user), NSTR(pm->idb.community)); - } - - return ll; -} - - -int mwPlace_sendText(struct mwPlace *place, const char *msg) { - struct mwOpaque o = {0,0}; - struct mwPutBuffer *b; - int ret; - - b = mwPutBuffer_new(); - guint32_put(b, 0x01); /* probably a message type */ - mwString_put(b, msg); - mwPutBuffer_finalize(&o, b); - - b = mwPutBuffer_new(); - guint32_put(b, place->section); - mwOpaque_put(b, &o); - mwOpaque_clear(&o); - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_send(place->channel, msg_out_MESSAGE, &o); - mwOpaque_clear(&o); - return ret; -} - - -int mwPlace_legacyInvite(struct mwPlace *place, - struct mwIdBlock *idb, - const char *message) { - - struct mwOpaque o = {0,0}; - struct mwPutBuffer *b; - int ret; - - b = mwPutBuffer_new(); - mwIdBlock_put(b, idb); - mwString_put(b, idb->user); - mwString_put(b, idb->user); - mwString_put(b, message); - gboolean_put(b, FALSE); - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_send(place->channel, msg_out_OLD_INVITE, &o); - mwOpaque_clear(&o); - return ret; -} - - -int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib, - struct mwOpaque *data) { - - struct mwOpaque o = {0,0}; - struct mwPutBuffer *b; - int ret; - - b = mwPutBuffer_new(); - guint32_put(b, place->our_id); - guint32_put(b, 0x00); - guint32_put(b, attrib); - mwOpaque_put(b, data); - - ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o); - mwOpaque_clear(&o); - return ret; -} - - -int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib) { - struct mwOpaque o = {0,0}; - struct mwPutBuffer *b; - int ret; - - b = mwPutBuffer_new(); - guint32_put(b, place->our_id); - guint32_put(b, attrib); - - ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o); - mwOpaque_clear(&o); - return ret; -} - - -void mwPlace_setClientData(struct mwPlace *place, - gpointer data, GDestroyNotify clear) { - - g_return_if_fail(place != NULL); - mw_datum_set(&place->client_data, data, clear); -} - - -gpointer mwPlace_getClientData(struct mwPlace *place) { - g_return_val_if_fail(place != NULL, NULL); - return mw_datum_get(&place->client_data); -} - - -void mwPlace_removeClientData(struct mwPlace *place) { - g_return_if_fail(place != NULL); - mw_datum_clear(&place->client_data); -} diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_resolve.c --- a/src/protocols/sametime/meanwhile/srvc_resolve.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,389 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -#include "mw_channel.h" -#include "mw_common.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_resolve.h" - - -#define PROTOCOL_TYPE 0x00000015 -#define PROTOCOL_VER 0x00000000 - - -/** oddly, there is only one message type in this service */ -#define RESOLVE_ACTION 0x02 - - -struct mwServiceResolve { - struct mwService service; - - struct mwChannel *channel; /**< channel for this service */ - GHashTable *searches; /**< guint32:struct mw_search */ - guint32 counter; /**< incremented to provide searche IDs */ -}; - - -/** structure representing an active search. keeps track of the ID, - the handler, and the optional user data and cleanup */ -struct mw_search { - struct mwServiceResolve *service; - guint32 id; - mwResolveHandler handler; - gpointer data; - GDestroyNotify cleanup; -}; - - -static struct mw_search *search_new(struct mwServiceResolve *srvc, - mwResolveHandler handler, - gpointer data, GDestroyNotify cleanup) { - - struct mw_search *search = g_new0(struct mw_search, 1); - - search->service = srvc; - search->handler = handler; - - /* we want search IDs that aren't SEARCH_ERROR */ - do { - search->id = srvc->counter++; - } while(search->id == SEARCH_ERROR); - - search->data = data; - search->cleanup = cleanup; - - return search; -} - - -/** called whenever a mw_search is removed from the searches table of - the service */ -static void search_free(struct mw_search *search) { - g_return_if_fail(search != NULL); - - if(search->cleanup) - search->cleanup(search->data); - - g_free(search); -} - - -static const char *get_name(struct mwService *srvc) { - return "Identity Resolution"; -} - - -static const char *get_desc(struct mwService *srvc) { - return "Resolves short IDs to full IDs"; -} - - -static struct mwChannel *make_channel(struct mwServiceResolve *srvc) { - struct mwSession *session; - struct mwChannelSet *cs; - struct mwChannel *chan; - - session = mwService_getSession(MW_SERVICE(srvc)); - cs = mwSession_getChannels(session); - chan = mwChannel_newOutgoing(cs); - - mwChannel_setService(chan, MW_SERVICE(srvc)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - return mwChannel_create(chan)? NULL: chan; -} - - -static void start(struct mwServiceResolve *srvc) { - struct mwChannel *chan; - - g_return_if_fail(srvc != NULL); - - chan = make_channel(srvc); - if(chan) { - srvc->channel = chan; - } else { - mwService_stopped(MW_SERVICE(srvc)); - return; - } - - /* semi-lazily create the searches table */ - srvc->searches = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) search_free); -} - - -static void stop(struct mwServiceResolve *srvc) { - g_return_if_fail(srvc != NULL); - - if(srvc->channel) { - mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL); - srvc->channel = NULL; - } - - /* destroy all the pending requests. */ - g_hash_table_destroy(srvc->searches); - srvc->searches = NULL; - - mwService_stopped(MW_SERVICE(srvc)); -} - - -static void clear(struct mwServiceResolve *srvc) { - if(srvc->searches) { - g_hash_table_destroy(srvc->searches); - srvc->searches = NULL; - } -} - - -static void recv_create(struct mwServiceResolve *srvc, - struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - /* you serve me, not the other way around */ - mwChannel_destroy(chan, ERR_FAILURE, NULL); -} - - -static void recv_accept(struct mwServiceResolve *srvc, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc->channel); - - mwService_started(MW_SERVICE(srvc)); -} - - -static void recv_destroy(struct mwServiceResolve *srvc, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - struct mwSession *session; - - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc->channel); - - srvc->channel = NULL; - mwService_stop(MW_SERVICE(srvc)); - - session = mwService_getSession(MW_SERVICE(srvc)); - g_return_if_fail(session != NULL); - - mwSession_senseService(session, mwService_getType(MW_SERVICE(srvc))); -} - - -static GList *load_matches(struct mwGetBuffer *b, guint32 count) { - GList *matches = NULL; - - while(count--) { - struct mwResolveMatch *m = g_new0(struct mwResolveMatch, 1); - - mwString_get(b, &m->id); - mwString_get(b, &m->name); - mwString_get(b, &m->desc); - guint32_get(b, &m->type); - - matches = g_list_append(matches, m); - } - - return matches; -} - - -static GList *load_results(struct mwGetBuffer *b, guint32 count) { - GList *results = NULL; - - while(count--) { - struct mwResolveResult *r = g_new0(struct mwResolveResult, 1); - guint32 junk, matches; - - guint32_get(b, &junk); - guint32_get(b, &r->code); - mwString_get(b, &r->name); - - guint32_get(b, &matches); - r->matches = load_matches(b, matches); - - results = g_list_append(results, r); - } - - return results; -} - - -static void free_matches(GList *matches) { - for(; matches; matches = g_list_delete_link(matches, matches)) { - struct mwResolveMatch *m = matches->data; - g_free(m->id); - g_free(m->name); - g_free(m->desc); - g_free(m); - } -} - - -static void free_results(GList *results) { - for(; results; results = g_list_delete_link(results, results)) { - struct mwResolveResult *r = results->data; - g_free(r->name); - free_matches(r->matches); - g_free(r); - } -} - - -static void recv(struct mwServiceResolve *srvc, - struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - struct mwGetBuffer *b; - guint32 junk, id, code, count; - struct mw_search *search; - - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc->channel); - g_return_if_fail(data != NULL); - - if(type != RESOLVE_ACTION) { - mw_mailme_opaque(data, "unknown message in resolve service: 0x%04x", type); - return; - } - - b = mwGetBuffer_wrap(data); - guint32_get(b, &junk); - guint32_get(b, &id); - guint32_get(b, &code); - guint32_get(b, &count); - - if(mwGetBuffer_error(b)) { - g_warning("error parsing search result"); - mwGetBuffer_free(b); - return; - } - - search = g_hash_table_lookup(srvc->searches, GUINT_TO_POINTER(id)); - - if(search) { - GList *results = load_results(b, count); - if(mwGetBuffer_error(b)) { - g_warning("error parsing search results"); - } else { - g_debug("triggering handler"); - search->handler(srvc, id, code, results, search->data); - } - free_results(results); - g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id)); - - } else { - g_debug("no search found: 0x%x", id); - } - - mwGetBuffer_free(b); -} - - -struct mwServiceResolve *mwServiceResolve_new(struct mwSession *session) { - struct mwServiceResolve *srvc_resolve; - struct mwService *srvc; - - g_return_val_if_fail(session != NULL, NULL); - - srvc_resolve = g_new0(struct mwServiceResolve, 1); - - srvc = MW_SERVICE(srvc_resolve); - - mwService_init(srvc, session, mwService_RESOLVE); - srvc->get_name = get_name; - srvc->get_desc = get_desc; - srvc->recv_create = (mwService_funcRecvCreate) recv_create; - srvc->recv_accept = (mwService_funcRecvAccept) recv_accept; - srvc->recv_destroy = (mwService_funcRecvDestroy) recv_destroy; - srvc->recv = (mwService_funcRecv) recv; - srvc->start = (mwService_funcStart) start; - srvc->stop = (mwService_funcStop) stop; - srvc->clear = (mwService_funcClear) clear; - - return srvc_resolve; -} - - -guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc, - GList *queries, enum mwResolveFlag flags, - mwResolveHandler handler, - gpointer data, GDestroyNotify cleanup) { - - struct mw_search *search; - struct mwPutBuffer *b; - struct mwOpaque o = { 0, 0 }; - int ret, count = 0; - - g_return_val_if_fail(srvc != NULL, SEARCH_ERROR); - g_return_val_if_fail(handler != NULL, SEARCH_ERROR); - - count = g_list_length(queries); - g_return_val_if_fail(count > 0, SEARCH_ERROR); - - search = search_new(srvc, handler, data, cleanup); - - b = mwPutBuffer_new(); - guint32_put(b, 0x00); /* to be overwritten */ - guint32_put(b, search->id); - guint32_put(b, count); - for(; queries; queries = queries->next) - mwString_put(b, queries->data); - guint32_put(b, flags); - - mwPutBuffer_finalize(&o, b); - - ret = mwChannel_send(srvc->channel, RESOLVE_ACTION, &o); - if(ret) { - search_free(search); - return SEARCH_ERROR; - - } else { - g_hash_table_insert(srvc->searches, - GUINT_TO_POINTER(search->id), search); - return search->id; - } -} - - -void mwServiceResolve_cancelResolve(struct mwServiceResolve *srvc, - guint32 id) { - - g_return_if_fail(srvc != NULL); - g_return_if_fail(srvc->searches != NULL); - - g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id)); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/srvc_store.c --- a/src/protocols/sametime/meanwhile/srvc_store.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,608 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -#include "mw_channel.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_store.h" - - -#define PROTOCOL_TYPE 0x00000025 -#define PROTOCOL_VER 0x00000001 - - -enum storage_action { - action_load = 0x0004, - action_loaded = 0x0005, - action_save = 0x0006, - action_saved = 0x0007, -}; - - -struct mwStorageUnit { - /** key by which data is referenced in service - @see mwStorageKey */ - guint32 key; - - /** Data associated with key in service */ - struct mwOpaque data; -}; - - -struct mwStorageReq { - guint32 id; /**< unique id for this request */ - guint32 result_code; /**< result code for completed request */ - enum storage_action action; /**< load or save */ - struct mwStorageUnit *item; /**< the key/data pair */ - mwStorageCallback cb; /**< callback to notify upon completion */ - gpointer data; /**< user data to pass with callback */ - GDestroyNotify data_free; /**< optionally frees user data */ -}; - - -struct mwServiceStorage { - struct mwService service; - - /** collection of mwStorageReq */ - GList *pending; - - /** current service channel */ - struct mwChannel *channel; - - /** keep track of the counter */ - guint32 id_counter; -}; - - -static void request_get(struct mwGetBuffer *b, struct mwStorageReq *req) { - guint32 id, count, junk; - - if(mwGetBuffer_error(b)) return; - - guint32_get(b, &id); - guint32_get(b, &req->result_code); - - if(req->action == action_loaded) { - guint32_get(b, &count); - - if(count > 0) { - guint32_get(b, &junk); - guint32_get(b, &req->item->key); - - mwOpaque_clear(&req->item->data); - mwOpaque_get(b, &req->item->data); - } - } -} - - -static void request_put(struct mwPutBuffer *b, struct mwStorageReq *req) { - - guint32_put(b, req->id); - guint32_put(b, 1); - - if(req->action == action_save) { - guint32_put(b, 20 + req->item->data.len); /* ugh, offset garbage */ - guint32_put(b, req->item->key); - mwOpaque_put(b, &req->item->data); - - } else { - guint32_put(b, req->item->key); - } -} - - -static int request_send(struct mwChannel *chan, struct mwStorageReq *req) { - struct mwPutBuffer *b; - struct mwOpaque o = { 0, 0 }; - int ret; - - b = mwPutBuffer_new(); - request_put(b, req); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, req->action, &o); - mwOpaque_clear(&o); - - if(! ret) { - if(req->action == action_save) { - req->action = action_saved; - } else if(req->action == action_load) { - req->action = action_loaded; - } - } - - return ret; -} - - -static struct mwStorageReq *request_find(struct mwServiceStorage *srvc, - guint32 id) { - GList *l; - - for(l = srvc->pending; l; l = l->next) { - struct mwStorageReq *r = l->data; - if(r->id == id) return r; - } - - return NULL; -} - - -static const char *action_str(enum storage_action act) { - switch(act) { - case action_load: return "load"; - case action_loaded: return "loaded"; - case action_save: return "save"; - case action_saved: return "saved"; - default: return "UNKNOWN"; - } -} - - -static void request_trigger(struct mwServiceStorage *srvc, - struct mwStorageReq *req) { - - struct mwStorageUnit *item = req->item; - - g_message("storage request %s: key = 0x%x, result = 0x%x, length = %u", - action_str(req->action), - item->key, req->result_code, (guint) item->data.len); - - if(req->cb) - req->cb(srvc, req->result_code, item, req->data); -} - - -static void request_free(struct mwStorageReq *req) { - if(req->data_free) { - req->data_free(req->data); - req->data = NULL; - req->data_free = NULL; - } - - mwStorageUnit_free(req->item); - g_free(req); -} - - -static void request_remove(struct mwServiceStorage *srvc, - struct mwStorageReq *req) { - - srvc->pending = g_list_remove_all(srvc->pending, req); - request_free(req); -} - - -static const char *get_name(struct mwService *srvc) { - return "User Storage"; -} - - -static const char *get_desc(struct mwService *srvc) { - return "Stores user data and settings on the server"; -} - - -static struct mwChannel *make_channel(struct mwServiceStorage *srvc) { - struct mwSession *session; - struct mwChannelSet *cs; - struct mwChannel *chan; - - session = mwService_getSession(MW_SERVICE(srvc)); - cs = mwSession_getChannels(session); - chan = mwChannel_newOutgoing(cs); - - mwChannel_setService(chan, MW_SERVICE(srvc)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - return mwChannel_create(chan)? NULL: chan; -} - - -static void start(struct mwService *srvc) { - struct mwServiceStorage *srvc_store; - struct mwChannel *chan; - - g_return_if_fail(srvc != NULL); - srvc_store = (struct mwServiceStorage *) srvc; - - chan = make_channel(srvc_store); - if(chan) { - srvc_store->channel = chan; - } else { - mwService_stopped(srvc); - } -} - - -static void stop(struct mwService *srvc) { - - struct mwServiceStorage *srvc_store; - GList *l; - - g_return_if_fail(srvc != NULL); - srvc_store = (struct mwServiceStorage *) srvc; - - if(srvc_store->channel) { - mwChannel_destroy(srvc_store->channel, ERR_SUCCESS, NULL); - srvc_store->channel = NULL; - } - -#if 1 - /* the new way */ - /* remove pending requests. Sometimes we can crash the storage - service, and when that happens, we end up resending the killer - request over and over again, and the service never stays up */ - for(l = srvc_store->pending; l; l = l->next) - request_free(l->data); - - g_list_free(srvc_store->pending); - srvc_store->pending = NULL; - - srvc_store->id_counter = 0; - -#else - /* the old way */ - /* reset all of the started requests to their unstarted states */ - for(l = srvc_store->pending; l; l = l->next) { - struct mwStorageReq *req = l->data; - - if(req->action == action_loaded) { - req->action = action_load; - } else if(req->action == action_saved) { - req->action = action_save; - } - } -#endif - - mwService_stopped(srvc); -} - - -static void recv_channelAccept(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - struct mwServiceStorage *srvc_stor; - GList *l; - - g_return_if_fail(srvc != NULL); - srvc_stor = (struct mwServiceStorage *) srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc_stor->channel); - - /* send all pending requests */ - for(l = srvc_stor->pending; l; l = l->next) { - struct mwStorageReq *req = l->data; - - if(req->action == action_save || req->action == action_load) { - request_send(chan, req); - } - } - - mwService_started(srvc); -} - - -static void recv_channelDestroy(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - struct mwSession *session; - struct mwServiceStorage *srvc_stor; - - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan != NULL); - - session = mwService_getSession(srvc); - g_return_if_fail(session != NULL); - - srvc_stor = (struct mwServiceStorage *) srvc; - srvc_stor->channel = NULL; - - mwService_stop(srvc); - mwSession_senseService(session, mwService_getType(srvc)); -} - - -static void recv(struct mwService *srvc, struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - /* process into results, trigger callbacks */ - - struct mwGetBuffer *b; - struct mwServiceStorage *srvc_stor; - struct mwStorageReq *req; - guint32 id; - - g_return_if_fail(srvc != NULL); - srvc_stor = (struct mwServiceStorage *) srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc_stor->channel); - g_return_if_fail(data != NULL); - - b = mwGetBuffer_wrap(data); - - id = guint32_peek(b); - req = request_find(srvc_stor, id); - - if(! req) { - g_warning("couldn't find request 0x%x in storage service", id); - mwGetBuffer_free(b); - return; - } - - g_return_if_fail(req->action == type); - request_get(b, req); - - if(mwGetBuffer_error(b)) { - mw_mailme_opaque(data, "storage request 0x%x, type: 0x%x", id, type); - - } else { - request_trigger(srvc_stor, req); - } - - mwGetBuffer_free(b); - request_remove(srvc_stor, req); -} - - -static void clear(struct mwService *srvc) { - struct mwServiceStorage *srvc_stor; - GList *l; - - srvc_stor = (struct mwServiceStorage *) srvc; - - for(l = srvc_stor->pending; l; l = l->next) - request_free(l->data); - - g_list_free(srvc_stor->pending); - srvc_stor->pending = NULL; - - srvc_stor->id_counter = 0; -} - - -struct mwServiceStorage *mwServiceStorage_new(struct mwSession *session) { - struct mwServiceStorage *srvc_store; - struct mwService *srvc; - - srvc_store = g_new0(struct mwServiceStorage, 1); - srvc = MW_SERVICE(srvc_store); - - mwService_init(srvc, session, mwService_STORAGE); - srvc->get_name = get_name; - srvc->get_desc = get_desc; - srvc->recv_accept = recv_channelAccept; - srvc->recv_destroy = recv_channelDestroy; - srvc->recv = recv; - srvc->start = start; - srvc->stop = stop; - srvc->clear = clear; - - return srvc_store; -} - - -struct mwStorageUnit *mwStorageUnit_new(guint32 key) { - struct mwStorageUnit *u; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - return u; -} - - -struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key, - struct mwOpaque *data) { - struct mwStorageUnit *u; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - if(data) - mwOpaque_clone(&u->data, data); - - return u; -} - - -struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key, - gboolean val) { - - return mwStorageUnit_newInteger(key, (guint32) val); -} - - -struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key, - guint32 val) { - struct mwStorageUnit *u; - struct mwPutBuffer *b; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - b = mwPutBuffer_new(); - guint32_put(b, val); - mwPutBuffer_finalize(&u->data, b); - - return u; -} - - -struct mwStorageUnit *mwStorageUnit_newString(guint32 key, - const char *str) { - struct mwStorageUnit *u; - struct mwPutBuffer *b; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - b = mwPutBuffer_new(); - mwString_put(b, str); - mwPutBuffer_finalize(&u->data, b); - - return u; -} - - -guint32 mwStorageUnit_getKey(struct mwStorageUnit *item) { - g_return_val_if_fail(item != NULL, 0x00); /* feh, unsafe */ - return item->key; -} - - -gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *item, - gboolean val) { - - return !! mwStorageUnit_asInteger(item, (guint32) val); -} - - -guint32 mwStorageUnit_asInteger(struct mwStorageUnit *item, - guint32 val) { - struct mwGetBuffer *b; - guint32 v; - - g_return_val_if_fail(item != NULL, val); - - b = mwGetBuffer_wrap(&item->data); - - guint32_get(b, &v); - if(! mwGetBuffer_error(b)) val = v; - mwGetBuffer_free(b); - - return val; -} - - -char *mwStorageUnit_asString(struct mwStorageUnit *item) { - struct mwGetBuffer *b; - char *c = NULL; - - g_return_val_if_fail(item != NULL, NULL); - - b = mwGetBuffer_wrap(&item->data); - - mwString_get(b, &c); - - if(mwGetBuffer_error(b)) - g_debug("error obtaining string value from opaque"); - - mwGetBuffer_free(b); - - return c; -} - - -struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *item) { - g_return_val_if_fail(item != NULL, NULL); - return &item->data; -} - - -void mwStorageUnit_free(struct mwStorageUnit *item) { - if(! item) return; - - mwOpaque_clear(&item->data); - g_free(item); -} - - -static struct mwStorageReq *request_new(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify df) { - - struct mwStorageReq *req = g_new0(struct mwStorageReq, 1); - - req->id = ++srvc->id_counter; - req->item = item; - req->cb = cb; - req->data = data; - req->data_free = df; - - return req; -} - - -void mwServiceStorage_load(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify d_free) { - - /* - construct a request - - put request at end of pending - - if channel is open and connected - - compose the load message - - send message - - set request to sent - - else - - start service - */ - - struct mwStorageReq *req; - - req = request_new(srvc, item, cb, data, d_free); - req->action = action_load; - - srvc->pending = g_list_append(srvc->pending, req); - - if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc))) - request_send(srvc->channel, req); -} - - -void mwServiceStorage_save(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify d_free) { - - /* - construct a request - - put request at end of pending - - if channel is open and connected - - compose the save message - - send message - - set request to sent - - else - - start service - */ - - struct mwStorageReq *req; - - req = request_new(srvc, item, cb, data, d_free); - req->action = action_save; - - srvc->pending = g_list_append(srvc->pending, req); - - if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc))) - request_send(srvc->channel, req); -} - diff -r 921e17c06a1d -r 481560f82468 src/protocols/sametime/meanwhile/st_list.c --- a/src/protocols/sametime/meanwhile/st_list.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,668 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include - -#include "mw_debug.h" -#include "mw_util.h" -#include "mw_st_list.h" - - -struct mwSametimeList { - guint ver_major; - guint ver_minor; - guint ver_micro; - - GList *groups; -}; - - -struct mwSametimeGroup { - struct mwSametimeList *list; - - enum mwSametimeGroupType type; - char *name; - char *alias; - gboolean open; - - GList *users; -}; - - -struct mwSametimeUser { - struct mwSametimeGroup *group; - - enum mwSametimeUserType type; - struct mwIdBlock id; - char *name; - char *alias; -}; - - -static void user_free(struct mwSametimeUser *u) { - struct mwSametimeGroup *g; - - g = u->group; - g->users = g_list_remove(g->users, u); - - mwIdBlock_clear(&u->id); - g_free(u->name); - g_free(u->alias); - g_free(u); -} - - -static void group_free(struct mwSametimeGroup *g) { - struct mwSametimeList *l; - - l = g->list; - l->groups = g_list_remove(l->groups, g); - - while(g->users) - mwSametimeUser_free(g->users->data); - - g_free(g->name); - g_free(g->alias); - g_free(g); -} - - -static void list_free(struct mwSametimeList *l) { - while(l->groups) - mwSametimeGroup_free(l->groups->data); - - g_free(l); -} - - -struct mwSametimeList * -mwSametimeList_new() { - - struct mwSametimeList *stl; - - stl = g_new0(struct mwSametimeList, 1); - stl->ver_major = ST_LIST_MAJOR; - stl->ver_minor = ST_LIST_MINOR; - stl->ver_micro = ST_LIST_MICRO; - - return stl; -} - - -void mwSametimeList_setMajor(struct mwSametimeList *l, guint v) { - g_return_if_fail(l != NULL); - l->ver_major = v; -} - - -guint mwSametimeList_getMajor(struct mwSametimeList *l) { - g_return_val_if_fail(l != NULL, 0); - return l->ver_major; -} - - -void mwSametimeList_setMinor(struct mwSametimeList *l, guint v) { - g_return_if_fail(l != NULL); - l->ver_minor = v; -} - - -guint mwSametimeList_getMinor(struct mwSametimeList *l) { - g_return_val_if_fail(l != NULL, 0); - return l->ver_minor; -} - - -void mwSametimeList_setMicro(struct mwSametimeList *l, guint v) { - g_return_if_fail(l != NULL); - l->ver_micro = v; -} - - -guint mwSametimeList_getMicro(struct mwSametimeList *l) { - g_return_val_if_fail(l != NULL, 0); - return l->ver_micro; -} - - -GList *mwSametimeList_getGroups(struct mwSametimeList *l) { - g_return_val_if_fail(l != NULL, NULL); - return g_list_copy(l->groups); -} - - -struct mwSametimeGroup * -mwSametimeList_findGroup(struct mwSametimeList *l, - const char *name) { - GList *s; - - g_return_val_if_fail(l != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - g_return_val_if_fail(*name != '\0', NULL); - - for(s = l->groups; s; s = s->next) { - struct mwSametimeGroup *g = s->data; - if(! strcmp(g->name, name)) return g; - } - - return NULL; -} - - -void mwSametimeList_free(struct mwSametimeList *l) { - g_return_if_fail(l != NULL); - list_free(l); -} - - -struct mwSametimeGroup * -mwSametimeGroup_new(struct mwSametimeList *list, - enum mwSametimeGroupType type, - const char *name) { - - struct mwSametimeGroup *stg; - - g_return_val_if_fail(list != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - g_return_val_if_fail(*name != '\0', NULL); - - stg = g_new0(struct mwSametimeGroup, 1); - stg->list = list; - stg->type = type; - stg->name = g_strdup(name); - - list->groups = g_list_append(list->groups, stg); - - return stg; -} - - -enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g) { - g_return_val_if_fail(g != NULL, mwSametimeGroup_UNKNOWN); - return g->type; -} - - -const char *mwSametimeGroup_getName(struct mwSametimeGroup *g) { - g_return_val_if_fail(g != NULL, NULL); - return g->name; -} - - -void mwSametimeGroup_setAlias(struct mwSametimeGroup *g, - const char *alias) { - g_return_if_fail(g != NULL); - - g_free(g->alias); - g->alias = g_strdup(alias); -} - - -const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g) { - g_return_val_if_fail(g != NULL, NULL); - return g->alias; -} - - -void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open) { - g_return_if_fail(g != NULL); - g->open = open; -} - - -gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g) { - g_return_val_if_fail(g != NULL, FALSE); - return g->open; -} - - -struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g) { - g_return_val_if_fail(g != NULL, NULL); - return g->list; -} - - -GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g) { - g_return_val_if_fail(g != NULL, NULL); - return g_list_copy(g->users); -} - - -struct mwSametimeUser * -mwSametimeGroup_findUser(struct mwSametimeGroup *g, - struct mwIdBlock *user) { - GList *s; - - g_return_val_if_fail(g != NULL, NULL); - g_return_val_if_fail(user != NULL, NULL); - - for(s = g->users; s; s = s->next) { - struct mwSametimeUser *u = s->data; - if(mwIdBlock_equal(user, &u->id)) return u; - } - - return NULL; -} - - -void mwSametimeGroup_free(struct mwSametimeGroup *g) { - g_return_if_fail(g != NULL); - g_return_if_fail(g->list != NULL); - group_free(g); -} - - -struct mwSametimeUser * -mwSametimeUser_new(struct mwSametimeGroup *group, - enum mwSametimeUserType type, - struct mwIdBlock *id) { - - struct mwSametimeUser *stu; - - g_return_val_if_fail(group != NULL, NULL); - g_return_val_if_fail(id != NULL, NULL); - - stu = g_new0(struct mwSametimeUser, 1); - stu->group = group; - stu->type = type; - mwIdBlock_clone(&stu->id, id); - - group->users = g_list_append(group->users, stu); - - return stu; -} - - -struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u) { - g_return_val_if_fail(u != NULL, NULL); - return u->group; -} - - -enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u) { - g_return_val_if_fail(u != NULL, mwSametimeUser_UNKNOWN); - return u->type; -} - - -const char *mwSametimeUser_getUser(struct mwSametimeUser *u) { - g_return_val_if_fail(u != NULL, NULL); - return u->id.user; -} - - -const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u) { - g_return_val_if_fail(u != NULL, NULL); - return u->id.community; -} - - -void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name) { - g_return_if_fail(u != NULL); - g_free(u->name); - u->name = g_strdup(name); -} - - -const char *mwSametimeUser_getShortName(struct mwSametimeUser *u) { - g_return_val_if_fail(u != NULL, NULL); - return u->name; -} - - -void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias) { - g_return_if_fail(u != NULL); - g_free(u->alias); - u->alias = g_strdup(alias); -} - - -const char *mwSametimeUser_getAlias(struct mwSametimeUser *u) { - g_return_val_if_fail(u != NULL, NULL); - return u->alias; -} - - -void mwSametimeUser_free(struct mwSametimeUser *u) { - g_return_if_fail(u != NULL); - g_return_if_fail(u->group != NULL); - user_free(u); -} - - -static void str_replace(char *str, char from, char to) { - if(! str) return; - for(; *str; str++) if(*str == from) *str = to; -} - - -static char user_type_to_char(enum mwSametimeUserType type) { - switch(type) { - case mwSametimeUser_NORMAL: return '1'; - case mwSametimeUser_EXTERNAL: return '2'; - case mwSametimeUser_UNKNOWN: - default: return '9'; - } -} - - -static enum mwSametimeUserType user_char_to_type(char type) { - switch(type) { - case '1': return mwSametimeUser_NORMAL; - case '2': return mwSametimeUser_EXTERNAL; - default: return mwSametimeUser_UNKNOWN; - } -} - - -static void user_put(GString *str, struct mwSametimeUser *u) { - char *id, *name, *alias; - char type; - - id = g_strdup(u->id.user); - name = g_strdup(u->name); - alias = g_strdup(u->alias); - type = user_type_to_char(u->type); - - if(id) str_replace(id, ' ', ';'); - if(name) str_replace(name, ' ', ';'); - if(alias) str_replace(alias, ' ', ';'); - - if(!name && alias) { - name = alias; - alias = NULL; - } - - g_string_append_printf(str, "U %s%c:: %s,%s\r\n", - id, type, (name? name: ""), (alias? alias: "")); - - g_free(id); - g_free(name); - g_free(alias); -} - - -static char group_type_to_char(enum mwSametimeGroupType type) { - switch(type) { - case mwSametimeGroup_NORMAL: return '2'; - case mwSametimeGroup_DYNAMIC: return '3'; - case mwSametimeGroup_UNKNOWN: - default: return '9'; - } -} - - -static enum mwSametimeGroupType group_char_to_type(char type) { - switch(type) { - case '2': return mwSametimeGroup_NORMAL; - case '3': return mwSametimeGroup_DYNAMIC; - default: return mwSametimeGroup_UNKNOWN; - } -} - - -static void group_put(GString *str, struct mwSametimeGroup *g) { - char *name, *alias; - char type; - GList *gl; - - name = g_strdup(g->name); - alias = g_strdup((g->alias)? g->alias: name); - type = group_type_to_char(g->type); - - str_replace(name, ' ', ';'); - str_replace(alias, ' ', ';'); - - g_string_append_printf(str, "G %s%c %s %c\r\n", - name, type, alias, (g->open? 'O':'C')); - - for(gl = g->users; gl; gl = gl->next) { - user_put(str, gl->data); - } - - g_free(name); - g_free(alias); -} - - -/** composes a GString with the written contents of a sametime list */ -static GString *list_store(struct mwSametimeList *l) { - GString *str; - GList *gl; - - g_return_val_if_fail(l != NULL, NULL); - - str = g_string_new(NULL); - g_string_append_printf(str, "Version=%u.%u.%u\r\n", - l->ver_major, l->ver_minor, l->ver_micro); - - for(gl = l->groups; gl; gl = gl->next) { - group_put(str, gl->data); - } - - return str; -} - - -char *mwSametimeList_store(struct mwSametimeList *l) { - GString *str; - char *s; - - g_return_val_if_fail(l != NULL, NULL); - - str = list_store(l); - s = str->str; - g_string_free(str, FALSE); - return s; -} - - -void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l) { - GString *str; - guint16 len; - - g_return_if_fail(l != NULL); - g_return_if_fail(b != NULL); - - str = list_store(l); - len = (guint16) str->len; - guint16_put(b, len); - mwPutBuffer_write(b, str->str, len); - - g_string_free(str, TRUE); -} - - -static void get_version(const char *line, struct mwSametimeList *l) { - guint major = 0, minor = 0, micro = 0; - int ret; - - ret = sscanf(line, "Version=%u.%u.%u\n", &major, &minor, µ); - if(ret != 3) { - g_warning("strange sametime list version line:\n%s", line); - } - - l->ver_major = major; - l->ver_minor = minor; - l->ver_micro = micro; -} - - -static struct mwSametimeGroup *get_group(const char *line, - struct mwSametimeList *l) { - struct mwSametimeGroup *group; - char *name, *alias; - char type = '2', open = 'O'; - int ret; - - ret = strlen(line); - name = g_malloc0(ret); - alias = g_malloc0(ret); - - ret = sscanf(line, "G %s %s %c\n", - name, alias, &open); - - if(ret < 3) { - g_warning("strange sametime list group line:\n%s", line); - } - - str_replace(name, ';', ' '); - str_replace(alias, ';', ' '); - - if(name && *name) { - int l = strlen(name)-1; - type = name[l]; - name[l] = '\0'; - } - - group = g_new0(struct mwSametimeGroup, 1); - group->list = l; - group->name = name; - group->type = group_char_to_type(type); - group->alias = alias; - group->open = (open == 'O'); - - l->groups = g_list_append(l->groups, group); - - return group; -} - - -static void get_user(const char *line, struct mwSametimeGroup *g) { - struct mwSametimeUser *user; - struct mwIdBlock idb = { 0, 0 }; - char *name, *alias = NULL; - char type = '1'; - int ret; - - ret = strlen(line); - idb.user = g_malloc0(ret); - name = g_malloc0(ret); - - ret = sscanf(line, "U %s %s", - idb.user, name); - - if(ret < 2) { - g_warning("strange sametime list user line:\n%s", line); - } - - str_replace(idb.user, ';', ' '); - str_replace(name, ';', ' '); - - if(idb.user && *idb.user) { - char *tmp = strstr(idb.user, "::"); - if(tmp--) { - type = *(tmp); - *tmp = '\0'; - } - } - - if(name && *name) { - char *tmp = strrchr(name, ','); - if(tmp) { - *tmp++ = '\0'; - if(*tmp) alias = tmp; - } - } - - user = g_new0(struct mwSametimeUser, 1); - user->group = g; - user->id.user = idb.user; - user->type = user_char_to_type(type); - user->name = name; - user->alias = g_strdup(alias); - - g->users = g_list_append(g->users, user); -} - - -/** returns a line from str, and advances str */ -static char *fetch_line(char **str) { - char *start = *str; - char *end; - - /* move to first non-whitespace character */ - while(*start && g_ascii_isspace(*start)) start++; - if(! *start) return NULL; - - for(end = start + 1; *end; end++) { - if(*end == '\n' || *end == '\r') { - *(end++) = '\0'; - break; - } - } - - *str = end; - return start; -} - - -void list_get(const char *lines, struct mwSametimeList *l) { - char *s = (char *) lines; - char *line; - - struct mwSametimeGroup *g = NULL; - - while( (line = fetch_line(&s)) ) { - switch(*line) { - case 'V': - get_version(line, l); - break; - - case 'G': - g = get_group(line, l); - break; - - case 'U': - get_user(line, g); - break; - - default: - g_warning("unknown sametime list data line:\n%s", line); - } - } -} - - -struct mwSametimeList *mwSametimeList_load(const char *data) { - struct mwSametimeList *l; - - g_return_val_if_fail(data != NULL, NULL); - - l = mwSametimeList_new(); - list_get(data, l); - - return l; -} - - -void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l) { - char *str = NULL; - - g_return_if_fail(l != NULL); - g_return_if_fail(b != NULL); - - mwString_get(b, &str); - list_get(str, l); - g_free(str); -} -