diff --git a/samples/logging_proxy.c b/samples/logging_proxy.c index dc22740..26a7d96 100644 --- a/samples/logging_proxy.c +++ b/samples/logging_proxy.c @@ -25,6 +25,7 @@ #include #include +#include #include #include diff --git a/samples/logging_proxy.c.fix-glib-headers b/samples/logging_proxy.c.fix-glib-headers deleted file mode 100644 index 26a7d96..0000000 --- a/samples/logging_proxy.c.fix-glib-headers +++ /dev/null @@ -1,1004 +0,0 @@ - -/* - Logging Sametime Proxy Utility - The Meanwhile Project - - This is a tool which can act as a proxy between a client and a - sametime server, which will log all messages to stdout. It will also - munge channel creation messages in order to be able to decrypt any - encrypted data sent over a channel, and will log decrypted chunks to - stdout as well. This makes reverse-engineering of services much, - much easier. - - The idea is simple, but the implementation made my head hurt. - - Christopher O'Brien -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - - -/** one side of the proxy (either the client side or the server - side). The forward method for one should push data into the socket - of the other. */ -struct proxy_side { - int sock; - GIOChannel *chan; - gint chan_io; - - guchar *buf; - gsize buf_size; - gsize buf_recv; - - void (*forward)(const guchar *buf, gsize len); -}; - - -static struct proxy_side client; /**< side facing the client */ -static struct proxy_side server; /**< side facing the server */ - - -static char *host = NULL; -static int client_port = 0; -static int server_port = 0; - - -static int counter = 0; -static int listen_sock = 0; -static GIOChannel *listen_chan = NULL; -static gint listen_io = 0; - - - - - -/** given one side, get the other */ -#define OTHER_SIDE(side) \ - ((side == &client)? &server: &client) - - -/** encryption state information used in the RC2/40 cipher */ -struct rc2_40enc { - guchar outgoing_iv[8]; - int outgoing_key[64]; - guchar incoming_iv[8]; - int incoming_key[64]; -}; - - -/* re-usable rc2 40 stuff */ -static int session_key[64] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - - -/** encryption state information used in the RC2/128 cipher */ -struct rc2_128enc { - guchar outgoing_iv[8]; - guchar incoming_iv[8]; - int shared_key[64]; -}; - - -/* re-usable rc2 128 stuff */ -static struct mwMpi *private_key; -static struct mwOpaque public_key; - - -/** represents a channel. The channel has a left side and a right - side. The left side is the creator of the channel. The right side - is the target of the channel. Each side has its own encryption - state information, so an incoming message from either side can - be decrypted, then re-encrypted for the other side. */ -struct channel { - guint32 id; - - /* login id of creator or NULL if created by client side */ - char *creator; - - /* the offer from the left side */ - struct mwEncryptOffer offer; - - /** the mode of encryption */ - enum { - enc_none = 0, /**< nothing encrypted */ - enc_easy, /**< easy (rc2/40) encryption */ - enc_hard, /**< hard (rc2/128) encryption */ - } enc_mode; - - /** encryption data for the left side */ - union { - struct rc2_40enc easy; - struct rc2_128enc hard; - } left_enc; - - /** encryption data for the right side */ - union { - struct rc2_40enc easy; - struct rc2_128enc hard; - } right_enc; - - struct proxy_side *left; /**< proxy side acting as the left side */ - struct proxy_side *right; /**< proxy side acting as the right side */ -}; - - -/* collection of channels */ -static GHashTable *channels; - - -#define PUT_CHANNEL(chan) \ - g_hash_table_insert(channels, GUINT_TO_POINTER((chan)->id), (chan)) - -#define GET_CHANNEL(id) \ - g_hash_table_lookup(channels, GUINT_TO_POINTER(id)) - -#define REMOVE_CHANNEL(id) \ - g_hash_table_remove(channels, GUINT_TO_POINTER(id)) - - -/** print a message to stdout and use hexdump to print a data chunk */ -static void hexdump_vprintf(const guchar *buf, gsize len, - const char *txt, va_list args) { - FILE *fp; - - if(txt) { - fputc('\n', stdout); - vfprintf(stdout, txt, args); - fputc('\n', stdout); - } - fflush(stdout); - - fp = popen("hexdump -C", "w"); - fwrite(buf, len, 1, fp); - fflush(fp); - pclose(fp); -} - - -/** print a message to stdout and use hexdump to print a data chunk */ -static void hexdump_printf(const guchar *buf, gsize len, - const char *txt, ...) { - va_list args; - va_start(args, txt); - hexdump_vprintf(buf, len, txt, args); - va_end(args); -} - - -/** serialize a message for sending */ -static void put_msg(struct mwMessage *msg, struct mwOpaque *o) { - struct mwPutBuffer *b; - - b = mwPutBuffer_new(); - mwMessage_put(b, msg); - mwPutBuffer_finalize(o, b); - - b = mwPutBuffer_new(); - mwOpaque_put(b, o); - mwOpaque_clear(o); - mwPutBuffer_finalize(o, b); -} - - -static void key_copy(int to[64], int from[64]) { - int i = 64; - while(i--) to[i] = from[i]; -} - - -/* we don't want to be redirected away from the proxy, so eat any - redirect messages from the server and respond with a login cont */ -static void munge_redir() { - struct mwMessage *msg; - struct mwOpaque o = { 0, 0 }; - - msg = mwMessage_new(mwMessage_LOGIN_CONTINUE); - put_msg(msg, &o); - mwMessage_free(msg); - - server.forward(o.data, o.len); - - mwOpaque_clear(&o); -} - - -/* handle receipt of channel create messages from either side, - recording the offered ciphers, and munging it to instead include - our own key as applicable, then sending it on */ -static void munge_create(struct proxy_side *side, - struct mwMsgChannelCreate *msg) { - - struct mwOpaque o = { 0, 0 }; - GList *l; - struct channel *c; - - /* create a new channel on the side */ - c = g_new0(struct channel, 1); - c->id = msg->channel; - c->left = side; - c->right = OTHER_SIDE(side); - - if(msg->creator_flag) { - c->creator = g_strdup(msg->creator.login_id); - } - - /* record the mode and encryption items */ - c->offer.mode = msg->encrypt.mode; - c->offer.items = msg->encrypt.items; - c->offer.extra = msg->encrypt.extra; - c->offer.flag = msg->encrypt.flag; - - PUT_CHANNEL(c); - - /* replace the encryption items with our own as applicable */ - if(msg->encrypt.items) { - l = msg->encrypt.items; - msg->encrypt.items = NULL; /* steal them */ - - for(; l; l = l->next) { - struct mwEncryptItem *i1, *i2; - - /* the original we've stolen */ - i1 = l->data; - - /* the munged replacement */ - i2 = g_new0(struct mwEncryptItem, 1); - i2->id = i1->id; - - switch(i1->id) { - case mwCipher_RC2_128: - printf("munging an offered RC2/128\n"); - mwOpaque_clone(&i2->info, &public_key); - break; - case mwCipher_RC2_40: - printf("munging an offered RC2/40\n"); - default: - ; - } - - msg->encrypt.items = g_list_append(msg->encrypt.items, i2); - } - } - - put_msg(MW_MESSAGE(msg), &o); - side->forward(o.data, o.len); - mwOpaque_clear(&o); -} - - -/* find an enc item by id in a list of items */ -struct mwEncryptItem *find_item(GList *items, guint16 id) { - GList *ltmp; - for(ltmp = items; ltmp; ltmp = ltmp->next) { - struct mwEncryptItem *i = ltmp->data; - if(i->id == id) return i; - } - return NULL; -} - - -/* handle acceptance of a channel */ -static void munge_accept(struct proxy_side *side, - struct mwMsgChannelAccept *msg) { - - struct mwOpaque o = {0,0}; - struct channel *chan; - struct mwEncryptItem *item; - - chan = GET_CHANNEL(msg->head.channel); - item = msg->encrypt.item; - - if(! item) { - /* cut to the chase */ - put_msg(MW_MESSAGE(msg), &o); - side->forward(o.data, o.len); - mwOpaque_clear(&o); - return; - } - - /* init right-side encryption with our enc and accepted enc */ - switch(item->id) { - case mwCipher_RC2_128: { - struct mwMpi *remote, *shared; - struct mwOpaque k; - - remote = mwMpi_new(); - shared = mwMpi_new(); - - printf("right side accepted RC2/128\n"); - - mwMpi_import(remote, &item->info); - mwMpi_calculateDHShared(shared, remote, private_key); - mwMpi_export(shared, &k); - - chan->enc_mode = enc_hard; - - mwIV_init(chan->right_enc.hard.outgoing_iv); - mwIV_init(chan->right_enc.hard.incoming_iv); - mwKeyExpand(chan->right_enc.hard.shared_key, k.data+(k.len-16), 16); - - mwMpi_free(remote); - mwMpi_free(shared); - mwOpaque_clear(&k); - break; - } - case mwCipher_RC2_40: { - char *who; - - printf("right side accepted RC2/40\n"); - - chan->enc_mode = enc_easy; - - mwIV_init(chan->right_enc.easy.outgoing_iv); - mwIV_init(chan->right_enc.easy.incoming_iv); - - if(msg->acceptor_flag) { - who = msg->acceptor.login_id; - printf("right side is the server\n"); - printf("server is %s\n", who); - mwKeyExpand(chan->right_enc.easy.incoming_key, (guchar *) who, 5); - key_copy(chan->right_enc.easy.outgoing_key, session_key); - - } else { - who = chan->creator; - printf("right side is the client\n"); - printf("server is %s\n", who); - key_copy(chan->right_enc.easy.incoming_key, session_key); - mwKeyExpand(chan->right_enc.easy.outgoing_key, (guchar *) who, 5); - } - - break; - } - default: - chan->enc_mode = enc_none; - break; - } - - /* init left-side encryption with offered enc and our enc, munge accept */ - switch(item->id) { - case mwCipher_RC2_128: { - struct mwMpi *remote, *shared; - struct mwOpaque k; - struct mwEncryptItem *offered; - - remote = mwMpi_new(); - shared = mwMpi_new(); - - printf("accepting left side with RC2/128\n"); - - offered = find_item(chan->offer.items, mwCipher_RC2_128); - mwMpi_import(remote, &offered->info); - mwMpi_calculateDHShared(shared, remote, private_key); - mwMpi_export(shared, &k); - - mwIV_init(chan->left_enc.hard.outgoing_iv); - mwIV_init(chan->left_enc.hard.incoming_iv); - mwKeyExpand(chan->left_enc.hard.shared_key, k.data+(k.len-16), 16); - - mwMpi_free(remote); - mwMpi_free(shared); - mwOpaque_clear(&k); - - /* munge accept with out public key */ - mwOpaque_clear(&item->info); - mwOpaque_clone(&item->info, &public_key); - break; - } - case mwCipher_RC2_40: - printf("accepting left side with RC2/40\n"); - - mwIV_init(chan->left_enc.easy.outgoing_iv); - mwIV_init(chan->left_enc.easy.incoming_iv); - - key_copy(chan->left_enc.easy.outgoing_key, - chan->right_enc.easy.incoming_key); - - key_copy(chan->left_enc.easy.incoming_key, - chan->right_enc.easy.outgoing_key); - break; - - default: - ; - } - - put_msg(MW_MESSAGE(msg), &o); - side->forward(o.data, o.len); - mwOpaque_clear(&o); -} - - -static void dec(struct channel *chan, struct proxy_side *side, - struct mwOpaque *to, struct mwOpaque *from) { - - switch(chan->enc_mode) { - case enc_easy: { - if(chan->left == side) { - /* left side decrypt */ - mwDecryptExpanded(chan->left_enc.easy.incoming_key, - chan->left_enc.easy.incoming_iv, - from, to); - } else { - /* right side decrypt */ - mwDecryptExpanded(chan->right_enc.easy.incoming_key, - chan->right_enc.easy.incoming_iv, - from, to); - } - break; - } - case enc_hard: { - if(chan->left == side) { - /* left side decrypt */ - mwDecryptExpanded(chan->left_enc.hard.shared_key, - chan->left_enc.hard.incoming_iv, - from, to); - } else { - /* right side decrypt */ - mwDecryptExpanded(chan->right_enc.hard.shared_key, - chan->right_enc.hard.incoming_iv, - from, to); - } - break; - } - } -} - - -static void enc(struct channel *chan, struct proxy_side *side, - struct mwOpaque *to, struct mwOpaque *from) { - - switch(chan->enc_mode) { - case enc_easy: { - if(chan->left == side) { - /* left side encrypt */ - mwEncryptExpanded(chan->left_enc.easy.outgoing_key, - chan->left_enc.easy.outgoing_iv, - from, to); - } else { - /* right side encrypt */ - mwEncryptExpanded(chan->right_enc.easy.outgoing_key, - chan->right_enc.easy.outgoing_iv, - from, to); - } - break; - } - case enc_hard: { - if(chan->left == side) { - /* left side encrypt */ - mwEncryptExpanded(chan->left_enc.hard.shared_key, - chan->left_enc.hard.outgoing_iv, - from, to); - } else { - /* right side encrypt */ - mwEncryptExpanded(chan->right_enc.hard.shared_key, - chan->right_enc.hard.outgoing_iv, - from, to); - } - break; - } - } -} - - -static void munge_channel(struct proxy_side *side, - struct mwMsgChannelSend *msg) { - - struct mwOpaque o = {0,0}; - - if(msg->head.options & mwMessageOption_ENCRYPT) { - struct mwOpaque d = {0,0}; - struct channel *chan; - - chan = GET_CHANNEL(msg->head.channel); - - /* decrypt from side */ - dec(chan, side, &d, &msg->data); - - /* display */ - hexdump_printf(d.data, d.len, "decrypted channel message data:", - msg->type); - - /* encrypt to other side */ - mwOpaque_clear(&msg->data); - enc(chan, OTHER_SIDE(side), &msg->data, &d); - mwOpaque_clear(&d); - } - - /* send to other side */ - put_msg(MW_MESSAGE(msg), &o); - side->forward(o.data, o.len); - mwOpaque_clear(&o); -} - - -/* handle destruction of a channel */ -static void handle_destroy(struct proxy_side *side, - struct mwMsgChannelDestroy *msg) { - - struct channel *chan; - GList *l; - - chan = GET_CHANNEL(msg->head.channel); - REMOVE_CHANNEL(msg->head.channel); - - if(! chan) return; - - for(l = chan->offer.items; l; l = l->next) { - mwEncryptItem_free(l->data); - } - g_list_free(chan->offer.items); - chan->offer.items = NULL; - - g_free(chan->creator); - chan->creator = NULL; - - g_free(chan); -} - - -static void forward(struct proxy_side *to, - struct mwOpaque *data) { - - struct mwPutBuffer *pb = mwPutBuffer_new(); - struct mwOpaque po = { 0, 0 }; - - mwOpaque_put(pb, data); - mwPutBuffer_finalize(&po, pb); - to->forward(po.data, po.len); - mwOpaque_clear(&po); -} - - -/* handle messages from either side */ -static void side_process(struct proxy_side *s, const guchar *buf, gsize len) { - struct mwOpaque o = { .len = len, .data = (guchar *) buf }; - struct mwGetBuffer *b; - guint16 type; - - if(! len) return; - - if(s == &server) { - hexdump_printf(buf, len, "server -> client"); - } else { - hexdump_printf(buf, len, "client -> server"); - } - - b = mwGetBuffer_wrap(&o); - type = guint16_peek(b); - - switch(type) { - case mwMessage_LOGIN_ACK: { - struct mwMsgLoginAck *msg = (struct mwMsgLoginAck *) mwMessage_get(b); - printf("client is %s\n", msg->login.login_id); - mwKeyExpand(session_key, (guchar *) msg->login.login_id, 5); - mwMessage_free(MW_MESSAGE(msg)); - forward(s, &o); - break; - } - - case mwMessage_LOGIN_REDIRECT: { - munge_redir(); - break; - } - - case mwMessage_CHANNEL_CREATE: { - struct mwMessage *msg = mwMessage_get(b); - munge_create(s, (struct mwMsgChannelCreate *) msg); - mwMessage_free(msg); - break; - } - - case mwMessage_CHANNEL_ACCEPT: { - struct mwMessage *msg = mwMessage_get(b); - munge_accept(s, (struct mwMsgChannelAccept *) msg); - mwMessage_free(msg); - break; - } - - case mwMessage_CHANNEL_DESTROY: { - struct mwMessage *msg = mwMessage_get(b); - handle_destroy(s, (struct mwMsgChannelDestroy *) msg); - mwMessage_free(msg); - forward(s, &o); - break; - } - - case mwMessage_CHANNEL_SEND: { - struct mwMessage *msg = mwMessage_get(b); - munge_channel(s, (struct mwMsgChannelSend *) msg); - mwMessage_free(msg); - break; - } - - default: - forward(s, &o); - } - - mwGetBuffer_free(b); -} - - -/** clean up a proxy side's inner buffer */ -static void side_buf_free(struct proxy_side *s) { - g_free(s->buf); - s->buf = NULL; - s->buf_size = 0; - s->buf_recv = 0; -} - - -#define ADVANCE(b, n, count) { b += count; n -= count; } - - -/** handle input to complete an existing buffer */ -static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) { - - gsize x = s->buf_size - s->buf_recv; - - if(n < x) { - memcpy(s->buf+s->buf_recv, b, n); - s->buf_recv += n; - return 0; - - } else { - memcpy(s->buf+s->buf_recv, b, x); - ADVANCE(b, n, x); - - if(s->buf_size == 4) { - struct mwOpaque o = { .len = 4, .data = s->buf }; - struct mwGetBuffer *gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - - if(n < x) { - guchar *t; - x += 4; - t = (guchar *) g_malloc(x); - memcpy(t, s->buf, 4); - memcpy(t+4, b, n); - - side_buf_free(s); - - s->buf = t; - s->buf_size = x; - s->buf_recv = n + 4; - return 0; - - } else { - side_buf_free(s); - side_process(s, b, x); - ADVANCE(b, n, x); - } - - } else { - side_process(s, s->buf+4, s->buf_size-4); - side_buf_free(s); - } - } - - return n; -} - - -/** handle input when there's nothing previously buffered */ -static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) { - struct mwOpaque o = { .len = n, .data = (guchar *) b }; - struct mwGetBuffer *gb; - gsize x; - - if(n < 4) { - s->buf = (guchar *) g_malloc0(4); - memcpy(s->buf, b, n); - s->buf_size = 4; - s->buf_recv = n; - return 0; - } - - gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - if(! x) return n - 4; - - if(n < (x + 4)) { - - x += 4; - s->buf = (guchar *) g_malloc(x); - memcpy(s->buf, b, n); - s->buf_size = x; - s->buf_recv = n; - return 0; - - } else { - ADVANCE(b, n, 4); - side_process(s, b, x); - ADVANCE(b, n, x); - - return n; - } -} - - -/** handle input in chunks */ -static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) { - - if(n && (s->buf_size == 0) && (*b & 0x80)) { - ADVANCE(b, n, 1); - } - - if(n == 0) { - return 0; - - } else if(s->buf_size > 0) { - return side_recv_cont(s, b, n); - - } else { - return side_recv_empty(s, b, n); - } -} - - -/** handle input */ -static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) { - guchar *b = (guchar *) buf; - gsize remain = 0; - - g_return_if_fail(side != NULL); - - while(n > 0) { - remain = side_recv(side, b, n); - b += (n - remain); - n = remain; - } -} - - -static int read_recv(struct proxy_side *side) { - guchar buf[2048]; - int len; - - len = read(side->sock, buf, 2048); - if(len > 0) feed_buf(side, buf, (gsize) len); - - return len; -} - - -static void init_listen(); - - -static void side_done(struct proxy_side *side) { - if(side->sock) { - g_source_remove(side->chan_io); - close(side->sock); - side->sock = 0; - side->chan = NULL; - side->chan_io = 0; - } -} - - -static void done() { - printf("closing connection\n"); - - side_done(&client); - side_done(&server); - - if(counter--) { - init_listen(); - } else { - exit(0); - } -} - - -static gboolean read_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - - struct proxy_side *side = data; - int ret = 0; - - if(cond & G_IO_IN) { - ret = read_recv(side); - if(ret > 0) return TRUE; - } - - done(); - - return FALSE; -} - - -static void client_cb(const guchar *buf, gsize len) { - if(server.sock) write(server.sock, buf, len); -} - - -/** setup the client */ -static void init_client(int sock) { - - client.forward = client_cb; - client.sock = sock; - client.chan = g_io_channel_unix_new(sock); - client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - read_cb, &client); -} - - -static void server_cb(const guchar *buf, gsize len) { - if(client.sock) write(client.sock, buf, len); -} - - -/** generate a private/public DH keypair for internal (re)use */ -static void init_rc2_128() { - struct mwMpi *public; - - private_key = mwMpi_new(); - public = mwMpi_new(); - - mwMpi_randDHKeypair(private_key, public); - mwMpi_export(public, &public_key); - - mwMpi_free(public); -} - - -/** address lookup used by init_sock */ -static void init_sockaddr(struct sockaddr_in *addr, - const char *host, int port) { - - struct hostent *hostinfo; - - addr->sin_family = AF_INET; - addr->sin_port = htons (port); - hostinfo = gethostbyname(host); - if(hostinfo == NULL) { - fprintf(stderr, "Unknown host %s.\n", host); - exit(1); - } - addr->sin_addr = *(struct in_addr *) hostinfo->h_addr; -} - - -/** connect to server on host:port */ -static void init_server() { - struct sockaddr_in srvrname; - int sock; - - printf("connecting to %s:%i\n", host, server_port); - - sock = socket(PF_INET, SOCK_STREAM, 0); - if(sock < 0) { - fprintf(stderr, "socket failure"); - exit(1); - } - - init_sockaddr(&srvrname, host, server_port); - connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname)); - - server.forward = server_cb; - server.sock = sock; - server.chan = g_io_channel_unix_new(sock); - server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - read_cb, &server); - - printf("connected to %s:%i\n", host, server_port); -} - - - -static gboolean listen_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - - struct sockaddr_in rem; - guint len = sizeof(rem); - int sock; - - printf("got connection\n"); - - sock = accept(listen_sock, (struct sockaddr *) &rem, &len); - /* g_assert(sock > 0); */ - - init_server(); - init_client(sock); - - listen_io = 0; - - return FALSE; -} - - -static void init_listen() { - if(! listen_sock) { - struct sockaddr_in sin; - int sock; - - sock = socket(PF_INET, SOCK_STREAM, 0); - g_assert(sock >= 0); - - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = PF_INET; - sin.sin_port = htons(client_port); - sin.sin_addr.s_addr = htonl(INADDR_ANY); - - if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - g_assert_not_reached(); - - if(listen(sock, 1) < 0) - g_assert_not_reached(); - - listen_sock = sock; - listen_chan = g_io_channel_unix_new(sock); - } - - if(! listen_io) { - listen_io = g_io_add_watch(listen_chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - listen_cb, NULL); - printf("listening on port %i\n", client_port); - } -} - - -int main(int argc, char *argv[]) { - - memset(&client, 0, sizeof(struct proxy_side)); - memset(&server, 0, sizeof(struct proxy_side)); - - if(argc > 1) { - char *z; - - host = argv[1]; - z = host; - - host = strchr(z, ':'); - if(host) *host++ = '\0'; - client_port = atoi(z); - - z = strchr(host, ':'); - if(z) *z++ = '\0'; - server_port = atoi(z); - } - - if(argc > 2) { - counter = atoi(argv[2]); - } - - if(!host || !*host || !client_port || !server_port) { - fprintf(stderr, - ( " Usage: %s local_port:remote_host:remote_port [n]\n" - " Creates a locally-running sametime proxy which enforces" - " unencrypted channels. Will drop the first n connections\n" ), - argv[0]); - exit(1); - } - - /* @todo create signal handlers to cleanup sockets */ - - channels = g_hash_table_new(g_direct_hash, g_direct_equal); - - init_rc2_128(); - init_listen(); - - g_main_loop_run(g_main_loop_new(NULL, FALSE)); - return 0; -} - diff --git a/samples/login_server.c b/samples/login_server.c index 43380d3..3264467 100644 --- a/samples/login_server.c +++ b/samples/login_server.c @@ -19,6 +19,7 @@ #include #include +#include #include #include diff --git a/samples/login_server.c.fix-glib-headers b/samples/login_server.c.fix-glib-headers deleted file mode 100644 index 3264467..0000000 --- a/samples/login_server.c.fix-glib-headers +++ /dev/null @@ -1,421 +0,0 @@ - -/* - Login-parsing Faux Server - The Meanwhile Project - - This is a tool to aide in reverse engineering different types of - authentication schemes. - - Christopher O'Brien -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - - -/** the server socket or the connected socket */ -static int sock; - -/** the io channel */ -static GIOChannel *chan; - -/** the listening event on the io channel */ -static int chan_io; - - -static guchar *sbuf; -static gsize sbuf_size; -static gsize sbuf_recv; - - -struct mwMpi *private, *public; - - -static void hexout(const char *txt, const guchar *buf, gsize len) { - FILE *fp; - - if(txt) fprintf(stdout, "\n%s\n", txt); - fflush(stdout); - - fp = popen("hexdump -C", "w"); - fwrite(buf, len, 1, fp); - fflush(fp); - pclose(fp); -} - - -static void send_msg(struct mwMessage *msg) { - struct mwPutBuffer *b; - struct mwOpaque o = { 0, 0 }; - - b = mwPutBuffer_new(); - mwMessage_put(b, msg); - mwPutBuffer_finalize(&o, b); - - b = mwPutBuffer_new(); - mwOpaque_put(b, &o); - mwOpaque_clear(&o); - mwPutBuffer_finalize(&o, b); - - if(sock) write(sock, o.data, o.len); - - hexout("sent:", o.data, o.len); - - mwOpaque_clear(&o); -} - - -static void handshake_ack() { - struct mwMsgHandshakeAck *msg; - - msg = (struct mwMsgHandshakeAck *) - mwMessage_new(mwMessage_HANDSHAKE_ACK); - - msg->major = 0x1e; - msg->minor = 0x1d; - - mwMpi_randDHKeypair(private, public); - mwMpi_export(public, &msg->data); - - msg->magic = 0x01234567; - hexout("sending pubkey:", msg->data.data, msg->data.len); - - send_msg(MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); -} - - -static void handle_login(struct mwMsgLogin *msg) { - struct mwGetBuffer *gb; - struct mwOpaque a, b, c; - guint16 z; - struct mwMpi *remote, *shared; - guchar iv[8]; - - remote = mwMpi_new(); - shared = mwMpi_new(); - - mwIV_init(iv); - - gb = mwGetBuffer_wrap(&msg->auth_data); - guint16_get(gb, &z); - mwOpaque_get(gb, &a); - mwOpaque_get(gb, &b); - mwGetBuffer_free(gb); - - mwMpi_import(remote, &a); - mwOpaque_clear(&a); - - mwMpi_calculateDHShared(shared, remote, private); - mwMpi_export(shared, &a); - hexout("shared key:", a.data, a.len); - - mwDecrypt(a.data+(a.len-16), 16, iv, &b, &c); - hexout("decrypted to:", c.data, c.len); - - mwOpaque_clear(&a); - mwOpaque_clear(&b); - mwOpaque_clear(&c); - - mwMpi_free(remote); - mwMpi_free(shared); -} - - -static void done() { - close(sock); - exit(0); -} - - -static void side_process(const guchar *buf, gsize len) { - struct mwOpaque o = { .len = len, .data = (guchar *) buf }; - struct mwGetBuffer *b; - guint16 type; - - if(! len) return; - - b = mwGetBuffer_wrap(&o); - type = guint16_peek(b); - - hexout("received:", buf, len); - - switch(type) { - case mwMessage_HANDSHAKE: - printf("got handshake, sending handshake_ack\n"); - handshake_ack(); - break; - - case mwMessage_LOGIN: - printf("got login, attempting to decipher\n"); - { - struct mwMsgLogin *msg = (struct mwMsgLogin *) mwMessage_get(b); - handle_login(msg); - mwMessage_free(MW_MESSAGE(msg)); - done(); - } - break; - - case mwMessage_CHANNEL_DESTROY: - printf("channel destroy\n"); - done(); - break; - - default: - ; - } - - mwGetBuffer_free(b); -} - - -static void sbuf_free() { - g_free(sbuf); - sbuf = NULL; - sbuf_size = 0; - sbuf_recv = 0; -} - - -#define ADVANCE(b, n, count) { b += count; n -= count; } - - -/* handle input to complete an existing buffer */ -static gsize side_recv_cont(const guchar *b, gsize n) { - - gsize x = sbuf_size - sbuf_recv; - - if(n < x) { - memcpy(sbuf + sbuf_recv, b, n); - sbuf_recv += n; - return 0; - - } else { - memcpy(sbuf + sbuf_recv, b, x); - ADVANCE(b, n, x); - - if(sbuf_size == 4) { - struct mwOpaque o = { .len = 4, .data = sbuf }; - struct mwGetBuffer *gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - - if(n < x) { - guchar *t; - x += 4; - t = (guchar *) g_malloc(x); - memcpy(t, sbuf, 4); - memcpy(t+4, b, n); - - sbuf_free(); - - sbuf = t; - sbuf_size = x; - sbuf_recv = n + 4; - return 0; - - } else { - sbuf_free(); - side_process(b, x); - ADVANCE(b, n, x); - } - - } else { - side_process(sbuf+4, sbuf_size-4); - sbuf_free(); - } - } - - return n; -} - - -/* handle input when there's nothing previously buffered */ -static gsize side_recv_empty(const guchar *b, gsize n) { - struct mwOpaque o = { .len = n, .data = (guchar *) b }; - struct mwGetBuffer *gb; - gsize x; - - if(n < 4) { - sbuf = (guchar *) g_malloc0(4); - memcpy(sbuf, b, n); - sbuf_size = 4; - sbuf_recv = n; - return 0; - } - - gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - if(! x) return n - 4; - - if(n < (x + 4)) { - - x += 4; - sbuf = (guchar *) g_malloc(x); - memcpy(sbuf, b, n); - sbuf_size = x; - sbuf_recv = n; - return 0; - - } else { - ADVANCE(b, n, 4); - side_process(b, x); - ADVANCE(b, n, x); - - return n; - } -} - - -static gsize side_recv(const guchar *b, gsize n) { - - if(n && (sbuf_size == 0) && (*b & 0x80)) { - ADVANCE(b, n, 1); - } - - if(n == 0) { - return 0; - - } else if(sbuf_size > 0) { - return side_recv_cont(b, n); - - } else { - return side_recv_empty(b, n); - } -} - - -static void feed_buf(const guchar *buf, gsize n) { - guchar *b = (guchar *) buf; - gsize remain = 0; - - while(n > 0) { - remain = side_recv(b, n); - b += (n - remain); - n = remain; - } -} - - -static int read_recv() { - guchar buf[2048]; - int len; - - len = read(sock, buf, 2048); - if(len > 0) feed_buf(buf, (gsize) len); - - return len; -} - - -static gboolean read_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - int ret = 0; - - if(cond & G_IO_IN) { - ret = read_recv(); - if(ret > 0) return TRUE; - } - - if(sock) { - g_source_remove(chan_io); - close(sock); - sock = 0; - chan = NULL; - chan_io = 0; - } - - done(); - - return FALSE; -} - - -static gboolean listen_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - - struct sockaddr_in rem; - guint len = sizeof(rem); - - printf("accepting connection\n"); - - sock = accept(sock, (struct sockaddr *) &rem, &len); - g_assert(sock > 0); - - g_source_remove(chan_io); - chan = g_io_channel_unix_new(sock); - chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - read_cb, NULL); - - return FALSE; -} - - -static void init_socket(int port) { - /* start listening on the local port specifier */ - - struct sockaddr_in sin; - - sock = socket(PF_INET, SOCK_STREAM, 0); - g_assert(sock >= 0); - - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = PF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = htonl(INADDR_ANY); - - if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - g_assert_not_reached(); - - if(listen(sock, 1) < 0) - g_assert_not_reached(); - - chan = g_io_channel_unix_new(sock); - chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - listen_cb, NULL); -} - - -int main(int argc, char *argv[]) { - int port = 0; - - private = mwMpi_new(); - public = mwMpi_new(); - - if(argc > 1) { - port = atoi(argv[1]); - } - - if(!port) { - fprintf(stderr, - ( " Usage: %s local_port\n" - " Creates a locally-running sametime server which prints" - " login information to stdout\n" ), - argv[0]); - exit(1); - } - - /* @todo create signal handlers to cleanup socket */ - - init_socket(port); - - g_main_loop_run(g_main_loop_new(NULL, FALSE)); - return 0; -} - diff --git a/samples/nocipher_proxy.c b/samples/nocipher_proxy.c index 3851913..dde6485 100644 --- a/samples/nocipher_proxy.c +++ b/samples/nocipher_proxy.c @@ -29,6 +29,7 @@ #include #include +#include #include #include diff --git a/samples/nocipher_proxy.c.fix-glib-headers b/samples/nocipher_proxy.c.fix-glib-headers deleted file mode 100644 index dde6485..0000000 --- a/samples/nocipher_proxy.c.fix-glib-headers +++ /dev/null @@ -1,476 +0,0 @@ - -/* - Clear Channel Sametime Proxy Utility - The Meanwhile Project - - This is a tool which can act as a proxy between a client and a - sametime server, which will force all channels to be created without - any encryption method. This makes reverse-engineering much, much - easier. - - It also outputs the messages sent to and from the client to stdout - as hex pairs. If compiled with USE_HEXDUMP, output will be printed - via `hexdump -C` - - All it really does is nab all Channel Create messages, strip the - offered ciphers portion from the message and replace it with an - empty ciphers list. - - Christopher O'Brien -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -struct proxy_side { - int sock; - GIOChannel *chan; - gint chan_io; - - guchar *buf; - gsize buf_size; - gsize buf_recv; - - void (*forward)(const guchar *buf, gsize len); -}; - - -static struct proxy_side client; -static struct proxy_side server; - - -static void hexdump(const char *txt, const guchar *buf, gsize len) { - FILE *fp; - - if(txt) fprintf(stdout, "\n%s\n", txt); - fflush(stdout); - - fp = popen("hexdump -C", "w"); - fwrite(buf, len, 1, fp); - fflush(fp); - pclose(fp); -} - - -static void put_msg(struct mwMessage *msg, struct mwOpaque *o) { - struct mwPutBuffer *b; - - b = mwPutBuffer_new(); - mwMessage_put(b, msg); - mwPutBuffer_finalize(o, b); - - b = mwPutBuffer_new(); - mwOpaque_put(b, o); - mwOpaque_clear(o); - mwPutBuffer_finalize(o, b); -} - - -static void side_buf_free(struct proxy_side *s) { - g_free(s->buf); - s->buf = NULL; - s->buf_size = 0; - s->buf_recv = 0; -} - - -static void munge_redir() { - struct mwMessage *msg; - struct mwOpaque o = { 0, 0 }; - - msg = mwMessage_new(mwMessage_LOGIN_CONTINUE); - put_msg(msg, &o); - mwMessage_free(msg); - - server.forward(o.data, o.len); - - mwOpaque_clear(&o); -} - - -static void munge_create(struct proxy_side *side, - struct mwMsgChannelCreate *msg) { - - struct mwOpaque o = { 0, 0 }; - GList *l; - - for(l = msg->encrypt.items; l; l = l->next) { - mwEncryptItem_clear(l->data); - g_free(l->data); - } - g_list_free(msg->encrypt.items); - msg->encrypt.items = NULL; - - msg->encrypt.mode = 0x00; - msg->encrypt.extra = 0x00; - msg->encrypt.flag = FALSE; - - put_msg(MW_MESSAGE(msg), &o); - side->forward(o.data, o.len); - mwOpaque_clear(&o); -} - - -static void side_process(struct proxy_side *s, const guchar *buf, gsize len) { - struct mwOpaque o = { .len = len, .data = (guchar *) buf }; - struct mwGetBuffer *b; - guint16 type; - - if(! len) return; - - b = mwGetBuffer_wrap(&o); - type = guint16_peek(b); - - switch(type) { - case mwMessage_LOGIN_REDIRECT: - munge_redir(); - break; - - case mwMessage_CHANNEL_CREATE: - { - struct mwMessage *msg = mwMessage_get(b); - munge_create(s, (struct mwMsgChannelCreate *) msg); - mwMessage_free(msg); - break; - } - - default: - { - struct mwPutBuffer *pb = mwPutBuffer_new(); - struct mwOpaque po = { 0, 0 }; - mwOpaque_put(pb, &o); - mwPutBuffer_finalize(&po, pb); - s->forward(po.data, po.len); - mwOpaque_clear(&po); - } - } - - mwGetBuffer_free(b); -} - - -#define ADVANCE(b, n, count) { b += count; n -= count; } - - -/* handle input to complete an existing buffer */ -static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) { - - gsize x = s->buf_size - s->buf_recv; - - if(n < x) { - memcpy(s->buf+s->buf_recv, b, n); - s->buf_recv += n; - return 0; - - } else { - memcpy(s->buf+s->buf_recv, b, x); - ADVANCE(b, n, x); - - if(s->buf_size == 4) { - struct mwOpaque o = { .len = 4, .data = s->buf }; - struct mwGetBuffer *gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - - if(n < x) { - guchar *t; - x += 4; - t = (guchar *) g_malloc(x); - memcpy(t, s->buf, 4); - memcpy(t+4, b, n); - - side_buf_free(s); - - s->buf = t; - s->buf_size = x; - s->buf_recv = n + 4; - return 0; - - } else { - side_buf_free(s); - side_process(s, b, x); - ADVANCE(b, n, x); - } - - } else { - side_process(s, s->buf+4, s->buf_size-4); - side_buf_free(s); - } - } - - return n; -} - - -/* handle input when there's nothing previously buffered */ -static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) { - struct mwOpaque o = { .len = n, .data = (guchar *) b }; - struct mwGetBuffer *gb; - gsize x; - - if(n < 4) { - s->buf = (guchar *) g_malloc0(4); - memcpy(s->buf, b, n); - s->buf_size = 4; - s->buf_recv = n; - return 0; - } - - gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - if(! x) return n - 4; - - if(n < (x + 4)) { - - x += 4; - s->buf = (guchar *) g_malloc(x); - memcpy(s->buf, b, n); - s->buf_size = x; - s->buf_recv = n; - return 0; - - } else { - ADVANCE(b, n, 4); - side_process(s, b, x); - ADVANCE(b, n, x); - - return n; - } -} - - -static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) { - - if(n && (s->buf_size == 0) && (*b & 0x80)) { - ADVANCE(b, n, 1); - } - - if(n == 0) { - return 0; - - } else if(s->buf_size > 0) { - return side_recv_cont(s, b, n); - - } else { - return side_recv_empty(s, b, n); - } -} - - -static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) { - guchar *b = (guchar *) buf; - gsize remain = 0; - - g_return_if_fail(side != NULL); - - while(n > 0) { - remain = side_recv(side, b, n); - b += (n - remain); - n = remain; - } -} - - -static int read_recv(struct proxy_side *side) { - guchar buf[2048]; - int len; - - len = read(side->sock, buf, 2048); - if(len > 0) feed_buf(side, buf, (gsize) len); - - return len; -} - - -static void done() { - close(client.sock); - close(server.sock); - exit(0); -} - - -static gboolean read_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - - struct proxy_side *side = data; - int ret = 0; - - if(cond & G_IO_IN) { - ret = read_recv(side); - if(ret > 0) return TRUE; - } - - if(side->sock) { - g_source_remove(side->chan_io); - close(side->sock); - side->sock = 0; - side->chan = NULL; - side->chan_io = 0; - } - - done(); - - return FALSE; -} - - -static void client_cb(const guchar *buf, gsize len) { - if(server.sock) { - hexdump("client -> server", buf, len); - write(server.sock, buf, len); - } -} - - -static gboolean listen_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - - struct sockaddr_in rem; - guint len = sizeof(rem); - struct proxy_side *side = data; - int sock; - - sock = accept(side->sock, (struct sockaddr *) &rem, &len); - g_assert(sock > 0); - - g_source_remove(side->chan_io); - side->sock = sock; - side->chan = g_io_channel_unix_new(sock); - side->chan_io = g_io_add_watch(side->chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - read_cb, side); - - return FALSE; -} - - -static void init_client(int port) { - /* start listening on the local port specifier */ - - struct sockaddr_in sin; - int sock; - - sock = socket(PF_INET, SOCK_STREAM, 0); - g_assert(sock >= 0); - - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = PF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = htonl(INADDR_ANY); - - if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - g_assert_not_reached(); - - if(listen(sock, 1) < 0) - g_assert_not_reached(); - - client.forward = client_cb; - client.sock = sock; - client.chan = g_io_channel_unix_new(sock); - client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - listen_cb, &client); -} - - -static void server_cb(const guchar *buf, gsize len) { - if(client.sock) { - hexdump("server -> client", buf, len); - write(client.sock, buf, len); - } -} - - -/* address lookup used by init_sock */ -static void init_sockaddr(struct sockaddr_in *addr, - const char *host, int port) { - - struct hostent *hostinfo; - - addr->sin_family = AF_INET; - addr->sin_port = htons (port); - hostinfo = gethostbyname(host); - if(hostinfo == NULL) { - fprintf(stderr, "Unknown host %s.\n", host); - exit(1); - } - addr->sin_addr = *(struct in_addr *) hostinfo->h_addr; -} - - -static void init_server(const char *host, int port) { - /* connect to server on host/port */ - struct sockaddr_in srvrname; - int sock; - - sock = socket(PF_INET, SOCK_STREAM, 0); - if(sock < 0) { - fprintf(stderr, "socket failure"); - exit(1); - } - - init_sockaddr(&srvrname, host, port); - connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname)); - - server.forward = server_cb; - server.sock = sock; - server.chan = g_io_channel_unix_new(sock); - server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - read_cb, &server); -} - - -int main(int argc, char *argv[]) { - char *host = NULL; - int client_port = 0, server_port = 0; - - memset(&client, 0, sizeof(struct proxy_side)); - memset(&server, 0, sizeof(struct proxy_side)); - - if(argc > 1) { - char *z; - - host = argv[1]; - z = host; - - host = strchr(z, ':'); - if(host) *host++ = '\0'; - client_port = atoi(z); - - z = strchr(host, ':'); - if(z) *z++ = '\0'; - server_port = atoi(z); - } - - if(!host || !*host || !client_port || !server_port) { - fprintf(stderr, - ( " Usage: %s local_port:remote_host:remote_port\n" - " Creates a locally-running sametime proxy which enforces" - " unencrypted channels\n" ), - argv[0]); - exit(1); - } - - /* @todo create signal handlers to cleanup sockets */ - - init_client(client_port); - init_server(host, server_port); - - g_main_loop_run(g_main_loop_new(NULL, FALSE)); - return 0; -} - diff --git a/samples/redirect_server.c b/samples/redirect_server.c index c0ed353..91f43f7 100644 --- a/samples/redirect_server.c +++ b/samples/redirect_server.c @@ -22,6 +22,7 @@ #include #include +#include #include #include diff --git a/samples/redirect_server.c.fix-glib-headers b/samples/redirect_server.c.fix-glib-headers deleted file mode 100644 index 91f43f7..0000000 --- a/samples/redirect_server.c.fix-glib-headers +++ /dev/null @@ -1,365 +0,0 @@ - -/* - Redirecting Sametime Faux-Server - The Meanwhile Project - - This is a tool which helps to test handling of login-redirects when - you don't have a server which will issue them. It will listen for a - single incoming connection, will accept a handshake message and send - a handshake ack, and will respond to a login message with a redirect - message to a server specified on the command line. - - Christopher O'Brien -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -/** the server socket or the connected socket */ -static int sock; - -/** the io channel */ -static GIOChannel *chan; - -/** the listening event on the io channel */ -static int chan_io; - -static char *host; - -static guchar *sbuf; -static gsize sbuf_size; -static gsize sbuf_recv; - - -static void send_msg(struct mwMessage *msg) { - struct mwPutBuffer *b; - struct mwOpaque o = { 0, 0 }; - - b = mwPutBuffer_new(); - mwMessage_put(b, msg); - mwPutBuffer_finalize(&o, b); - - b = mwPutBuffer_new(); - mwOpaque_put(b, &o); - mwOpaque_clear(&o); - mwPutBuffer_finalize(&o, b); - - if(sock) write(sock, o.data, o.len); - - mwOpaque_clear(&o); -} - - -static void handshake_ack() { - struct mwMsgHandshakeAck *msg; - - msg = (struct mwMsgHandshakeAck *) - mwMessage_new(mwMessage_HANDSHAKE_ACK); - - send_msg(MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); -} - - -static void login_redir() { - struct mwMsgLoginRedirect *msg; - - msg = (struct mwMsgLoginRedirect *) - mwMessage_new(mwMessage_LOGIN_REDIRECT); - msg->host = g_strdup(host); - msg->server_id = NULL; - - send_msg(MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); -} - - -static void done() { - close(sock); - exit(0); -} - - -static void side_process(const guchar *buf, gsize len) { - struct mwOpaque o = { .len = len, .data = (guchar *) buf }; - struct mwGetBuffer *b; - guint16 type; - - if(! len) return; - - b = mwGetBuffer_wrap(&o); - type = guint16_peek(b); - - switch(type) { - case mwMessage_HANDSHAKE: - handshake_ack(); - break; - - case mwMessage_LOGIN: - login_redir(); - break; - - case mwMessage_CHANNEL_DESTROY: - done(); - break; - - default: - ; - } - - mwGetBuffer_free(b); -} - - -static void sbuf_free() { - g_free(sbuf); - sbuf = NULL; - sbuf_size = 0; - sbuf_recv = 0; -} - - -#define ADVANCE(b, n, count) { b += count; n -= count; } - - -/* handle input to complete an existing buffer */ -static gsize side_recv_cont(const guchar *b, gsize n) { - - gsize x = sbuf_size - sbuf_recv; - - if(n < x) { - memcpy(sbuf + sbuf_recv, b, n); - sbuf_recv += n; - return 0; - - } else { - memcpy(sbuf + sbuf_recv, b, x); - ADVANCE(b, n, x); - - if(sbuf_size == 4) { - struct mwOpaque o = { .len = 4, .data = sbuf }; - struct mwGetBuffer *gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - - if(n < x) { - guchar *t; - x += 4; - t = (guchar *) g_malloc(x); - memcpy(t, sbuf, 4); - memcpy(t+4, b, n); - - sbuf_free(); - - sbuf = t; - sbuf_size = x; - sbuf_recv = n + 4; - return 0; - - } else { - sbuf_free(); - side_process(b, x); - ADVANCE(b, n, x); - } - - } else { - side_process(sbuf+4, sbuf_size-4); - sbuf_free(); - } - } - - return n; -} - - -/* handle input when there's nothing previously buffered */ -static gsize side_recv_empty(const guchar *b, gsize n) { - struct mwOpaque o = { .len = n, .data = (guchar *) b }; - struct mwGetBuffer *gb; - gsize x; - - if(n < 4) { - sbuf = (guchar *) g_malloc0(4); - memcpy(sbuf, b, n); - sbuf_size = 4; - sbuf_recv = n; - return 0; - } - - gb = mwGetBuffer_wrap(&o); - x = guint32_peek(gb); - mwGetBuffer_free(gb); - if(! x) return n - 4; - - if(n < (x + 4)) { - - x += 4; - sbuf = (guchar *) g_malloc(x); - memcpy(sbuf, b, n); - sbuf_size = x; - sbuf_recv = n; - return 0; - - } else { - ADVANCE(b, n, 4); - side_process(b, x); - ADVANCE(b, n, x); - - return n; - } -} - - -static gsize side_recv(const guchar *b, gsize n) { - - if(n && (sbuf_size == 0) && (*b & 0x80)) { - ADVANCE(b, n, 1); - } - - if(n == 0) { - return 0; - - } else if(sbuf_size > 0) { - return side_recv_cont(b, n); - - } else { - return side_recv_empty(b, n); - } -} - - -static void feed_buf(const guchar *buf, gsize n) { - guchar *b = (guchar *) buf; - gsize remain = 0; - - while(n > 0) { - remain = side_recv(b, n); - b += (n - remain); - n = remain; - } -} - - -static int read_recv() { - guchar buf[2048]; - int len; - - len = read(sock, buf, 2048); - if(len > 0) feed_buf(buf, (gsize) len); - - return len; -} - - -static gboolean read_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - int ret = 0; - - if(cond & G_IO_IN) { - ret = read_recv(); - if(ret > 0) return TRUE; - } - - if(sock) { - g_source_remove(chan_io); - close(sock); - sock = 0; - chan = NULL; - chan_io = 0; - } - - done(); - - return FALSE; -} - - -static gboolean listen_cb(GIOChannel *chan, - GIOCondition cond, - gpointer data) { - - struct sockaddr_in rem; - guint len = sizeof(rem); - - sock = accept(sock, (struct sockaddr *) &rem, &len); - g_assert(sock > 0); - - g_source_remove(chan_io); - chan = g_io_channel_unix_new(sock); - chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - read_cb, NULL); - - return FALSE; -} - - -static void init_socket(int port) { - /* start listening on the local port specifier */ - - struct sockaddr_in sin; - - sock = socket(PF_INET, SOCK_STREAM, 0); - g_assert(sock >= 0); - - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = PF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = htonl(INADDR_ANY); - - if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - g_assert_not_reached(); - - if(listen(sock, 1) < 0) - g_assert_not_reached(); - - chan = g_io_channel_unix_new(sock); - chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP, - listen_cb, NULL); -} - - -int main(int argc, char *argv[]) { - int port = 0; - - if(argc > 1) { - char *z; - - host = argv[1]; - z = host; - - host = strchr(z, ':'); - if(host) *host++ = '\0'; - port = atoi(z); - } - - if(!host || !*host || !port) { - fprintf(stderr, - ( " Usage: %s local_port:redirect_host\n" - " Creates a locally-running sametime proxy which redirects" - " logins to the\n specified host\n" ), - argv[0]); - exit(1); - } - - /* @todo create signal handlers to cleanup socket */ - - init_socket(port); - - g_main_loop_run(g_main_loop_new(NULL, FALSE)); - return 0; -} - diff --git a/src/channel.c b/src/channel.c index 932522d..d7215a9 100644 --- a/src/channel.c +++ b/src/channel.c @@ -19,6 +19,8 @@ */ #include +#include +#include #include #include "mw_channel.h" diff --git a/src/channel.c.fix-glib-headers b/src/channel.c.fix-glib-headers deleted file mode 100644 index d7215a9..0000000 --- a/src/channel.c.fix-glib-headers +++ /dev/null @@ -1,967 +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); -} - - -static struct mwCipherInstance * -get_supported(struct mwChannel *chan, guint16 id) { - - guint32 cid = (guint32) id; - return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid)); -} - - -static 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 --git a/src/common.c b/src/common.c index 9a7c6b9..c8f78ca 100644 --- a/src/common.c +++ b/src/common.c @@ -688,9 +688,6 @@ void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat) { guint16_get(b, &stat->status); guint32_get(b, &stat->time); mwString_get(b, &stat->desc); - - // Quick'n ugly hack for recent Sametime clients - stat->time = 0; } diff --git a/src/common.c.status-timestamp-workaround b/src/common.c.status-timestamp-workaround deleted file mode 100644 index c8f78ca..0000000 --- a/src/common.c.status-timestamp-workaround +++ /dev/null @@ -1,928 +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; -} - - -static 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 end_of_block; - - g_return_if_fail(b != NULL); - g_return_if_fail(idb != NULL); - - guint32_get(b, &end_of_block); - mwAwareIdBlock_get(b, &idb->id); - mwString_get(b, &idb->group); - gboolean_get(b, &idb->online); - - if(idb->online) { - mwString_get(b, &idb->alt_id); - mwUserStatus_get(b, &idb->status); - mwString_get(b, &idb->name); - } - - if(b->ptr < b->buf + end_of_block) { - mwGetBuffer_advance(b, b->buf + end_of_block - b->ptr); - } -} - - -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 --git a/src/mw_debug.c b/src/mw_debug.c index f86b6b5..cf47a38 100644 --- a/src/mw_debug.c +++ b/src/mw_debug.c @@ -19,7 +19,7 @@ */ -#include +#include #include "mw_debug.h" @@ -92,7 +92,7 @@ void mw_debug_datav(const guchar *buf, gsize len, } pretty_print(str, buf, len); - g_debug("%s", str->str); + g_debug(str->str); g_string_free(str, TRUE); } @@ -149,7 +149,7 @@ void mw_mailme_datav(const guchar *buf, gsize len, g_string_append(str, MW_MAILME_CUT_STOP); - g_debug("%s", str->str); + g_debug(str->str); g_string_free(str, TRUE); #else diff --git a/src/mw_debug.c.fix-glib-headers b/src/mw_debug.c.fix-glib-headers deleted file mode 100644 index cf47a38..0000000 --- a/src/mw_debug.c.fix-glib-headers +++ /dev/null @@ -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(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 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 --git a/src/mw_debug.c.format-security-fix b/src/mw_debug.c.format-security-fix deleted file mode 100644 index d22d287..0000000 --- a/src/mw_debug.c.format-security-fix +++ /dev/null @@ -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(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 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 --git a/src/mw_message.h b/src/mw_message.h index a825ec2..8402b8b 100644 --- a/src/mw_message.h +++ b/src/mw_message.h @@ -22,7 +22,7 @@ #define _MW_MESSAGE_H -#include +#include #include "mw_common.h" diff --git a/src/mw_message.h.fix-glib-headers b/src/mw_message.h.fix-glib-headers deleted file mode 100644 index 8402b8b..0000000 --- a/src/mw_message.h.fix-glib-headers +++ /dev/null @@ -1,305 +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" - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** 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; -}; - - -#ifdef __cplusplus -} -#endif - - -#endif /* _MW_MESSAGE_H */ - diff --git a/src/mw_srvc_conf.h b/src/mw_srvc_conf.h index 66d885b..156c639 100644 --- a/src/mw_srvc_conf.h +++ b/src/mw_srvc_conf.h @@ -22,7 +22,7 @@ #define _MW_SRVC_CONF_H -#include +#include #include "mw_common.h" diff --git a/src/mw_srvc_conf.h.fix-glib-headers b/src/mw_srvc_conf.h.fix-glib-headers deleted file mode 100644 index 156c639..0000000 --- a/src/mw_srvc_conf.h.fix-glib-headers +++ /dev/null @@ -1,209 +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" - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** 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); - - -#ifdef __cplusplus -} -#endif - - -#endif /* _MW_SRVC_CONF_H */ - diff --git a/src/mw_srvc_dir.h b/src/mw_srvc_dir.h index c45e850..b9230bb 100644 --- a/src/mw_srvc_dir.h +++ b/src/mw_srvc_dir.h @@ -22,6 +22,7 @@ #include +#include #ifdef __cplusplus diff --git a/src/mw_srvc_dir.h.fix-glib-headers b/src/mw_srvc_dir.h.fix-glib-headers deleted file mode 100644 index b9230bb..0000000 --- a/src/mw_srvc_dir.h.fix-glib-headers +++ /dev/null @@ -1,212 +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 - - -#ifdef __cplusplus -extern "C" { -#endif - - -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); - - -#ifdef __cplusplus -} -#endif - - -#endif /* _MW_SRVC_DIR_H */ diff --git a/src/mw_srvc_place.h b/src/mw_srvc_place.h index bba97b6..e17aa71 100644 --- a/src/mw_srvc_place.h +++ b/src/mw_srvc_place.h @@ -22,7 +22,7 @@ #define _MW_SRVC_PLACE_H -#include +#include #include "mw_common.h" diff --git a/src/mw_srvc_place.h.fix-glib-headers b/src/mw_srvc_place.h.fix-glib-headers deleted file mode 100644 index e17aa71..0000000 --- a/src/mw_srvc_place.h.fix-glib-headers +++ /dev/null @@ -1,148 +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" - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** 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); - - -#ifdef __cplusplus -} -#endif - - -#endif /* _MW_SRVC_PLACE_H */ - diff --git a/src/mw_srvc_resolve.h b/src/mw_srvc_resolve.h index dd033e1..3b06b75 100644 --- a/src/mw_srvc_resolve.h +++ b/src/mw_srvc_resolve.h @@ -23,6 +23,7 @@ #include +#include #ifdef __cplusplus diff --git a/src/mw_srvc_resolve.h.fix-glib-headers b/src/mw_srvc_resolve.h.fix-glib-headers deleted file mode 100644 index 3b06b75..0000000 --- a/src/mw_srvc_resolve.h.fix-glib-headers +++ /dev/null @@ -1,150 +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 - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** 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); - - -#ifdef __cplusplus -} -#endif - - -#endif /* _MW_SRVC_RESOLVE_H */ diff --git a/src/mw_st_list.h b/src/mw_st_list.h index 60635ee..db0d0e1 100644 --- a/src/mw_st_list.h +++ b/src/mw_st_list.h @@ -30,6 +30,7 @@ #include +#include #include "mw_common.h" diff --git a/src/mw_st_list.h.fix-glib-headers b/src/mw_st_list.h.fix-glib-headers deleted file mode 100644 index db0d0e1..0000000 --- a/src/mw_st_list.h.fix-glib-headers +++ /dev/null @@ -1,218 +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 - - -/** @file mw_st_list.h - - Parse and compose buddy lists in the format commonly used by Sametime - Connect clients. -*/ - - -#include -#include -#include "mw_common.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - -#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); - - - -#ifdef __cplusplus -} -#endif - - -#endif /* _MW_ST_LIST_H */ diff --git a/src/mw_util.h b/src/mw_util.h index 10dcd69..b8e0b7e 100644 --- a/src/mw_util.h +++ b/src/mw_util.h @@ -23,6 +23,9 @@ #include +#include +#include + #define map_guint_new() \ g_hash_table_new(g_direct_hash, g_direct_equal) diff --git a/src/mw_util.h.fix-glib-headers b/src/mw_util.h.fix-glib-headers deleted file mode 100644 index b8e0b7e..0000000 --- a/src/mw_util.h.fix-glib-headers +++ /dev/null @@ -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 --git a/src/srvc_aware.c b/src/srvc_aware.c index dc2c12f..869f973 100644 --- a/src/srvc_aware.c +++ b/src/srvc_aware.c @@ -19,6 +19,8 @@ */ #include +#include +#include #include #include "mw_channel.h" diff --git a/src/srvc_aware.c.fix-glib-headers b/src/srvc_aware.c.fix-glib-headers deleted file mode 100644 index 869f973..0000000 --- a/src/srvc_aware.c.fix-glib-headers +++ /dev/null @@ -1,1319 +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); - } -} - - -static 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 --git a/src/srvc_conf.c b/src/srvc_conf.c index 65e1e72..7a10d22 100644 --- a/src/srvc_conf.c +++ b/src/srvc_conf.c @@ -19,6 +19,8 @@ */ #include +#include +#include #include #include diff --git a/src/srvc_conf.c.fix-glib-headers b/src/srvc_conf.c.fix-glib-headers deleted file mode 100644 index 7a10d22..0000000 --- a/src/srvc_conf.c.fix-glib-headers +++ /dev/null @@ -1,867 +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); - - srvc->confs = 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_getMembers(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); - -#if 0 - /* offer all known ciphers */ - mwChannel_populateSupportedCipherInstances(chan); -#endif - - 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 --git a/src/srvc_dir.c b/src/srvc_dir.c index ed5997e..cf49152 100644 --- a/src/srvc_dir.c +++ b/src/srvc_dir.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include "mw_channel.h" #include "mw_common.h" diff --git a/src/srvc_dir.c.fix-glib-headers b/src/srvc_dir.c.fix-glib-headers deleted file mode 100644 index cf49152..0000000 --- a/src/srvc_dir.c.fix-glib-headers +++ /dev/null @@ -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_mailme_opaque(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_mailme_opaque(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 --git a/src/srvc_ft.c b/src/srvc_ft.c index b47bd67..0564732 100644 --- a/src/srvc_ft.c +++ b/src/srvc_ft.c @@ -19,7 +19,7 @@ */ -#include +#include #include "mw_channel.h" #include "mw_common.h" @@ -142,7 +142,7 @@ static void recv_channelCreate(struct mwServiceFileTransfer *srvc, 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 */ + guint32_get(b, &junk); /* unknown */ /* and we just skip an unknown guint16 at the end */ b_err = mwGetBuffer_error(b); diff --git a/src/srvc_ft.c.file-transfer b/src/srvc_ft.c.file-transfer deleted file mode 100644 index ff9f010..0000000 --- a/src/srvc_ft.c.file-transfer +++ /dev/null @@ -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 --git a/src/srvc_ft.c.fix-glib-headers b/src/srvc_ft.c.fix-glib-headers deleted file mode 100644 index 0564732..0000000 --- a/src/srvc_ft.c.fix-glib-headers +++ /dev/null @@ -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 --git a/src/srvc_im.c b/src/srvc_im.c index 5c13ca3..5930687 100644 --- a/src/srvc_im.c +++ b/src/srvc_im.c @@ -19,6 +19,7 @@ */ #include +#include #include #include "mw_channel.h" diff --git a/src/srvc_im.c.fix-glib-headers b/src/srvc_im.c.fix-glib-headers deleted file mode 100644 index 5930687..0000000 --- a/src/srvc_im.c.fix-glib-headers +++ /dev/null @@ -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 "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; - char *unkn, *host; - guint16 with_who; - - 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); - - /* todo: add a mwString_skip */ - mwString_get(b, &unkn); - mwString_get(b, &host); - g_free(unkn); - g_free(host); - - /* hack. Sometimes incoming convo invitation channels won't have the - owner id block filled in */ - guint16_get(b, &with_who); - if(with_who && !conv->target.user) { - char *login; - mwString_get(b, &conv->target.user); - mwString_get(b, &login); g_free(login); - mwString_get(b, &conv->target.community); - } - - if(mwGetBuffer_error(b)) { - mw_mailme_opaque(o, "problem with place invite over IM service"); - } else { - 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 --git a/src/srvc_place.c b/src/srvc_place.c index 58ba574..fc979ff 100644 --- a/src/srvc_place.c +++ b/src/srvc_place.c @@ -19,6 +19,8 @@ */ #include +#include +#include #include #include diff --git a/src/srvc_place.c.fix-glib-headers b/src/srvc_place.c.fix-glib-headers deleted file mode 100644 index fc979ff..0000000 --- a/src/srvc_place.c.fix-glib-headers +++ /dev/null @@ -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 --git a/src/srvc_resolve.c b/src/srvc_resolve.c index c71d7b3..aac0d49 100644 --- a/src/srvc_resolve.c +++ b/src/srvc_resolve.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include "mw_channel.h" #include "mw_common.h" diff --git a/src/srvc_resolve.c.fix-glib-headers b/src/srvc_resolve.c.fix-glib-headers deleted file mode 100644 index aac0d49..0000000 --- a/src/srvc_resolve.c.fix-glib-headers +++ /dev/null @@ -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 --git a/src/srvc_store.c b/src/srvc_store.c index afbd2b6..90f2efc 100644 --- a/src/srvc_store.c +++ b/src/srvc_store.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include "mw_channel.h" #include "mw_debug.h" diff --git a/src/srvc_store.c.fix-glib-headers b/src/srvc_store.c.fix-glib-headers deleted file mode 100644 index 90f2efc..0000000 --- a/src/srvc_store.c.fix-glib-headers +++ /dev/null @@ -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 --git a/src/st_list.c b/src/st_list.c index 186d5a3..949696a 100644 --- a/src/st_list.c +++ b/src/st_list.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include "mw_debug.h" #include "mw_util.h" @@ -662,9 +662,7 @@ void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l) { g_return_if_fail(b != NULL); mwString_get(b, &str); - if (str) { - list_get(str, l); - g_free(str); - } + list_get(str, l); + g_free(str); } diff --git a/src/st_list.c.crash b/src/st_list.c.crash deleted file mode 100644 index 949696a..0000000 --- a/src/st_list.c.crash +++ /dev/null @@ -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; -} - - -static 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); -} - diff --git a/src/st_list.c.fix-glib-headers b/src/st_list.c.fix-glib-headers deleted file mode 100644 index c2809be..0000000 --- a/src/st_list.c.fix-glib-headers +++ /dev/null @@ -1,670 +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; -} - - -static 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); - if (str) { - list_get(str, l); - g_free(str); - } -} -