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