Mercurial > pidgin
diff src/protocols/sametime/meanwhile/session.c @ 11943:0110fc7c6a8a
[gaim-migrate @ 14234]
Bringing things up to date with the last Meanwhile release, 0.5.0 and the last
gaim-meanwhile plugin release, 1.2.5 (which should be the last plugin release
against oldstatus, if all goes well with HEAD and no major bugs crop up)
It builds, so that's a start. The status bits that have been empty since the
first import of the sametime stuff are still empty, but I'm going to try and
fill those in tomorrow. I've decided to try and start using HEAD actively, to
encourage me to get this freaking prpl fully functional.
committer: Tailor Script <tailor@pidgin.im>
| author | Christopher O'Brien <siege@pidgin.im> |
|---|---|
| date | Wed, 02 Nov 2005 03:39:03 +0000 |
| parents | 57fccea36e36 |
| children | 2edf5dc1b2ea |
line wrap: on
line diff
--- a/src/protocols/sametime/meanwhile/session.c Wed Nov 02 03:31:38 2005 +0000 +++ b/src/protocols/sametime/meanwhile/session.c Wed Nov 02 03:39:03 2005 +0000 @@ -19,6 +19,7 @@ */ #include <glib.h> +#include <gmp.h> #include <string.h> #include "mw_channel.h" @@ -48,7 +49,7 @@ struct mwSessionHandler *handler; enum mwSessionState state; /**< session state */ - guint32 state_info; /**< additional state info */ + gpointer state_info; /**< additional state info */ /* input buffering for an incoming message */ char *buf; /**< buffer for incoming message data */ @@ -218,16 +219,8 @@ } -/** set the state of the session, and trigger the session handler's - on_stateChange function. Has no effect if the session is already - in the specified state (ignores additional state info) - - @param s the session - @param state the state to set - @param info additional state info -*/ static void state(struct mwSession *s, enum mwSessionState state, - guint32 info) { + gpointer info) { struct mwSessionHandler *sh; @@ -239,14 +232,24 @@ s->state = state; s->state_info = info; - if(info) { - g_message("session state: %s (0x%08x)", state_str(state), info); - } else { + switch(state) { + case mwSession_STOPPING: + case mwSession_STOPPED: + g_message("session state: %s (0x%08x)", state_str(state), + GPOINTER_TO_UINT(info)); + break; + + case mwSession_LOGIN_REDIR: + g_message("session state: %s (%s)", state_str(state), + (char *)info); + break; + + default: g_message("session state: %s", state_str(state)); } sh = s->handler; - if(sh->on_stateChange) + if(sh && sh->on_stateChange) sh->on_stateChange(s, state, info); } @@ -258,6 +261,11 @@ g_return_if_fail(s != NULL); g_return_if_fail(mwSession_isStopped(s)); + if(mwSession_isStarted(s) || mwSession_isStarting(s)) { + g_debug("attempted to start session that is already started/starting"); + return; + } + state(s, mwSession_STARTING, 0); msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE); @@ -265,6 +273,13 @@ msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR)); msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); + msg->loclcalc_addr = GUINT(property_get(s, mwSession_CLIENT_IP)); + + if(msg->major >= 0x001e && msg->minor >= 0x001d) { + msg->unknown_a = 0x0100; + msg->local_host = (char *) property_get(s, mwSession_CLIENT_HOST); + } + ret = mwSession_send(s, MW_MESSAGE(msg)); mwMessage_free(MW_MESSAGE(msg)); @@ -281,10 +296,13 @@ struct mwMsgChannelDestroy *msg; g_return_if_fail(s != NULL); - g_return_if_fail(! mwSession_isStopping(s)); - g_return_if_fail(! mwSession_isStopped(s)); + + if(mwSession_isStopped(s) || mwSession_isStopping(s)) { + g_debug("attempted to stop session that is already stopped/stopping"); + return; + } - state(s, mwSession_STOPPING, reason); + state(s, mwSession_STOPPING, GUINT_TO_POINTER(reason)); for(list = l = mwSession_getServices(s); l; l = l->next) mwService_stop(MW_SERVICE(l->data)); @@ -305,20 +323,20 @@ /* close the connection */ io_close(s); - state(s, mwSession_STOPPED, reason); + state(s, mwSession_STOPPED, GUINT_TO_POINTER(reason)); } /** compose authentication information into an opaque based on the - password */ -static void compose_auth(struct mwOpaque *auth, const char *pass) { + password, encrypted via RC2/40 */ +static void compose_auth_rc2_40(struct mwOpaque *auth, const char *pass) { char iv[8], key[5]; struct mwOpaque a, b, z; struct mwPutBuffer *p; /* get an IV and a random five-byte key */ mwIV_init((char *) iv); - rand_key((char *) key, 5); + mwKeyRandom((char *) key, 5); /* the opaque with the key */ a.len = 5; @@ -346,6 +364,63 @@ } +static void compose_auth_rc2_128(struct mwOpaque *auth, const char *pass, + guint32 magic, struct mwOpaque *rkey) { + + char iv[8]; + struct mwOpaque a, b, c; + struct mwPutBuffer *p; + + mpz_t private, public; + mpz_t remote; + mpz_t shared; + + mpz_init(private); + mpz_init(public); + mpz_init(remote); + mpz_init(shared); + + mwIV_init(iv); + + mwDHRandKeypair(private, public); + mwDHImportKey(remote, rkey); + mwDHCalculateShared(shared, remote, private); + + /* put the password in opaque a */ + p = mwPutBuffer_new(); + guint32_put(p, magic); + mwString_put(p, pass); + mwPutBuffer_finalize(&a, p); + + /* put the shared key in opaque b */ + mwDHExportKey(shared, &b); + + /* encrypt the password (a) using the shared key (b), put the result + in opaque c */ + mwEncrypt(b.data+(b.len-16), 16, iv, &a, &c); + + /* don't need the shared key anymore, re-use opaque (b) as the + export of the public key */ + mwOpaque_clear(&b); + mwDHExportKey(public, &b); + + p = mwPutBuffer_new(); + guint16_put(p, 0x0001); /* XXX: unknown */ + mwOpaque_put(p, &b); + mwOpaque_put(p, &c); + mwPutBuffer_finalize(auth, p); + + mwOpaque_clear(&a); + mwOpaque_clear(&b); + mwOpaque_clear(&c); + + mpz_clear(private); + mpz_clear(public); + mpz_clear(remote); + mpz_clear(shared); +} + + /** handle the receipt of a handshake_ack message by sending the login message */ static void HANDSHAKE_ACK_recv(struct mwSession *s, @@ -380,8 +455,21 @@ log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID)); /** @todo default to password for now. later use token optionally */ - log->auth_type = mwAuthType_ENCRYPT; - compose_auth(&log->auth_data, property_get(s, mwSession_AUTH_PASSWORD)); + { + const char *pw; + pw = (const char *) property_get(s, mwSession_AUTH_PASSWORD); + + if(msg->data.len >= 64) { + /* good login encryption */ + log->auth_type = mwAuthType_RC2_128; + compose_auth_rc2_128(&log->auth_data, pw, msg->magic, &msg->data); + + } else { + /* BAD login encryption */ + log->auth_type = mwAuthType_RC2_40; + compose_auth_rc2_40(&log->auth_data, pw); + } + } /* send the login message */ ret = mwSession_send(s, MW_MESSAGE(log)); @@ -524,14 +612,18 @@ } -static void LOGIN_REDIRECT_recv(struct mwSession *s, - struct mwMsgLoginRedirect *msg) { +static void ANNOUNCE_recv(struct mwSession *s, struct mwMsgAnnounce *msg) { struct mwSessionHandler *sh = s->handler; - state(s, mwSession_LOGIN_REDIR, 0); + if(sh && sh->on_announce) + sh->on_announce(s, &msg->sender, msg->may_reply, msg->text); +} + - if(sh && sh->on_loginRedirect) - sh->on_loginRedirect(s, msg->host); +static void LOGIN_REDIRECT_recv(struct mwSession *s, + struct mwMsgLoginRedirect *msg) { + + state(s, mwSession_LOGIN_REDIR, msg->host); } @@ -544,7 +636,7 @@ static void session_process(struct mwSession *s, const char *buf, gsize len) { - struct mwOpaque o = { len, (char *) buf }; + struct mwOpaque o = { .len = len, .data = (char *) buf }; struct mwGetBuffer *b; struct mwMessage *msg; @@ -559,6 +651,13 @@ /* attempt to parse the message. */ msg = mwMessage_get(b); + + if(mwGetBuffer_error(b)) { + mw_mailme_opaque(&o, "parsing of message failed"); + } + + mwGetBuffer_free(b); + g_return_if_fail(msg != NULL); /* handle each of the appropriate incoming types of mwMessage */ @@ -574,17 +673,12 @@ CASE(SET_USER_STATUS, mwMsgSetUserStatus); CASE(SENSE_SERVICE, mwMsgSenseService); CASE(ADMIN, mwMsgAdmin); + CASE(ANNOUNCE, mwMsgAnnounce); default: g_warning("unknown message type 0x%04x, no handler", msg->type); } - if(mwGetBuffer_error(b)) { - struct mwOpaque o = { .data = (char *) buf, .len = len }; - mw_debug_mailme(&o, "parsing of message type 0x%04x failed", msg->type); - } - - mwGetBuffer_free(b); mwMessage_free(msg); } @@ -592,7 +686,7 @@ #undef CASE -#define ADVANCE(b, n, count) (b += count, n -= count) +#define ADVANCE(b, n, count) { b += count; n -= count; } /* handle input to complete an existing buffer */ @@ -739,9 +833,11 @@ /* g_message(" session_recv: session = %p, b = %p, n = %u", s, b, n); */ - if(n && (s->buf_len == 0) && (*b & 0x80)) { - /* keep-alive and series bytes are ignored */ - ADVANCE(b, n, 1); + if(s->buf_len == 0) { + while(n && (*b & 0x80)) { + /* keep-alive and series bytes are ignored */ + ADVANCE(b, n, 1); + } } if(n == 0) { @@ -765,9 +861,6 @@ g_return_if_fail(s != NULL); - /* g_message(" mwSession_recv: session = %p, b = %p, n = %u", - s, b, n); */ - while(n > 0) { remain = session_recv(s, b, n); b += (n - remain); @@ -779,7 +872,6 @@ int mwSession_send(struct mwSession *s, struct mwMessage *msg) { struct mwPutBuffer *b; struct mwOpaque o; - gsize len; int ret = 0; g_return_val_if_fail(s != NULL, -1); @@ -799,7 +891,6 @@ mwPutBuffer_finalize(&o, b); /* then we use that opaque's data and length to write to the socket */ - len = o.len; ret = io_write(s, o.data, o.len); mwOpaque_clear(&o); @@ -845,6 +936,30 @@ } +int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply, + const char *text, const GList *recipients) { + + struct mwMsgAnnounce *msg; + int ret; + + g_return_val_if_fail(s != NULL, -1); + g_return_val_if_fail(mwSession_isStarted(s), -1); + + msg = (struct mwMsgAnnounce *) mwMessage_new(mwMessage_ANNOUNCE); + + msg->recipients = (GList *) recipients; + msg->may_reply = may_reply; + msg->text = g_strdup(text); + + ret = mwSession_send(s, MW_MESSAGE(msg)); + + msg->recipients = NULL; /* don't kill our recipients param */ + mwMessage_free(MW_MESSAGE(msg)); + + return ret; +} + + struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) { g_return_val_if_fail(s != NULL, NULL); return s->handler; @@ -917,7 +1032,7 @@ } -guint32 mwSession_getStateInfo(struct mwSession *s) { +gpointer mwSession_getStateInfo(struct mwSession *s) { g_return_val_if_fail(s != NULL, 0); return s->state_info; }
