Mercurial > pidgin
annotate src/protocols/sametime/meanwhile/session.c @ 11986:bfbb1798535e
[gaim-migrate @ 14279]
Switch to using the unicode character 0x25cf instead of an asterisk as
our password masking character.
In the words of the great Christian Hammond, "By the way, isn't it
about time we replace the asterisk in masked entries with that unicode
character for the round filled circle ("?")? The asterisk is so 1980s."
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Sat, 05 Nov 2005 23:42:35 +0000 |
| parents | 0110fc7c6a8a |
| children | 2edf5dc1b2ea |
| rev | line source |
|---|---|
| 10969 | 1 |
| 2 /* | |
| 3 Meanwhile - Unofficial Lotus Sametime Community Client Library | |
| 4 Copyright (C) 2004 Christopher (siege) O'Brien | |
| 5 | |
| 6 This library is free software; you can redistribute it and/or | |
| 7 modify it under the terms of the GNU Library General Public | |
| 8 License as published by the Free Software Foundation; either | |
| 9 version 2 of the License, or (at your option) any later version. | |
| 10 | |
| 11 This library is distributed in the hope that it will be useful, | |
| 12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 Library General Public License for more details. | |
| 15 | |
| 16 You should have received a copy of the GNU Library General Public | |
| 17 License along with this library; if not, write to the Free | |
| 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 */ | |
| 20 | |
| 21 #include <glib.h> | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
22 #include <gmp.h> |
| 10969 | 23 #include <string.h> |
| 24 | |
| 25 #include "mw_channel.h" | |
| 26 #include "mw_cipher.h" | |
| 27 #include "mw_debug.h" | |
| 28 #include "mw_error.h" | |
| 29 #include "mw_message.h" | |
| 30 #include "mw_service.h" | |
| 31 #include "mw_session.h" | |
| 32 #include "mw_util.h" | |
| 33 | |
| 34 | |
| 35 /** the hash table key for a service, for mwSession::services */ | |
| 36 #define SERVICE_KEY(srvc) mwService_getType(srvc) | |
| 37 | |
| 38 /** the hash table key for a cipher, for mwSession::ciphers */ | |
| 39 #define CIPHER_KEY(ciph) mwCipher_getType(ciph) | |
| 40 | |
| 41 | |
| 42 #define GPOINTER(val) (GUINT_TO_POINTER((guint) (val))) | |
| 43 #define GUINT(val) (GPOINTER_TO_UINT((val))) | |
| 44 | |
| 45 | |
| 46 struct mwSession { | |
| 47 | |
| 48 /** provides I/O and callback functions */ | |
| 49 struct mwSessionHandler *handler; | |
| 50 | |
| 51 enum mwSessionState state; /**< session state */ | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
52 gpointer state_info; /**< additional state info */ |
| 10969 | 53 |
| 54 /* input buffering for an incoming message */ | |
| 55 char *buf; /**< buffer for incoming message data */ | |
| 56 gsize buf_len; /**< length of buf */ | |
| 57 gsize buf_used; /**< offset to last-used byte of buf */ | |
| 58 | |
| 59 struct mwLoginInfo login; /**< login information */ | |
| 60 struct mwUserStatus status; /**< user status */ | |
| 61 struct mwPrivacyInfo privacy; /**< privacy list */ | |
| 62 | |
| 63 /** the collection of channels */ | |
| 64 struct mwChannelSet *channels; | |
| 65 | |
| 66 /** the collection of services, keyed to guint32 service id */ | |
| 67 GHashTable *services; | |
| 68 | |
| 69 /** the collection of ciphers, keyed to guint16 cipher type */ | |
| 70 GHashTable *ciphers; | |
| 71 | |
| 72 /** arbitrary key:value pairs */ | |
| 73 GHashTable *attributes; | |
| 74 | |
| 75 /** optional user data */ | |
| 76 struct mw_datum client_data; | |
| 77 }; | |
| 78 | |
| 79 | |
| 80 static void property_set(struct mwSession *s, const char *key, | |
| 81 gpointer val, GDestroyNotify clean) { | |
| 82 | |
| 83 g_hash_table_insert(s->attributes, g_strdup(key), | |
| 84 mw_datum_new(val, clean)); | |
| 85 } | |
| 86 | |
| 87 | |
| 88 static gpointer property_get(struct mwSession *s, const char *key) { | |
| 89 struct mw_datum *p = g_hash_table_lookup(s->attributes, key); | |
| 90 return p? p->data: NULL; | |
| 91 } | |
| 92 | |
| 93 | |
| 94 static void property_del(struct mwSession *s, const char *key) { | |
| 95 g_hash_table_remove(s->attributes, key); | |
| 96 } | |
| 97 | |
| 98 | |
| 99 /** | |
| 100 set up the default properties for a newly created session | |
| 101 */ | |
| 102 static void session_defaults(struct mwSession *s) { | |
| 103 property_set(s, mwSession_CLIENT_VER_MAJOR, | |
| 104 GPOINTER(MW_PROTOCOL_VERSION_MAJOR), NULL); | |
| 105 | |
| 106 property_set(s, mwSession_CLIENT_VER_MINOR, | |
| 107 GPOINTER(MW_PROTOCOL_VERSION_MINOR), NULL); | |
| 108 | |
| 109 property_set(s, mwSession_CLIENT_TYPE_ID, | |
| 110 GPOINTER(mwLogin_MEANWHILE), NULL); | |
| 111 } | |
| 112 | |
| 113 | |
| 114 struct mwSession *mwSession_new(struct mwSessionHandler *handler) { | |
| 115 struct mwSession *s; | |
| 116 | |
| 117 g_return_val_if_fail(handler != NULL, NULL); | |
| 118 | |
| 119 /* consider io_write and io_close to be absolute necessities */ | |
| 120 g_return_val_if_fail(handler->io_write != NULL, NULL); | |
| 121 g_return_val_if_fail(handler->io_close != NULL, NULL); | |
| 122 | |
| 123 s = g_new0(struct mwSession, 1); | |
| 124 | |
| 125 s->state = mwSession_STOPPED; | |
| 126 | |
| 127 s->handler = handler; | |
| 128 | |
| 129 s->channels = mwChannelSet_new(s); | |
| 130 s->services = map_guint_new(); | |
| 131 s->ciphers = map_guint_new(); | |
| 132 | |
| 133 s->attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, | |
| 134 (GDestroyNotify) mw_datum_free); | |
| 135 | |
| 136 session_defaults(s); | |
| 137 | |
| 138 return s; | |
| 139 } | |
| 140 | |
| 141 | |
| 142 /** free and reset the session buffer */ | |
| 143 static void session_buf_free(struct mwSession *s) { | |
| 144 g_return_if_fail(s != NULL); | |
| 145 | |
| 146 g_free(s->buf); | |
| 147 s->buf = NULL; | |
| 148 s->buf_len = 0; | |
| 149 s->buf_used = 0; | |
| 150 } | |
| 151 | |
| 152 | |
| 153 /** a polite string version of the session state enum */ | |
| 154 static const char *state_str(enum mwSessionState state) { | |
| 155 switch(state) { | |
| 156 case mwSession_STARTING: return "starting"; | |
| 157 case mwSession_HANDSHAKE: return "handshake sent"; | |
| 158 case mwSession_HANDSHAKE_ACK: return "handshake acknowledged"; | |
| 159 case mwSession_LOGIN: return "login sent"; | |
| 160 case mwSession_LOGIN_REDIR: return "login redirected"; | |
| 161 case mwSession_LOGIN_CONT: return "forcing login"; | |
| 162 case mwSession_LOGIN_ACK: return "login acknowledged"; | |
| 163 case mwSession_STARTED: return "started"; | |
| 164 case mwSession_STOPPING: return "stopping"; | |
| 165 case mwSession_STOPPED: return "stopped"; | |
| 166 | |
| 167 case mwSession_UNKNOWN: /* fall-through */ | |
| 168 default: return "UNKNOWN"; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 | |
| 173 void mwSession_free(struct mwSession *s) { | |
| 174 struct mwSessionHandler *h; | |
| 175 | |
| 176 g_return_if_fail(s != NULL); | |
| 177 | |
| 178 if(! mwSession_isStopped(s)) { | |
| 179 g_debug("session is not stopped (state: %s), proceeding with free", | |
| 180 state_str(s->state)); | |
| 181 } | |
| 182 | |
| 183 h = s->handler; | |
| 184 if(h) h->clear(s); | |
| 185 s->handler = NULL; | |
| 186 | |
| 187 session_buf_free(s); | |
| 188 | |
| 189 mwChannelSet_free(s->channels); | |
| 190 g_hash_table_destroy(s->services); | |
| 191 g_hash_table_destroy(s->ciphers); | |
| 192 g_hash_table_destroy(s->attributes); | |
| 193 | |
| 194 mwLoginInfo_clear(&s->login); | |
| 195 mwUserStatus_clear(&s->status); | |
| 196 mwPrivacyInfo_clear(&s->privacy); | |
| 197 | |
| 198 g_free(s); | |
| 199 } | |
| 200 | |
| 201 | |
| 202 /** write data to the session handler */ | |
| 203 static int io_write(struct mwSession *s, const char *buf, gsize len) { | |
| 204 g_return_val_if_fail(s != NULL, -1); | |
| 205 g_return_val_if_fail(s->handler != NULL, -1); | |
| 206 g_return_val_if_fail(s->handler->io_write != NULL, -1); | |
| 207 | |
| 208 return s->handler->io_write(s, buf, len); | |
| 209 } | |
| 210 | |
| 211 | |
| 212 /** close the session handler */ | |
| 213 static void io_close(struct mwSession *s) { | |
| 214 g_return_if_fail(s != NULL); | |
| 215 g_return_if_fail(s->handler != NULL); | |
| 216 g_return_if_fail(s->handler->io_close != NULL); | |
| 217 | |
| 218 s->handler->io_close(s); | |
| 219 } | |
| 220 | |
| 221 | |
| 222 static void state(struct mwSession *s, enum mwSessionState state, | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
223 gpointer info) { |
| 10969 | 224 |
| 225 struct mwSessionHandler *sh; | |
| 226 | |
| 227 g_return_if_fail(s != NULL); | |
| 228 g_return_if_fail(s->handler != NULL); | |
| 229 | |
| 230 if(mwSession_isState(s, state)) return; | |
| 231 | |
| 232 s->state = state; | |
| 233 s->state_info = info; | |
| 234 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
235 switch(state) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
236 case mwSession_STOPPING: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
237 case mwSession_STOPPED: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
238 g_message("session state: %s (0x%08x)", state_str(state), |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
239 GPOINTER_TO_UINT(info)); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
240 break; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
241 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
242 case mwSession_LOGIN_REDIR: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
243 g_message("session state: %s (%s)", state_str(state), |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
244 (char *)info); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
245 break; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
246 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
247 default: |
| 10969 | 248 g_message("session state: %s", state_str(state)); |
| 249 } | |
| 250 | |
| 251 sh = s->handler; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
252 if(sh && sh->on_stateChange) |
| 10969 | 253 sh->on_stateChange(s, state, info); |
| 254 } | |
| 255 | |
| 256 | |
| 257 void mwSession_start(struct mwSession *s) { | |
| 258 struct mwMsgHandshake *msg; | |
| 259 int ret; | |
| 260 | |
| 261 g_return_if_fail(s != NULL); | |
| 262 g_return_if_fail(mwSession_isStopped(s)); | |
| 263 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
264 if(mwSession_isStarted(s) || mwSession_isStarting(s)) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
265 g_debug("attempted to start session that is already started/starting"); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
266 return; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
267 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
268 |
| 10969 | 269 state(s, mwSession_STARTING, 0); |
| 270 | |
| 271 msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE); | |
| 272 msg->major = GUINT(property_get(s, mwSession_CLIENT_VER_MAJOR)); | |
| 273 msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR)); | |
| 274 msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); | |
| 275 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
276 msg->loclcalc_addr = GUINT(property_get(s, mwSession_CLIENT_IP)); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
277 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
278 if(msg->major >= 0x001e && msg->minor >= 0x001d) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
279 msg->unknown_a = 0x0100; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
280 msg->local_host = (char *) property_get(s, mwSession_CLIENT_HOST); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
281 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
282 |
| 10969 | 283 ret = mwSession_send(s, MW_MESSAGE(msg)); |
| 284 mwMessage_free(MW_MESSAGE(msg)); | |
| 285 | |
| 286 if(ret) { | |
| 287 mwSession_stop(s, CONNECTION_BROKEN); | |
| 288 } else { | |
| 289 state(s, mwSession_HANDSHAKE, 0); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 | |
| 294 void mwSession_stop(struct mwSession *s, guint32 reason) { | |
| 295 GList *list, *l = NULL; | |
| 296 struct mwMsgChannelDestroy *msg; | |
| 297 | |
| 298 g_return_if_fail(s != NULL); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
299 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
300 if(mwSession_isStopped(s) || mwSession_isStopping(s)) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
301 g_debug("attempted to stop session that is already stopped/stopping"); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
302 return; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
303 } |
| 10969 | 304 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
305 state(s, mwSession_STOPPING, GUINT_TO_POINTER(reason)); |
| 10969 | 306 |
| 307 for(list = l = mwSession_getServices(s); l; l = l->next) | |
| 308 mwService_stop(MW_SERVICE(l->data)); | |
| 309 g_list_free(list); | |
| 310 | |
| 311 msg = (struct mwMsgChannelDestroy *) | |
| 312 mwMessage_new(mwMessage_CHANNEL_DESTROY); | |
| 313 | |
| 314 msg->head.channel = MW_MASTER_CHANNEL_ID; | |
| 315 msg->reason = reason; | |
| 316 | |
| 317 /* don't care if this fails, we're closing the connection anyway */ | |
| 318 mwSession_send(s, MW_MESSAGE(msg)); | |
| 319 mwMessage_free(MW_MESSAGE(msg)); | |
| 320 | |
| 321 session_buf_free(s); | |
| 322 | |
| 323 /* close the connection */ | |
| 324 io_close(s); | |
| 325 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
326 state(s, mwSession_STOPPED, GUINT_TO_POINTER(reason)); |
| 10969 | 327 } |
| 328 | |
| 329 | |
| 330 /** compose authentication information into an opaque based on the | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
331 password, encrypted via RC2/40 */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
332 static void compose_auth_rc2_40(struct mwOpaque *auth, const char *pass) { |
| 10969 | 333 char iv[8], key[5]; |
| 334 struct mwOpaque a, b, z; | |
| 335 struct mwPutBuffer *p; | |
| 336 | |
| 337 /* get an IV and a random five-byte key */ | |
| 338 mwIV_init((char *) iv); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
339 mwKeyRandom((char *) key, 5); |
| 10969 | 340 |
| 341 /* the opaque with the key */ | |
| 342 a.len = 5; | |
| 343 a.data = key; | |
| 344 | |
| 345 /* the opaque to receive the encrypted pass */ | |
| 346 b.len = 0; | |
| 347 b.data = NULL; | |
| 348 | |
| 349 /* the plain-text pass dressed up as an opaque */ | |
| 350 z.len = strlen(pass); | |
| 351 z.data = (char *) pass; | |
| 352 | |
| 353 /* the opaque with the encrypted pass */ | |
| 354 mwEncrypt(a.data, a.len, iv, &z, &b); | |
| 355 | |
| 356 /* an opaque containing the other two opaques */ | |
| 357 p = mwPutBuffer_new(); | |
| 358 mwOpaque_put(p, &a); | |
| 359 mwOpaque_put(p, &b); | |
| 360 mwPutBuffer_finalize(auth, p); | |
| 361 | |
| 362 /* this is the only one to clear, as the other uses a static buffer */ | |
| 363 mwOpaque_clear(&b); | |
| 364 } | |
| 365 | |
| 366 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
367 static void compose_auth_rc2_128(struct mwOpaque *auth, const char *pass, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
368 guint32 magic, struct mwOpaque *rkey) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
369 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
370 char iv[8]; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
371 struct mwOpaque a, b, c; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
372 struct mwPutBuffer *p; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
373 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
374 mpz_t private, public; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
375 mpz_t remote; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
376 mpz_t shared; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
377 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
378 mpz_init(private); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
379 mpz_init(public); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
380 mpz_init(remote); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
381 mpz_init(shared); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
382 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
383 mwIV_init(iv); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
384 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
385 mwDHRandKeypair(private, public); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
386 mwDHImportKey(remote, rkey); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
387 mwDHCalculateShared(shared, remote, private); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
388 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
389 /* put the password in opaque a */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
390 p = mwPutBuffer_new(); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
391 guint32_put(p, magic); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
392 mwString_put(p, pass); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
393 mwPutBuffer_finalize(&a, p); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
394 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
395 /* put the shared key in opaque b */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
396 mwDHExportKey(shared, &b); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
397 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
398 /* encrypt the password (a) using the shared key (b), put the result |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
399 in opaque c */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
400 mwEncrypt(b.data+(b.len-16), 16, iv, &a, &c); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
401 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
402 /* don't need the shared key anymore, re-use opaque (b) as the |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
403 export of the public key */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
404 mwOpaque_clear(&b); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
405 mwDHExportKey(public, &b); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
406 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
407 p = mwPutBuffer_new(); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
408 guint16_put(p, 0x0001); /* XXX: unknown */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
409 mwOpaque_put(p, &b); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
410 mwOpaque_put(p, &c); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
411 mwPutBuffer_finalize(auth, p); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
412 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
413 mwOpaque_clear(&a); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
414 mwOpaque_clear(&b); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
415 mwOpaque_clear(&c); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
416 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
417 mpz_clear(private); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
418 mpz_clear(public); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
419 mpz_clear(remote); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
420 mpz_clear(shared); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
421 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
422 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
423 |
| 10969 | 424 /** handle the receipt of a handshake_ack message by sending the login |
| 425 message */ | |
| 426 static void HANDSHAKE_ACK_recv(struct mwSession *s, | |
| 427 struct mwMsgHandshakeAck *msg) { | |
| 428 struct mwMsgLogin *log; | |
| 429 int ret; | |
| 430 | |
| 431 g_return_if_fail(s != NULL); | |
| 432 g_return_if_fail(msg != NULL); | |
| 433 g_return_if_fail(mwSession_isState(s, mwSession_HANDSHAKE) || | |
| 434 mwSession_isState(s, mwSession_LOGIN_CONT)); | |
| 435 | |
| 436 if(mwSession_isState(s, mwSession_LOGIN_CONT)) { | |
| 437 /* this is a login continuation, don't re-send the login. We | |
| 438 should receive a login ack in a moment */ | |
| 439 | |
| 440 state(s, mwSession_HANDSHAKE_ACK, 0); | |
| 441 state(s, mwSession_LOGIN, 0); | |
| 442 return; | |
| 443 | |
| 444 } else { | |
| 445 state(s, mwSession_HANDSHAKE_ACK, 0); | |
| 446 } | |
| 447 | |
| 448 /* record the major/minor versions from the server */ | |
| 449 property_set(s, mwSession_SERVER_VER_MAJOR, GPOINTER(msg->major), NULL); | |
| 450 property_set(s, mwSession_SERVER_VER_MINOR, GPOINTER(msg->minor), NULL); | |
| 451 | |
| 452 /* compose the login message */ | |
| 453 log = (struct mwMsgLogin *) mwMessage_new(mwMessage_LOGIN); | |
| 454 log->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); | |
| 455 log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID)); | |
| 456 | |
| 457 /** @todo default to password for now. later use token optionally */ | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
458 { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
459 const char *pw; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
460 pw = (const char *) property_get(s, mwSession_AUTH_PASSWORD); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
461 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
462 if(msg->data.len >= 64) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
463 /* good login encryption */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
464 log->auth_type = mwAuthType_RC2_128; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
465 compose_auth_rc2_128(&log->auth_data, pw, msg->magic, &msg->data); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
466 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
467 } else { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
468 /* BAD login encryption */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
469 log->auth_type = mwAuthType_RC2_40; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
470 compose_auth_rc2_40(&log->auth_data, pw); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
471 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
472 } |
| 10969 | 473 |
| 474 /* send the login message */ | |
| 475 ret = mwSession_send(s, MW_MESSAGE(log)); | |
| 476 mwMessage_free(MW_MESSAGE(log)); | |
| 477 | |
| 478 if(! ret) { | |
| 479 /* sent login OK, set state appropriately */ | |
| 480 state(s, mwSession_LOGIN, 0); | |
| 481 } | |
| 482 } | |
| 483 | |
| 484 | |
| 485 /** handle the receipt of a login_ack message. This completes the | |
| 486 startup sequence for the session */ | |
| 487 static void LOGIN_ACK_recv(struct mwSession *s, | |
| 488 struct mwMsgLoginAck *msg) { | |
| 489 GList *ll, *l; | |
| 490 | |
| 491 g_return_if_fail(s != NULL); | |
| 492 g_return_if_fail(msg != NULL); | |
| 493 g_return_if_fail(mwSession_isState(s, mwSession_LOGIN)); | |
| 494 | |
| 495 /* store the login information in the session */ | |
| 496 mwLoginInfo_clear(&s->login); | |
| 497 mwLoginInfo_clone(&s->login, &msg->login); | |
| 498 | |
| 499 state(s, mwSession_LOGIN_ACK, 0); | |
| 500 | |
| 501 /* start up our services */ | |
| 502 for(ll = l = mwSession_getServices(s); l; l = l->next) { | |
| 503 mwService_start(l->data); | |
| 504 } | |
| 505 g_list_free(ll); | |
| 506 | |
| 507 /* @todo any further startup stuff? */ | |
| 508 | |
| 509 state(s, mwSession_STARTED, 0); | |
| 510 } | |
| 511 | |
| 512 | |
| 513 static void CHANNEL_CREATE_recv(struct mwSession *s, | |
| 514 struct mwMsgChannelCreate *msg) { | |
| 515 struct mwChannel *chan; | |
| 516 chan = mwChannel_newIncoming(s->channels, msg->channel); | |
| 517 | |
| 518 /* hand off to channel */ | |
| 519 mwChannel_recvCreate(chan, msg); | |
| 520 } | |
| 521 | |
| 522 | |
| 523 static void CHANNEL_ACCEPT_recv(struct mwSession *s, | |
| 524 struct mwMsgChannelAccept *msg) { | |
| 525 struct mwChannel *chan; | |
| 526 chan = mwChannel_find(s->channels, msg->head.channel); | |
| 527 | |
| 528 g_return_if_fail(chan != NULL); | |
| 529 | |
| 530 /* hand off to channel */ | |
| 531 mwChannel_recvAccept(chan, msg); | |
| 532 } | |
| 533 | |
| 534 | |
| 535 static void CHANNEL_DESTROY_recv(struct mwSession *s, | |
| 536 struct mwMsgChannelDestroy *msg) { | |
| 537 | |
| 538 /* the server can indicate that we should close the session by | |
| 539 destroying the zero channel */ | |
| 540 if(msg->head.channel == MW_MASTER_CHANNEL_ID) { | |
| 541 mwSession_stop(s, msg->reason); | |
| 542 | |
| 543 } else { | |
| 544 struct mwChannel *chan; | |
| 545 chan = mwChannel_find(s->channels, msg->head.channel); | |
| 546 | |
| 547 /* we don't have any such channel... so I guess we destroyed it. | |
| 548 This is to remove a warning from timing errors when two clients | |
| 549 both try to close a channel at about the same time. */ | |
| 550 if(! chan) return; | |
| 551 | |
| 552 /* hand off to channel */ | |
| 553 mwChannel_recvDestroy(chan, msg); | |
| 554 } | |
| 555 } | |
| 556 | |
| 557 | |
| 558 static void CHANNEL_SEND_recv(struct mwSession *s, | |
| 559 struct mwMsgChannelSend *msg) { | |
| 560 struct mwChannel *chan; | |
| 561 chan = mwChannel_find(s->channels, msg->head.channel); | |
| 562 | |
| 563 /* if we don't have any such channel, we're certainly not going to | |
| 564 accept data from it */ | |
| 565 if(! chan) return; | |
| 566 | |
| 567 /* hand off to channel */ | |
| 568 mwChannel_recv(chan, msg); | |
| 569 } | |
| 570 | |
| 571 | |
| 572 static void SET_PRIVACY_LIST_recv(struct mwSession *s, | |
| 573 struct mwMsgSetPrivacyList *msg) { | |
| 574 struct mwSessionHandler *sh = s->handler; | |
| 575 | |
| 576 g_info("SET_PRIVACY_LIST"); | |
| 577 | |
| 578 mwPrivacyInfo_clear(&s->privacy); | |
| 579 mwPrivacyInfo_clone(&s->privacy, &msg->privacy); | |
| 580 | |
| 581 if(sh && sh->on_setPrivacyInfo) | |
| 582 sh->on_setPrivacyInfo(s); | |
| 583 } | |
| 584 | |
| 585 | |
| 586 static void SET_USER_STATUS_recv(struct mwSession *s, | |
| 587 struct mwMsgSetUserStatus *msg) { | |
| 588 struct mwSessionHandler *sh = s->handler; | |
| 589 | |
| 590 mwUserStatus_clear(&s->status); | |
| 591 mwUserStatus_clone(&s->status, &msg->status); | |
| 592 | |
| 593 if(sh && sh->on_setUserStatus) | |
| 594 sh->on_setUserStatus(s); | |
| 595 } | |
| 596 | |
| 597 | |
| 598 static void SENSE_SERVICE_recv(struct mwSession *s, | |
| 599 struct mwMsgSenseService *msg) { | |
| 600 struct mwService *srvc; | |
| 601 | |
| 602 srvc = mwSession_getService(s, msg->service); | |
| 603 if(srvc) mwService_start(srvc); | |
| 604 } | |
| 605 | |
| 606 | |
| 607 static void ADMIN_recv(struct mwSession *s, struct mwMsgAdmin *msg) { | |
| 608 struct mwSessionHandler *sh = s->handler; | |
| 609 | |
| 610 if(sh && sh->on_admin) | |
| 611 sh->on_admin(s, msg->text); | |
| 612 } | |
| 613 | |
| 614 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
615 static void ANNOUNCE_recv(struct mwSession *s, struct mwMsgAnnounce *msg) { |
| 10969 | 616 struct mwSessionHandler *sh = s->handler; |
| 617 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
618 if(sh && sh->on_announce) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
619 sh->on_announce(s, &msg->sender, msg->may_reply, msg->text); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
620 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
621 |
| 10969 | 622 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
623 static void LOGIN_REDIRECT_recv(struct mwSession *s, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
624 struct mwMsgLoginRedirect *msg) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
625 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
626 state(s, mwSession_LOGIN_REDIR, msg->host); |
| 10969 | 627 } |
| 628 | |
| 629 | |
| 630 #define CASE(var, type) \ | |
| 631 case mwMessage_ ## var: \ | |
| 632 var ## _recv(s, (struct type *) msg); \ | |
| 633 break; | |
| 634 | |
| 635 | |
| 636 static void session_process(struct mwSession *s, | |
| 637 const char *buf, gsize len) { | |
| 638 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
639 struct mwOpaque o = { .len = len, .data = (char *) buf }; |
| 10969 | 640 struct mwGetBuffer *b; |
| 641 struct mwMessage *msg; | |
| 642 | |
| 11291 | 643 g_return_if_fail(s != NULL); |
| 10969 | 644 g_return_if_fail(buf != NULL); |
| 645 | |
| 646 /* ignore zero-length messages */ | |
| 647 if(len == 0) return; | |
| 648 | |
| 649 /* wrap up buf */ | |
| 650 b = mwGetBuffer_wrap(&o); | |
| 651 | |
| 652 /* attempt to parse the message. */ | |
| 653 msg = mwMessage_get(b); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
654 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
655 if(mwGetBuffer_error(b)) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
656 mw_mailme_opaque(&o, "parsing of message failed"); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
657 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
658 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
659 mwGetBuffer_free(b); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
660 |
| 10969 | 661 g_return_if_fail(msg != NULL); |
| 662 | |
| 663 /* handle each of the appropriate incoming types of mwMessage */ | |
| 664 switch(msg->type) { | |
| 665 CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); | |
| 666 CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); | |
| 667 CASE(LOGIN_ACK, mwMsgLoginAck); | |
| 668 CASE(CHANNEL_CREATE, mwMsgChannelCreate); | |
| 669 CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); | |
| 670 CASE(CHANNEL_SEND, mwMsgChannelSend); | |
| 671 CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); | |
| 672 CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); | |
| 673 CASE(SET_USER_STATUS, mwMsgSetUserStatus); | |
| 674 CASE(SENSE_SERVICE, mwMsgSenseService); | |
| 675 CASE(ADMIN, mwMsgAdmin); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
676 CASE(ANNOUNCE, mwMsgAnnounce); |
| 10969 | 677 |
| 678 default: | |
| 679 g_warning("unknown message type 0x%04x, no handler", msg->type); | |
| 680 } | |
| 681 | |
| 682 mwMessage_free(msg); | |
| 683 } | |
| 684 | |
| 685 | |
| 686 #undef CASE | |
| 687 | |
| 688 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
689 #define ADVANCE(b, n, count) { b += count; n -= count; } |
| 10969 | 690 |
| 691 | |
| 692 /* handle input to complete an existing buffer */ | |
| 693 static gsize session_recv_cont(struct mwSession *s, const char *b, gsize n) { | |
| 694 | |
| 695 /* determine how many bytes still required */ | |
| 696 gsize x = s->buf_len - s->buf_used; | |
| 697 | |
| 698 /* g_message(" session_recv_cont: session = %p, b = %p, n = %u", | |
| 699 s, b, n); */ | |
| 700 | |
| 701 if(n < x) { | |
| 702 /* not quite enough; still need some more */ | |
| 703 memcpy(s->buf+s->buf_used, b, n); | |
| 704 s->buf_used += n; | |
| 705 return 0; | |
| 706 | |
| 707 } else { | |
| 708 /* enough to finish the buffer, at least */ | |
| 709 memcpy(s->buf+s->buf_used, b, x); | |
| 710 ADVANCE(b, n, x); | |
| 711 | |
| 712 if(s->buf_len == 4) { | |
| 713 /* if only the length bytes were being buffered, we'll now try | |
| 714 to complete an actual message */ | |
| 715 | |
| 716 struct mwOpaque o = { 4, s->buf }; | |
| 717 struct mwGetBuffer *gb = mwGetBuffer_wrap(&o); | |
| 718 x = guint32_peek(gb); | |
| 719 mwGetBuffer_free(gb); | |
| 720 | |
| 721 if(n < x) { | |
| 722 /* there isn't enough to meet the demands of the length, so | |
| 723 we'll buffer it for next time */ | |
| 724 | |
| 725 char *t; | |
| 726 x += 4; | |
| 727 t = (char *) g_malloc(x); | |
| 728 memcpy(t, s->buf, 4); | |
| 729 memcpy(t+4, b, n); | |
| 730 | |
| 731 session_buf_free(s); | |
| 732 | |
| 733 s->buf = t; | |
| 734 s->buf_len = x; | |
| 735 s->buf_used = n + 4; | |
| 736 return 0; | |
| 737 | |
| 738 } else { | |
| 739 /* there's enough (maybe more) for a full message. don't need | |
| 740 the old session buffer (which recall, was only the length | |
| 741 bytes) any more */ | |
| 742 | |
| 743 session_buf_free(s); | |
| 744 session_process(s, b, x); | |
| 745 ADVANCE(b, n, x); | |
| 746 } | |
| 747 | |
| 748 } else { | |
| 749 /* process the now-complete buffer. remember to skip the first | |
| 750 four bytes, since they're just the size count */ | |
| 751 session_process(s, s->buf+4, s->buf_len-4); | |
| 752 session_buf_free(s); | |
| 753 } | |
| 754 } | |
| 755 | |
| 756 return n; | |
| 757 } | |
| 758 | |
| 759 | |
| 760 /* handle input when there's nothing previously buffered */ | |
| 761 static gsize session_recv_empty(struct mwSession *s, const char *b, gsize n) { | |
| 762 struct mwOpaque o = { n, (char *) b }; | |
| 763 struct mwGetBuffer *gb; | |
| 764 gsize x; | |
| 765 | |
| 766 if(n < 4) { | |
| 767 /* uh oh. less than four bytes means we've got an incomplete | |
| 768 length indicator. Have to buffer to get the rest of it. */ | |
| 769 s->buf = (char *) g_malloc0(4); | |
| 770 memcpy(s->buf, b, n); | |
| 771 s->buf_len = 4; | |
| 772 s->buf_used = n; | |
| 773 return 0; | |
| 774 } | |
| 775 | |
| 776 /* peek at the length indicator. if it's a zero length message, | |
| 777 don't process, just skip it */ | |
| 778 gb = mwGetBuffer_wrap(&o); | |
| 779 x = guint32_peek(gb); | |
| 780 mwGetBuffer_free(gb); | |
| 781 if(! x) return n - 4; | |
| 782 | |
| 783 if(n < (x + 4)) { | |
| 784 /* if the total amount of data isn't enough to cover the length | |
| 785 bytes and the length indicated by those bytes, then we'll need | |
| 786 to buffer. This is where the DOS mentioned below in | |
| 787 session_recv takes place */ | |
| 788 | |
| 789 x += 4; | |
| 790 s->buf = (char *) g_malloc(x); | |
| 791 memcpy(s->buf, b, n); | |
| 792 s->buf_len = x; | |
| 793 s->buf_used = n; | |
| 794 return 0; | |
| 795 | |
| 796 } else { | |
| 797 /* advance past length bytes */ | |
| 798 ADVANCE(b, n, 4); | |
| 799 | |
| 800 /* process and advance */ | |
| 801 session_process(s, b, x); | |
| 802 ADVANCE(b, n, x); | |
| 803 | |
| 804 /* return left-over count */ | |
| 805 return n; | |
| 806 } | |
| 807 } | |
| 808 | |
| 809 | |
| 810 static gsize session_recv(struct mwSession *s, const char *b, gsize n) { | |
| 811 /* This is messy and kind of confusing. I'd like to simplify it at | |
| 812 some point, but the constraints are as follows: | |
| 813 | |
| 814 - buffer up to a single full message on the session buffer | |
| 815 - buffer must contain the four length bytes | |
| 816 - the four length bytes indicate how much we'll need to buffer | |
| 817 - the four length bytes might not arrive all at once, so it's | |
| 818 possible that we'll need to buffer to get them. | |
| 819 - since our buffering includes the length bytes, we know we | |
| 820 still have an incomplete length if the buffer length is only | |
| 821 four. */ | |
| 822 | |
| 823 /** @todo we should allow a compiled-in upper limit to message | |
| 824 sizes, and just drop messages over that size. However, to do that | |
| 825 we'd need to keep track of the size of a message and keep | |
| 826 dropping bytes until we'd fulfilled the entire length. eg: if we | |
| 827 receive a message size of 10MB, we need to pass up exactly 10MB | |
| 828 before it's safe to start processing the rest as a new | |
| 829 message. As it stands, a malicious packet from the server can run | |
| 830 us out of memory by indicating it's going to send us some | |
| 831 obscenely long message (even if it never actually sends it) */ | |
| 832 | |
| 833 /* g_message(" session_recv: session = %p, b = %p, n = %u", | |
| 834 s, b, n); */ | |
| 835 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
836 if(s->buf_len == 0) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
837 while(n && (*b & 0x80)) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
838 /* keep-alive and series bytes are ignored */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
839 ADVANCE(b, n, 1); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
840 } |
| 10969 | 841 } |
| 842 | |
| 843 if(n == 0) { | |
| 844 return 0; | |
| 845 | |
| 846 } else if(s->buf_len > 0) { | |
| 847 return session_recv_cont(s, b, n); | |
| 848 | |
| 849 } else { | |
| 850 return session_recv_empty(s, b, n); | |
| 851 } | |
| 852 } | |
| 853 | |
| 854 | |
| 855 #undef ADVANCE | |
| 856 | |
| 857 | |
| 858 void mwSession_recv(struct mwSession *s, const char *buf, gsize n) { | |
| 859 char *b = (char *) buf; | |
| 860 gsize remain = 0; | |
| 861 | |
| 862 g_return_if_fail(s != NULL); | |
| 863 | |
| 864 while(n > 0) { | |
| 865 remain = session_recv(s, b, n); | |
| 866 b += (n - remain); | |
| 867 n = remain; | |
| 868 } | |
| 869 } | |
| 870 | |
| 871 | |
| 872 int mwSession_send(struct mwSession *s, struct mwMessage *msg) { | |
| 873 struct mwPutBuffer *b; | |
| 874 struct mwOpaque o; | |
| 875 int ret = 0; | |
| 876 | |
| 877 g_return_val_if_fail(s != NULL, -1); | |
| 878 | |
| 879 /* writing nothing is easy */ | |
| 880 if(! msg) return 0; | |
| 881 | |
| 882 /* first we render the message into an opaque */ | |
| 883 b = mwPutBuffer_new(); | |
| 884 mwMessage_put(b, msg); | |
| 885 mwPutBuffer_finalize(&o, b); | |
| 886 | |
| 887 /* then we render the opaque into... another opaque! */ | |
| 888 b = mwPutBuffer_new(); | |
| 889 mwOpaque_put(b, &o); | |
| 890 mwOpaque_clear(&o); | |
| 891 mwPutBuffer_finalize(&o, b); | |
| 892 | |
| 893 /* then we use that opaque's data and length to write to the socket */ | |
| 894 ret = io_write(s, o.data, o.len); | |
| 895 mwOpaque_clear(&o); | |
| 896 | |
| 897 /* ensure we could actually write the message */ | |
| 898 if(! ret) { | |
| 899 | |
| 900 /* special case, as the server doesn't always respond to user | |
| 901 status messages. Thus, we trigger the event when we send the | |
| 902 messages as well as when we receive them */ | |
| 903 if(msg->type == mwMessage_SET_USER_STATUS) { | |
| 904 SET_USER_STATUS_recv(s, (struct mwMsgSetUserStatus *) msg); | |
| 905 } | |
| 906 } | |
| 907 | |
| 908 return ret; | |
| 909 } | |
| 910 | |
| 911 | |
| 912 int mwSession_sendKeepalive(struct mwSession *s) { | |
| 913 const char b = 0x80; | |
| 914 | |
| 915 g_return_val_if_fail(s != NULL, -1); | |
| 916 return io_write(s, &b, 1); | |
| 917 } | |
| 918 | |
| 919 | |
| 920 int mwSession_forceLogin(struct mwSession *s) { | |
| 921 struct mwMsgLoginContinue *msg; | |
| 922 int ret; | |
| 923 | |
| 924 g_return_val_if_fail(s != NULL, -1); | |
| 925 g_return_val_if_fail(mwSession_isState(s, mwSession_LOGIN_REDIR), -1); | |
| 926 | |
| 927 state(s, mwSession_LOGIN_CONT, 0x00); | |
| 928 | |
| 929 msg = (struct mwMsgLoginContinue *) | |
| 930 mwMessage_new(mwMessage_LOGIN_CONTINUE); | |
| 931 | |
| 932 ret = mwSession_send(s, MW_MESSAGE(msg)); | |
| 933 mwMessage_free(MW_MESSAGE(msg)); | |
| 934 | |
| 935 return ret; | |
| 936 } | |
| 937 | |
| 938 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
939 int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
940 const char *text, const GList *recipients) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
941 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
942 struct mwMsgAnnounce *msg; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
943 int ret; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
944 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
945 g_return_val_if_fail(s != NULL, -1); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
946 g_return_val_if_fail(mwSession_isStarted(s), -1); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
947 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
948 msg = (struct mwMsgAnnounce *) mwMessage_new(mwMessage_ANNOUNCE); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
949 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
950 msg->recipients = (GList *) recipients; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
951 msg->may_reply = may_reply; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
952 msg->text = g_strdup(text); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
953 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
954 ret = mwSession_send(s, MW_MESSAGE(msg)); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
955 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
956 msg->recipients = NULL; /* don't kill our recipients param */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
957 mwMessage_free(MW_MESSAGE(msg)); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
958 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
959 return ret; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
960 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
961 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
962 |
| 10969 | 963 struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) { |
| 964 g_return_val_if_fail(s != NULL, NULL); | |
| 965 return s->handler; | |
| 966 } | |
| 967 | |
| 968 | |
| 969 struct mwLoginInfo *mwSession_getLoginInfo(struct mwSession *s) { | |
| 970 g_return_val_if_fail(s != NULL, NULL); | |
| 971 return &s->login; | |
| 972 } | |
| 973 | |
| 974 | |
| 975 int mwSession_setPrivacyInfo(struct mwSession *s, | |
| 976 struct mwPrivacyInfo *privacy) { | |
| 977 | |
| 978 struct mwMsgSetPrivacyList *msg; | |
| 979 int ret; | |
| 980 | |
| 981 g_return_val_if_fail(s != NULL, -1); | |
| 982 g_return_val_if_fail(privacy != NULL, -1); | |
| 983 | |
| 984 msg = (struct mwMsgSetPrivacyList *) | |
| 985 mwMessage_new(mwMessage_SET_PRIVACY_LIST); | |
| 986 | |
| 987 mwPrivacyInfo_clone(&msg->privacy, privacy); | |
| 988 | |
| 989 ret = mwSession_send(s, MW_MESSAGE(msg)); | |
| 990 mwMessage_free(MW_MESSAGE(msg)); | |
| 991 | |
| 992 return ret; | |
| 993 } | |
| 994 | |
| 995 | |
| 996 struct mwPrivacyInfo *mwSession_getPrivacyInfo(struct mwSession *s) { | |
| 997 g_return_val_if_fail(s != NULL, NULL); | |
| 998 return &s->privacy; | |
| 999 } | |
| 1000 | |
| 1001 | |
| 1002 int mwSession_setUserStatus(struct mwSession *s, | |
| 1003 struct mwUserStatus *stat) { | |
| 1004 | |
| 1005 struct mwMsgSetUserStatus *msg; | |
| 1006 int ret; | |
| 1007 | |
| 1008 g_return_val_if_fail(s != NULL, -1); | |
| 1009 g_return_val_if_fail(stat != NULL, -1); | |
| 1010 | |
| 1011 msg = (struct mwMsgSetUserStatus *) | |
| 1012 mwMessage_new(mwMessage_SET_USER_STATUS); | |
| 1013 | |
| 1014 mwUserStatus_clone(&msg->status, stat); | |
| 1015 | |
| 1016 ret = mwSession_send(s, MW_MESSAGE(msg)); | |
| 1017 mwMessage_free(MW_MESSAGE(msg)); | |
| 1018 | |
| 1019 return ret; | |
| 1020 } | |
| 1021 | |
| 1022 | |
| 1023 struct mwUserStatus *mwSession_getUserStatus(struct mwSession *s) { | |
| 1024 g_return_val_if_fail(s != NULL, NULL); | |
| 1025 return &s->status; | |
| 1026 } | |
| 1027 | |
| 1028 | |
| 1029 enum mwSessionState mwSession_getState(struct mwSession *s) { | |
| 1030 g_return_val_if_fail(s != NULL, mwSession_UNKNOWN); | |
| 1031 return s->state; | |
| 1032 } | |
| 1033 | |
| 1034 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1035 gpointer mwSession_getStateInfo(struct mwSession *s) { |
| 10969 | 1036 g_return_val_if_fail(s != NULL, 0); |
| 1037 return s->state_info; | |
| 1038 } | |
| 1039 | |
| 1040 | |
| 1041 struct mwChannelSet *mwSession_getChannels(struct mwSession *session) { | |
| 1042 g_return_val_if_fail(session != NULL, NULL); | |
| 1043 return session->channels; | |
| 1044 } | |
| 1045 | |
| 1046 | |
| 1047 gboolean mwSession_addService(struct mwSession *s, struct mwService *srv) { | |
| 1048 g_return_val_if_fail(s != NULL, FALSE); | |
| 1049 g_return_val_if_fail(srv != NULL, FALSE); | |
| 1050 g_return_val_if_fail(s->services != NULL, FALSE); | |
| 1051 | |
| 1052 if(map_guint_lookup(s->services, SERVICE_KEY(srv))) { | |
| 1053 return FALSE; | |
| 1054 | |
| 1055 } else { | |
| 1056 map_guint_insert(s->services, SERVICE_KEY(srv), srv); | |
| 1057 if(mwSession_isState(s, mwSession_STARTED)) | |
| 1058 mwSession_senseService(s, mwService_getType(srv)); | |
| 1059 return TRUE; | |
| 1060 } | |
| 1061 } | |
| 1062 | |
| 1063 | |
| 1064 struct mwService *mwSession_getService(struct mwSession *s, guint32 srv) { | |
| 1065 g_return_val_if_fail(s != NULL, NULL); | |
| 1066 g_return_val_if_fail(s->services != NULL, NULL); | |
| 1067 | |
| 1068 return map_guint_lookup(s->services, srv); | |
| 1069 } | |
| 1070 | |
| 1071 | |
| 1072 struct mwService *mwSession_removeService(struct mwSession *s, guint32 srv) { | |
| 1073 struct mwService *svc; | |
| 1074 | |
| 1075 g_return_val_if_fail(s != NULL, NULL); | |
| 1076 g_return_val_if_fail(s->services != NULL, NULL); | |
| 1077 | |
| 1078 svc = map_guint_lookup(s->services, srv); | |
| 1079 if(svc) map_guint_remove(s->services, srv); | |
| 1080 return svc; | |
| 1081 } | |
| 1082 | |
| 1083 | |
| 1084 GList *mwSession_getServices(struct mwSession *s) { | |
| 1085 g_return_val_if_fail(s != NULL, NULL); | |
| 1086 g_return_val_if_fail(s->services != NULL, NULL); | |
| 1087 | |
| 1088 return map_collect_values(s->services); | |
| 1089 } | |
| 1090 | |
| 1091 | |
| 1092 void mwSession_senseService(struct mwSession *s, guint32 srvc) { | |
| 1093 struct mwMsgSenseService *msg; | |
| 1094 | |
| 1095 g_return_if_fail(s != NULL); | |
| 1096 g_return_if_fail(srvc != 0x00); | |
| 1097 g_return_if_fail(mwSession_isStarted(s)); | |
| 1098 | |
| 1099 msg = (struct mwMsgSenseService *) | |
| 1100 mwMessage_new(mwMessage_SENSE_SERVICE); | |
| 1101 msg->service = srvc; | |
| 1102 | |
| 1103 mwSession_send(s, MW_MESSAGE(msg)); | |
| 1104 mwMessage_free(MW_MESSAGE(msg)); | |
| 1105 } | |
| 1106 | |
| 1107 | |
| 1108 gboolean mwSession_addCipher(struct mwSession *s, struct mwCipher *c) { | |
| 1109 g_return_val_if_fail(s != NULL, FALSE); | |
| 1110 g_return_val_if_fail(c != NULL, FALSE); | |
| 1111 g_return_val_if_fail(s->ciphers != NULL, FALSE); | |
| 1112 | |
| 1113 if(map_guint_lookup(s->ciphers, mwCipher_getType(c))) { | |
| 1114 g_message("cipher %s is already added, apparently", | |
| 1115 NSTR(mwCipher_getName(c))); | |
| 1116 return FALSE; | |
| 1117 | |
| 1118 } else { | |
| 1119 g_message("adding cipher %s", NSTR(mwCipher_getName(c))); | |
| 1120 map_guint_insert(s->ciphers, mwCipher_getType(c), c); | |
| 1121 return TRUE; | |
| 1122 } | |
| 1123 } | |
| 1124 | |
| 1125 | |
| 1126 struct mwCipher *mwSession_getCipher(struct mwSession *s, guint16 c) { | |
| 1127 g_return_val_if_fail(s != NULL, NULL); | |
| 1128 g_return_val_if_fail(s->ciphers != NULL, NULL); | |
| 1129 | |
| 1130 return map_guint_lookup(s->ciphers, c); | |
| 1131 } | |
| 1132 | |
| 1133 | |
| 1134 struct mwCipher *mwSession_removeCipher(struct mwSession *s, guint16 c) { | |
| 1135 struct mwCipher *ciph; | |
| 1136 | |
| 1137 g_return_val_if_fail(s != NULL, NULL); | |
| 1138 g_return_val_if_fail(s->ciphers != NULL, NULL); | |
| 1139 | |
| 1140 ciph = map_guint_lookup(s->ciphers, c); | |
| 1141 if(ciph) map_guint_remove(s->ciphers, c); | |
| 1142 return ciph; | |
| 1143 } | |
| 1144 | |
| 1145 | |
| 1146 GList *mwSession_getCiphers(struct mwSession *s) { | |
| 1147 g_return_val_if_fail(s != NULL, NULL); | |
| 1148 g_return_val_if_fail(s->ciphers != NULL, NULL); | |
| 1149 | |
| 1150 return map_collect_values(s->ciphers); | |
| 1151 } | |
| 1152 | |
| 1153 | |
| 1154 void mwSession_setProperty(struct mwSession *s, const char *key, | |
| 1155 gpointer val, GDestroyNotify clean) { | |
| 1156 | |
| 1157 g_return_if_fail(s != NULL); | |
| 1158 g_return_if_fail(s->attributes != NULL); | |
| 1159 g_return_if_fail(key != NULL); | |
| 1160 | |
| 1161 property_set(s, key, val, clean); | |
| 1162 } | |
| 1163 | |
| 1164 | |
| 1165 gpointer mwSession_getProperty(struct mwSession *s, const char *key) { | |
| 1166 | |
| 1167 g_return_val_if_fail(s != NULL, NULL); | |
| 1168 g_return_val_if_fail(s->attributes != NULL, NULL); | |
| 1169 g_return_val_if_fail(key != NULL, NULL); | |
| 1170 | |
| 1171 return property_get(s, key); | |
| 1172 } | |
| 1173 | |
| 1174 | |
| 1175 void mwSession_removeProperty(struct mwSession *s, const char *key) { | |
| 1176 g_return_if_fail(s != NULL); | |
| 1177 g_return_if_fail(s->attributes != NULL); | |
| 1178 g_return_if_fail(key != NULL); | |
| 1179 | |
| 1180 property_del(s, key); | |
| 1181 } | |
| 1182 | |
| 1183 | |
| 1184 void mwSession_setClientData(struct mwSession *session, | |
| 1185 gpointer data, GDestroyNotify clear) { | |
| 1186 | |
| 1187 g_return_if_fail(session != NULL); | |
| 1188 mw_datum_set(&session->client_data, data, clear); | |
| 1189 } | |
| 1190 | |
| 1191 | |
| 1192 gpointer mwSession_getClientData(struct mwSession *session) { | |
| 1193 g_return_val_if_fail(session != NULL, NULL); | |
| 1194 return mw_datum_get(&session->client_data); | |
| 1195 } | |
| 1196 | |
| 1197 | |
| 1198 void mwSession_removeClientData(struct mwSession *session) { | |
| 1199 g_return_if_fail(session != NULL); | |
| 1200 mw_datum_clear(&session->client_data); | |
| 1201 } | |
| 1202 |
