Mercurial > pidgin
annotate src/protocols/sametime/meanwhile/channel.c @ 12264:2be62353f708
[gaim-migrate @ 14566]
this was TRUE in oldstatus
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Tue, 29 Nov 2005 23:50:39 +0000 |
| parents | 0110fc7c6a8a |
| 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 <glib/ghash.h> | |
| 23 #include <glib/glist.h> | |
| 24 #include <string.h> | |
| 25 | |
| 26 #include "mw_channel.h" | |
| 27 #include "mw_cipher.h" | |
| 28 #include "mw_debug.h" | |
| 29 #include "mw_error.h" | |
| 30 #include "mw_message.h" | |
| 31 #include "mw_service.h" | |
| 32 #include "mw_session.h" | |
| 33 #include "mw_util.h" | |
| 34 | |
| 35 | |
| 36 /** @todo reorganize this file, stuff is just strewn about */ | |
| 37 | |
| 38 | |
| 39 struct mwChannel { | |
| 40 | |
| 41 /** session this channel belongs to */ | |
| 42 struct mwSession *session; | |
| 43 | |
| 44 enum mwChannelState state; | |
| 45 | |
| 46 /** creator for incoming channel, target for outgoing channel */ | |
| 47 struct mwLoginInfo user; | |
| 48 | |
| 49 /* similar to data from the CreateCnl message in 8.4.1.7 */ | |
| 50 guint32 reserved; /**< special, unknown meaning */ | |
| 51 guint32 id; /**< channel ID */ | |
| 52 guint32 service; /**< service ID */ | |
| 53 guint32 proto_type; /**< service protocol type */ | |
| 54 guint32 proto_ver; /**< service protocol version */ | |
| 55 guint32 options; /**< channel options */ | |
| 56 | |
| 57 struct mwOpaque addtl_create; | |
| 58 struct mwOpaque addtl_accept; | |
| 59 | |
| 60 /** all those supported ciphers */ | |
| 61 GHashTable *supported; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
62 guint16 offered_policy; /**< @see enum mwEncryptPolicy */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
63 guint16 policy; /**< @see enum mwEncryptPolicy */ |
| 10969 | 64 |
| 65 /** cipher information determined at channel acceptance */ | |
| 66 struct mwCipherInstance *cipher; | |
| 67 | |
| 68 /** statistics table */ | |
| 69 GHashTable *stats; | |
| 70 | |
| 71 GSList *outgoing_queue; /**< queued outgoing messages */ | |
| 72 GSList *incoming_queue; /**< queued incoming messages */ | |
| 73 | |
| 74 struct mw_datum srvc_data; /**< service-specific data */ | |
| 75 }; | |
| 76 | |
| 77 | |
| 78 struct mwChannelSet { | |
| 79 struct mwSession *session; /**< owning session */ | |
| 80 GHashTable *map; /**< map of all channels, by ID */ | |
| 81 guint32 counter; /**< counter for outgoing ID */ | |
| 82 }; | |
| 83 | |
| 84 | |
| 85 static void flush_channel(struct mwChannel *); | |
| 86 | |
| 87 | |
| 88 static const char *state_str(enum mwChannelState state) { | |
| 89 switch(state) { | |
| 90 case mwChannel_NEW: return "new"; | |
| 91 case mwChannel_INIT: return "initializing"; | |
| 92 case mwChannel_WAIT: return "waiting"; | |
| 93 case mwChannel_OPEN: return "open"; | |
| 94 case mwChannel_DESTROY: return "closing"; | |
| 95 case mwChannel_ERROR: return "error"; | |
| 96 | |
| 97 case mwChannel_UNKNOWN: /* fall through */ | |
| 98 default: return "UNKNOWN"; | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
103 static void state(struct mwChannel *chan, enum mwChannelState state, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
104 guint32 err_code) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
105 |
| 10969 | 106 g_return_if_fail(chan != NULL); |
| 107 | |
| 108 if(chan->state == state) return; | |
| 109 | |
| 110 chan->state = state; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
111 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
112 if(err_code) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
113 g_message("channel 0x%08x state: %s (0x%08x)", |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
114 chan->id, state_str(state), err_code); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
115 } else { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
116 g_message("channel 0x%08x state: %s", chan->id, state_str(state)); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
117 } |
| 10969 | 118 } |
| 119 | |
| 120 | |
| 121 static gpointer get_stat(struct mwChannel *chan, | |
| 122 enum mwChannelStatField field) { | |
| 123 | |
| 124 return g_hash_table_lookup(chan->stats, (gpointer) field); | |
| 125 } | |
| 126 | |
| 127 | |
| 128 static void set_stat(struct mwChannel *chan, enum mwChannelStatField field, | |
| 129 gpointer val) { | |
| 130 | |
| 131 g_hash_table_insert(chan->stats, (gpointer) field, val); | |
| 132 } | |
| 133 | |
| 134 | |
| 135 #define incr_stat(chan, field, incr) \ | |
| 136 set_stat(chan, field, get_stat(chan, field) + incr) | |
| 137 | |
| 138 | |
| 139 #define timestamp_stat(chan, field) \ | |
| 140 set_stat(chan, field, (gpointer) time(NULL)) | |
| 141 | |
| 142 | |
| 143 static void sup_free(gpointer a) { | |
| 144 mwCipherInstance_free(a); | |
| 145 } | |
| 146 | |
| 147 | |
| 148 struct mwCipherInstance *get_supported(struct mwChannel *chan, guint16 id) { | |
| 149 guint32 cid = (guint32) id; | |
| 150 return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid)); | |
| 151 } | |
| 152 | |
| 153 | |
| 154 void put_supported(struct mwChannel *chan, struct mwCipherInstance *ci) { | |
| 155 struct mwCipher *cipher = mwCipherInstance_getCipher(ci); | |
| 156 guint32 cid = (guint32) mwCipher_getType(cipher); | |
| 157 g_hash_table_insert(chan->supported, GUINT_TO_POINTER(cid), ci); | |
| 158 } | |
| 159 | |
| 160 | |
| 161 struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *cs, guint32 id) { | |
| 162 struct mwChannel *chan; | |
| 163 | |
| 164 g_return_val_if_fail(cs != NULL, NULL); | |
| 165 g_return_val_if_fail(cs->session != NULL, NULL); | |
| 166 | |
| 167 chan = g_new0(struct mwChannel, 1); | |
| 168 chan->state = mwChannel_NEW; | |
| 169 chan->session = cs->session; | |
| 170 chan->id = id; | |
| 171 | |
| 172 chan->stats = g_hash_table_new(g_direct_hash, g_direct_equal); | |
| 173 | |
| 174 chan->supported = g_hash_table_new_full(g_direct_hash, g_direct_equal, | |
| 175 NULL, sup_free); | |
| 176 | |
| 177 g_hash_table_insert(cs->map, GUINT_TO_POINTER(id), chan); | |
| 178 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
179 state(chan, mwChannel_WAIT, 0); |
| 10969 | 180 |
| 181 return chan; | |
| 182 } | |
| 183 | |
| 184 | |
| 185 struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *cs) { | |
| 186 guint32 id; | |
| 187 struct mwChannel *chan; | |
| 188 | |
| 189 g_return_val_if_fail(cs != NULL, NULL); | |
| 190 g_return_val_if_fail(cs->map != NULL, NULL); | |
| 191 | |
| 192 /* grab the next id, and try to make sure there isn't already a | |
| 193 channel using it */ | |
| 194 do { | |
| 195 id = ++cs->counter; | |
| 196 } while(g_hash_table_lookup(cs->map, GUINT_TO_POINTER(id))); | |
| 197 | |
| 198 chan = mwChannel_newIncoming(cs, id); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
199 state(chan, mwChannel_INIT, 0); |
| 10969 | 200 |
| 201 return chan; | |
| 202 } | |
| 203 | |
| 204 | |
| 205 guint32 mwChannel_getId(struct mwChannel *chan) { | |
| 206 g_return_val_if_fail(chan != NULL, 0); | |
| 207 return chan->id; | |
| 208 } | |
| 209 | |
| 210 | |
| 211 struct mwSession *mwChannel_getSession(struct mwChannel *chan) { | |
| 212 g_return_val_if_fail(chan != NULL, NULL); | |
| 213 return chan->session; | |
| 214 } | |
| 215 | |
| 216 | |
| 217 guint32 mwChannel_getServiceId(struct mwChannel *chan) { | |
| 218 g_return_val_if_fail(chan != NULL, 0); | |
| 219 return chan->service; | |
| 220 } | |
| 221 | |
| 222 | |
| 223 struct mwService *mwChannel_getService(struct mwChannel *chan) { | |
| 224 g_return_val_if_fail(chan != NULL, NULL); | |
| 225 return mwSession_getService(chan->session, chan->service); | |
| 226 } | |
| 227 | |
| 228 | |
| 229 void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc) { | |
| 230 g_return_if_fail(chan != NULL); | |
| 231 g_return_if_fail(srvc != NULL); | |
| 232 g_return_if_fail(chan->state == mwChannel_INIT); | |
| 233 chan->service = mwService_getType(srvc); | |
| 234 } | |
| 235 | |
| 236 | |
| 237 gpointer mwChannel_getServiceData(struct mwChannel *chan) { | |
| 238 g_return_val_if_fail(chan != NULL, NULL); | |
| 239 return mw_datum_get(&chan->srvc_data); | |
| 240 } | |
| 241 | |
| 242 | |
| 243 void mwChannel_setServiceData(struct mwChannel *chan, | |
| 244 gpointer data, GDestroyNotify clean) { | |
| 245 | |
| 246 g_return_if_fail(chan != NULL); | |
| 247 mw_datum_set(&chan->srvc_data, data, clean); | |
| 248 } | |
| 249 | |
| 250 | |
| 251 void mwChannel_removeServiceData(struct mwChannel *chan) { | |
| 252 g_return_if_fail(chan != NULL); | |
| 253 mw_datum_clear(&chan->srvc_data); | |
| 254 } | |
| 255 | |
| 256 | |
| 257 guint32 mwChannel_getProtoType(struct mwChannel *chan) { | |
| 258 g_return_val_if_fail(chan != NULL, 0x00); | |
| 259 return chan->proto_type; | |
| 260 } | |
| 261 | |
| 262 | |
| 263 void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type) { | |
| 264 g_return_if_fail(chan != NULL); | |
| 265 g_return_if_fail(chan->state == mwChannel_INIT); | |
| 266 chan->proto_type = proto_type; | |
| 267 } | |
| 268 | |
| 269 | |
| 270 guint32 mwChannel_getProtoVer(struct mwChannel *chan) { | |
| 271 g_return_val_if_fail(chan != NULL, 0x00); | |
| 272 return chan->proto_ver; | |
| 273 } | |
| 274 | |
| 275 | |
| 276 void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver) { | |
| 277 g_return_if_fail(chan != NULL); | |
| 278 g_return_if_fail(chan->state == mwChannel_INIT); | |
| 279 chan->proto_ver = proto_ver; | |
| 280 } | |
| 281 | |
| 282 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
283 guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
284 g_return_val_if_fail(chan != NULL, 0x00); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
285 return chan->policy; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
286 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
287 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
288 |
| 10969 | 289 guint32 mwChannel_getOptions(struct mwChannel *chan) { |
| 290 g_return_val_if_fail(chan != NULL, 0x00); | |
| 291 return chan->options; | |
| 292 } | |
| 293 | |
| 294 | |
| 295 void mwChannel_setOptions(struct mwChannel *chan, guint32 options) { | |
| 296 g_return_if_fail(chan != NULL); | |
| 297 g_return_if_fail(chan->state == mwChannel_INIT); | |
| 298 chan->options = options; | |
| 299 } | |
| 300 | |
| 301 | |
| 302 struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan) { | |
| 303 g_return_val_if_fail(chan != NULL, NULL); | |
| 304 return &chan->user; | |
| 305 } | |
| 306 | |
| 307 | |
| 308 struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *chan) { | |
| 309 g_return_val_if_fail(chan != NULL, NULL); | |
| 310 return &chan->addtl_create; | |
| 311 } | |
| 312 | |
| 313 | |
| 314 struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *chan) { | |
| 315 g_return_val_if_fail(chan != NULL, NULL); | |
| 316 return &chan->addtl_accept; | |
| 317 } | |
| 318 | |
| 319 | |
| 320 struct mwCipherInstance *mwChannel_getCipherInstance(struct mwChannel *chan) { | |
| 321 g_return_val_if_fail(chan != NULL, NULL); | |
| 322 return chan->cipher; | |
| 323 } | |
| 324 | |
| 325 | |
| 326 enum mwChannelState mwChannel_getState(struct mwChannel *chan) { | |
| 327 g_return_val_if_fail(chan != NULL, mwChannel_UNKNOWN); | |
| 328 return chan->state; | |
| 329 } | |
| 330 | |
| 331 | |
| 332 gpointer mwChannel_getStatistic(struct mwChannel *chan, | |
| 333 enum mwChannelStatField stat) { | |
| 334 | |
| 335 g_return_val_if_fail(chan != NULL, 0); | |
| 336 g_return_val_if_fail(chan->stats != NULL, 0); | |
| 337 | |
| 338 return get_stat(chan, stat); | |
| 339 } | |
| 340 | |
| 341 | |
| 342 /* send a channel create message */ | |
| 343 int mwChannel_create(struct mwChannel *chan) { | |
| 344 struct mwMsgChannelCreate *msg; | |
| 345 GList *list, *l; | |
| 346 int ret; | |
| 347 | |
| 348 g_return_val_if_fail(chan != NULL, -1); | |
| 349 g_return_val_if_fail(chan->state == mwChannel_INIT, -1); | |
| 350 g_return_val_if_fail(mwChannel_isOutgoing(chan), -1); | |
| 351 | |
| 352 msg = (struct mwMsgChannelCreate *) | |
| 353 mwMessage_new(mwMessage_CHANNEL_CREATE); | |
| 354 | |
| 355 msg->channel = chan->id; | |
| 356 msg->target.user = g_strdup(chan->user.user_id); | |
| 357 msg->target.community = g_strdup(chan->user.community); | |
| 358 msg->service = chan->service; | |
| 359 msg->proto_type = chan->proto_type; | |
| 360 msg->proto_ver = chan->proto_ver; | |
| 361 msg->options = chan->options; | |
| 362 mwOpaque_clone(&msg->addtl, &chan->addtl_create); | |
| 363 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
364 list = mwChannel_getSupportedCipherInstances(chan); |
| 10969 | 365 if(list) { |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
366 /* offer what we have */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
367 for(l = list; l; l = l->next) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
368 struct mwEncryptItem *ei = mwCipherInstance_offer(l->data); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
369 msg->encrypt.items = g_list_append(msg->encrypt.items, ei); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
370 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
371 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
372 /* we're easy to get along with */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
373 chan->offered_policy = mwEncrypt_WHATEVER; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
374 g_list_free(list); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
375 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
376 } else { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
377 /* we apparently don't support anything */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
378 chan->offered_policy = mwEncrypt_NONE; |
| 10969 | 379 } |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
380 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
381 msg->encrypt.mode = chan->offered_policy; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
382 msg->encrypt.extra = chan->offered_policy; |
| 10969 | 383 |
| 384 ret = mwSession_send(chan->session, MW_MESSAGE(msg)); | |
| 385 mwMessage_free(MW_MESSAGE(msg)); | |
| 386 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
387 state(chan, (ret)? mwChannel_ERROR: mwChannel_WAIT, ret); |
| 10969 | 388 |
| 389 return ret; | |
| 390 } | |
| 391 | |
| 392 | |
| 393 static void channel_open(struct mwChannel *chan) { | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
394 state(chan, mwChannel_OPEN, 0); |
| 10969 | 395 timestamp_stat(chan, mwChannelStat_OPENED_AT); |
| 396 flush_channel(chan); | |
| 397 } | |
| 398 | |
| 399 | |
| 400 int mwChannel_accept(struct mwChannel *chan) { | |
| 401 struct mwSession *session; | |
| 402 struct mwMsgChannelAccept *msg; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
403 struct mwCipherInstance *ci; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
404 |
| 10969 | 405 int ret; |
| 406 | |
| 407 g_return_val_if_fail(chan != NULL, -1); | |
| 408 g_return_val_if_fail(mwChannel_isIncoming(chan), -1); | |
| 409 g_return_val_if_fail(chan->state == mwChannel_WAIT, -1); | |
| 410 | |
| 411 session = chan->session; | |
| 412 g_return_val_if_fail(session != NULL, -1); | |
| 413 | |
| 414 msg = (struct mwMsgChannelAccept *) | |
| 415 mwMessage_new(mwMessage_CHANNEL_ACCEPT); | |
| 416 | |
| 417 msg->head.channel = chan->id; | |
| 418 msg->service = chan->service; | |
| 419 msg->proto_type = chan->proto_type; | |
| 420 msg->proto_ver = chan->proto_ver; | |
| 421 mwOpaque_clone(&msg->addtl, &chan->addtl_accept); | |
| 422 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
423 ci = chan->cipher; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
424 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
425 if(! ci) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
426 /* automatically select a cipher if one hasn't been already */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
427 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
428 switch(chan->offered_policy) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
429 case mwEncrypt_NONE: |
| 10969 | 430 mwChannel_selectCipherInstance(chan, NULL); |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
431 break; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
432 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
433 case mwEncrypt_RC2_40: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
434 ci = get_supported(chan, mwCipher_RC2_40); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
435 mwChannel_selectCipherInstance(chan, ci); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
436 break; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
437 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
438 case mwEncrypt_RC2_128: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
439 ci = get_supported(chan, mwCipher_RC2_128); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
440 mwChannel_selectCipherInstance(chan, ci); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
441 break; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
442 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
443 case mwEncrypt_WHATEVER: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
444 case mwEncrypt_ALL: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
445 default: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
446 { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
447 GList *l, *ll; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
448 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
449 l = mwChannel_getSupportedCipherInstances(chan); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
450 if(l) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
451 /* nobody selected a cipher, so we'll just pick the last in |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
452 the list of available ones */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
453 for(ll = l; ll->next; ll = ll->next); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
454 ci = ll->data; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
455 g_list_free(l); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
456 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
457 mwChannel_selectCipherInstance(chan, ci); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
458 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
459 } else { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
460 /* this may cause breakage, but there's really nothing else |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
461 we can do. They want something we can't provide. If they |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
462 don't like it, then they'll error the channel out */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
463 mwChannel_selectCipherInstance(chan, NULL); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
464 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
465 } |
| 10969 | 466 } |
| 467 } | |
| 468 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
469 msg->encrypt.mode = chan->policy; /* set in selectCipherInstance */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
470 msg->encrypt.extra = chan->offered_policy; |
| 10969 | 471 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
472 if(chan->cipher) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
473 msg->encrypt.item = mwCipherInstance_accept(chan->cipher); |
| 10969 | 474 } |
| 475 | |
| 476 ret = mwSession_send(session, MW_MESSAGE(msg)); | |
| 477 mwMessage_free(MW_MESSAGE(msg)); | |
| 478 | |
| 479 if(ret) { | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
480 state(chan, mwChannel_ERROR, ret); |
| 10969 | 481 } else { |
| 482 channel_open(chan); | |
| 483 } | |
| 484 | |
| 485 return ret; | |
| 486 } | |
| 487 | |
| 488 | |
| 489 static void channel_free(struct mwChannel *chan) { | |
| 490 struct mwSession *s; | |
| 491 struct mwMessage *msg; | |
| 492 GSList *l; | |
| 493 | |
| 494 /* maybe no warning in the future */ | |
| 495 g_return_if_fail(chan != NULL); | |
| 496 | |
| 497 s = chan->session; | |
| 498 | |
| 499 mwLoginInfo_clear(&chan->user); | |
| 500 mwOpaque_clear(&chan->addtl_create); | |
| 501 mwOpaque_clear(&chan->addtl_accept); | |
| 502 | |
| 503 if(chan->supported) { | |
| 504 g_hash_table_destroy(chan->supported); | |
| 505 chan->supported = NULL; | |
| 506 } | |
| 507 | |
| 508 if(chan->stats) { | |
| 509 g_hash_table_destroy(chan->stats); | |
| 510 chan->stats = NULL; | |
| 511 } | |
| 512 | |
| 513 mwCipherInstance_free(chan->cipher); | |
| 514 | |
| 515 /* clean up the outgoing queue */ | |
| 516 for(l = chan->outgoing_queue; l; l = l->next) { | |
| 517 msg = (struct mwMessage *) l->data; | |
| 518 l->data = NULL; | |
| 519 mwMessage_free(msg); | |
| 520 } | |
| 521 g_slist_free(chan->outgoing_queue); | |
| 522 | |
| 523 /* clean up the incoming queue */ | |
| 524 for(l = chan->incoming_queue; l; l = l->next) { | |
| 525 msg = (struct mwMessage *) l->data; | |
| 526 l->data = NULL; | |
| 527 mwMessage_free(msg); | |
| 528 } | |
| 529 g_slist_free(chan->incoming_queue); | |
| 530 | |
| 531 g_free(chan); | |
| 532 } | |
| 533 | |
| 534 | |
| 535 int mwChannel_destroy(struct mwChannel *chan, | |
| 536 guint32 reason, struct mwOpaque *info) { | |
| 537 | |
| 538 struct mwMsgChannelDestroy *msg; | |
| 539 struct mwSession *session; | |
| 540 struct mwChannelSet *cs; | |
| 541 int ret; | |
| 542 | |
| 543 /* may make this not a warning in the future */ | |
| 544 g_return_val_if_fail(chan != NULL, 0); | |
| 545 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
546 state(chan, reason? mwChannel_ERROR: mwChannel_DESTROY, reason); |
| 10969 | 547 |
| 548 session = chan->session; | |
| 549 g_return_val_if_fail(session != NULL, -1); | |
| 550 | |
| 551 cs = mwSession_getChannels(session); | |
| 552 g_return_val_if_fail(cs != NULL, -1); | |
| 553 | |
| 554 /* compose the message */ | |
| 555 msg = (struct mwMsgChannelDestroy *) | |
| 556 mwMessage_new(mwMessage_CHANNEL_DESTROY); | |
| 557 msg->head.channel = chan->id; | |
| 558 msg->reason = reason; | |
| 559 if(info) mwOpaque_clone(&msg->data, info); | |
| 560 | |
| 561 /* remove the channel from the channel set */ | |
| 562 g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); | |
| 563 | |
| 564 /* send the message */ | |
| 565 ret = mwSession_send(session, (struct mwMessage *) msg); | |
| 566 mwMessage_free(MW_MESSAGE(msg)); | |
| 567 | |
| 568 return ret; | |
| 569 } | |
| 570 | |
| 571 | |
| 572 static void queue_outgoing(struct mwChannel *chan, | |
| 573 struct mwMsgChannelSend *msg) { | |
| 574 | |
| 575 g_info("queue_outgoing, channel 0x%08x", chan->id); | |
| 576 chan->outgoing_queue = g_slist_append(chan->outgoing_queue, msg); | |
| 577 } | |
| 578 | |
| 579 | |
| 580 static int channel_send(struct mwChannel *chan, | |
| 581 struct mwMsgChannelSend *msg) { | |
| 582 | |
| 583 int ret = 0; | |
| 584 | |
| 585 /* if the channel is open, send and free the message. Otherwise, | |
| 586 queue the message to be sent once the channel is finally | |
| 587 opened */ | |
| 588 | |
| 589 if(chan->state == mwChannel_OPEN) { | |
| 590 ret = mwSession_send(chan->session, (struct mwMessage *) msg); | |
| 591 mwMessage_free(MW_MESSAGE(msg)); | |
| 592 | |
| 593 } else { | |
| 594 queue_outgoing(chan, msg); | |
| 595 } | |
| 596 | |
| 597 return ret; | |
| 598 } | |
| 599 | |
| 600 | |
| 601 int mwChannel_sendEncrypted(struct mwChannel *chan, | |
| 602 guint32 type, struct mwOpaque *data, | |
| 603 gboolean encrypt) { | |
| 604 | |
| 605 struct mwMsgChannelSend *msg; | |
| 606 | |
| 607 g_return_val_if_fail(chan != NULL, -1); | |
| 608 | |
| 609 msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND); | |
| 610 msg->head.channel = chan->id; | |
| 611 msg->type = type; | |
| 612 | |
| 613 mwOpaque_clone(&msg->data, data); | |
| 614 | |
| 615 if(encrypt && chan->cipher) { | |
| 616 msg->head.options = mwMessageOption_ENCRYPT; | |
| 617 mwCipherInstance_encrypt(chan->cipher, &msg->data); | |
| 618 } | |
| 619 | |
| 620 return channel_send(chan, msg); | |
| 621 } | |
| 622 | |
| 623 | |
| 624 int mwChannel_send(struct mwChannel *chan, guint32 type, | |
| 625 struct mwOpaque *data) { | |
| 626 | |
| 627 return mwChannel_sendEncrypted(chan, type, data, TRUE); | |
| 628 } | |
| 629 | |
| 630 | |
| 631 static void queue_incoming(struct mwChannel *chan, | |
| 632 struct mwMsgChannelSend *msg) { | |
| 633 | |
| 634 /* we clone the message, because session_process will clear it once | |
| 635 we return */ | |
| 636 | |
| 637 struct mwMsgChannelSend *m = g_new0(struct mwMsgChannelSend, 1); | |
| 638 m->head.type = msg->head.type; | |
| 639 m->head.options = msg->head.options; | |
| 640 m->head.channel = msg->head.channel; | |
| 641 mwOpaque_clone(&m->head.attribs, &msg->head.attribs); | |
| 642 | |
| 643 m->type = msg->type; | |
| 644 mwOpaque_clone(&m->data, &msg->data); | |
| 645 | |
| 646 g_info("queue_incoming, channel 0x%08x", chan->id); | |
| 647 chan->incoming_queue = g_slist_append(chan->incoming_queue, m); | |
| 648 } | |
| 649 | |
| 650 | |
| 651 static void channel_recv(struct mwChannel *chan, | |
| 652 struct mwMsgChannelSend *msg) { | |
| 653 | |
| 654 struct mwService *srvc; | |
| 655 srvc = mwChannel_getService(chan); | |
| 656 | |
| 657 incr_stat(chan, mwChannelStat_MSG_RECV, 1); | |
| 658 | |
| 659 if(msg->head.options & mwMessageOption_ENCRYPT) { | |
| 660 struct mwOpaque data = { 0, 0 }; | |
| 661 mwOpaque_clone(&data, &msg->data); | |
| 662 | |
| 663 mwCipherInstance_decrypt(chan->cipher, &data); | |
| 664 mwService_recv(srvc, chan, msg->type, &data); | |
| 665 mwOpaque_clear(&data); | |
| 666 | |
| 667 } else { | |
| 668 mwService_recv(srvc, chan, msg->type, &msg->data); | |
| 669 } | |
| 670 } | |
| 671 | |
| 672 | |
| 673 static void flush_channel(struct mwChannel *chan) { | |
| 674 GSList *l; | |
| 675 | |
| 676 for(l = chan->incoming_queue; l; l = l->next) { | |
| 677 struct mwMsgChannelSend *msg = (struct mwMsgChannelSend *) l->data; | |
| 678 l->data = NULL; | |
| 679 | |
| 680 channel_recv(chan, msg); | |
| 681 mwMessage_free(MW_MESSAGE(msg)); | |
| 682 } | |
| 683 g_slist_free(chan->incoming_queue); | |
| 684 chan->incoming_queue = NULL; | |
| 685 | |
| 686 for(l = chan->outgoing_queue; l; l = l->next) { | |
| 687 struct mwMessage *msg = (struct mwMessage *) l->data; | |
| 688 l->data = NULL; | |
| 689 | |
| 690 mwSession_send(chan->session, msg); | |
| 691 mwMessage_free(msg); | |
| 692 } | |
| 693 g_slist_free(chan->outgoing_queue); | |
| 694 chan->outgoing_queue = NULL; | |
| 695 } | |
| 696 | |
| 697 | |
| 698 void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg) { | |
| 699 if(chan->state == mwChannel_OPEN) { | |
| 700 channel_recv(chan, msg); | |
| 701 | |
| 702 } else { | |
| 703 queue_incoming(chan, msg); | |
| 704 } | |
| 705 } | |
| 706 | |
| 707 | |
| 708 struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan) { | |
| 709 g_return_val_if_fail(cs != NULL, NULL); | |
| 710 g_return_val_if_fail(cs->map != NULL, NULL); | |
| 711 return g_hash_table_lookup(cs->map, GUINT_TO_POINTER(chan)); | |
| 712 } | |
| 713 | |
| 714 | |
| 715 void mwChannelSet_free(struct mwChannelSet *cs) { | |
| 716 if(! cs) return; | |
| 717 if(cs->map) g_hash_table_destroy(cs->map); | |
| 718 g_free(cs); | |
| 719 } | |
| 720 | |
| 721 | |
| 722 struct mwChannelSet *mwChannelSet_new(struct mwSession *s) { | |
| 723 struct mwChannelSet *cs = g_new0(struct mwChannelSet, 1); | |
| 724 cs->session = s; | |
| 725 | |
| 726 /* for some reason, g_int_hash/g_int_equal cause a SIGSEGV */ | |
| 727 cs->map = g_hash_table_new_full(g_direct_hash, g_direct_equal, | |
| 728 NULL, (GDestroyNotify) channel_free); | |
| 729 return cs; | |
| 730 } | |
| 731 | |
| 732 | |
| 733 void mwChannel_recvCreate(struct mwChannel *chan, | |
| 734 struct mwMsgChannelCreate *msg) { | |
| 735 | |
| 736 struct mwSession *session; | |
| 737 GList *list; | |
| 738 struct mwService *srvc; | |
| 739 | |
| 740 g_return_if_fail(chan != NULL); | |
| 741 g_return_if_fail(msg != NULL); | |
| 742 g_return_if_fail(chan->id == msg->channel); | |
| 743 | |
| 744 session = chan->session; | |
| 745 g_return_if_fail(session != NULL); | |
| 746 | |
| 747 if(mwChannel_isOutgoing(chan)) { | |
| 748 g_warning("channel 0x%08x not an incoming channel", chan->id); | |
| 749 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); | |
| 750 return; | |
| 751 } | |
| 752 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
753 chan->offered_policy = msg->encrypt.mode; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
754 g_message("channel offered with encrypt policy 0x%04x", chan->policy); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
755 |
| 10969 | 756 for(list = msg->encrypt.items; list; list = list->next) { |
| 757 struct mwEncryptItem *ei = list->data; | |
| 758 struct mwCipher *cipher; | |
| 759 struct mwCipherInstance *ci; | |
| 760 | |
| 761 g_message("channel offered cipher id 0x%04x", ei->id); | |
| 762 cipher = mwSession_getCipher(session, ei->id); | |
| 763 if(! cipher) { | |
| 764 g_message("no such cipher found in session"); | |
| 765 continue; | |
| 766 } | |
| 767 | |
| 768 ci = mwCipher_newInstance(cipher, chan); | |
| 769 mwCipherInstance_offered(ci, ei); | |
| 770 mwChannel_addSupportedCipherInstance(chan, ci); | |
| 771 } | |
| 772 | |
| 773 mwLoginInfo_clone(&chan->user, &msg->creator); | |
| 774 chan->service = msg->service; | |
| 775 chan->proto_type = msg->proto_type; | |
| 776 chan->proto_ver = msg->proto_ver; | |
| 777 | |
| 778 srvc = mwSession_getService(session, msg->service); | |
| 779 if(srvc) { | |
| 780 mwService_recvCreate(srvc, chan, msg); | |
| 781 | |
| 782 } else { | |
| 783 mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); | |
| 784 } | |
| 785 } | |
| 786 | |
| 787 | |
| 788 void mwChannel_recvAccept(struct mwChannel *chan, | |
| 789 struct mwMsgChannelAccept *msg) { | |
| 790 | |
| 791 struct mwService *srvc; | |
| 792 | |
| 793 g_return_if_fail(chan != NULL); | |
| 794 g_return_if_fail(msg != NULL); | |
| 795 g_return_if_fail(chan->id == msg->head.channel); | |
| 796 | |
| 797 if(mwChannel_isIncoming(chan)) { | |
| 798 g_warning("channel 0x%08x not an outgoing channel", chan->id); | |
| 799 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); | |
| 800 return; | |
| 801 } | |
| 802 | |
| 803 if(chan->state != mwChannel_WAIT) { | |
| 804 g_warning("channel 0x%08x state not WAIT: %s", | |
| 805 chan->id, state_str(chan->state)); | |
| 806 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); | |
| 807 return; | |
| 808 } | |
| 809 | |
| 810 mwLoginInfo_clone(&chan->user, &msg->acceptor); | |
| 811 | |
| 812 srvc = mwSession_getService(chan->session, chan->service); | |
| 813 if(! srvc) { | |
| 814 g_warning("no service: 0x%08x", chan->service); | |
| 815 mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); | |
| 816 return; | |
| 817 } | |
| 818 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
819 chan->policy = msg->encrypt.mode; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
820 g_message("channel accepted with encrypt policy 0x%04x", chan->policy); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
821 |
| 10969 | 822 if(! msg->encrypt.mode || ! msg->encrypt.item) { |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
823 /* no mode or no item means no encryption */ |
| 10969 | 824 mwChannel_selectCipherInstance(chan, NULL); |
| 825 | |
| 826 } else { | |
| 827 guint16 cid = msg->encrypt.item->id; | |
| 828 struct mwCipherInstance *ci = get_supported(chan, cid); | |
| 829 | |
| 830 if(! ci) { | |
| 831 g_warning("not an offered cipher: 0x%04x", cid); | |
| 832 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); | |
| 833 return; | |
| 834 } | |
| 835 | |
| 836 mwCipherInstance_accepted(ci, msg->encrypt.item); | |
| 837 mwChannel_selectCipherInstance(chan, ci); | |
| 838 } | |
| 839 | |
| 840 /* mark it as open for the service */ | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
841 state(chan, mwChannel_OPEN, 0); |
| 10969 | 842 |
| 843 /* let the service know */ | |
| 844 mwService_recvAccept(srvc, chan, msg); | |
| 845 | |
| 846 /* flush it if the service didn't just immediately close it */ | |
| 847 if(mwChannel_isState(chan, mwChannel_OPEN)) { | |
| 848 channel_open(chan); | |
| 849 } | |
| 850 } | |
| 851 | |
| 852 | |
| 853 void mwChannel_recvDestroy(struct mwChannel *chan, | |
| 854 struct mwMsgChannelDestroy *msg) { | |
| 855 | |
| 856 struct mwChannelSet *cs; | |
| 857 struct mwService *srvc; | |
| 858 | |
| 859 g_return_if_fail(chan != NULL); | |
| 860 g_return_if_fail(msg != NULL); | |
| 861 g_return_if_fail(chan->id == msg->head.channel); | |
| 862 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
863 state(chan, msg->reason? mwChannel_ERROR: mwChannel_DESTROY, msg->reason); |
| 10969 | 864 |
| 865 srvc = mwChannel_getService(chan); | |
| 866 if(srvc) mwService_recvDestroy(srvc, chan, msg); | |
| 867 | |
| 868 cs = mwSession_getChannels(chan->session); | |
| 869 g_return_if_fail(cs != NULL); | |
| 870 g_return_if_fail(cs->map != NULL); | |
| 871 | |
| 872 g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); | |
| 873 } | |
| 874 | |
| 875 | |
| 876 void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan) { | |
| 877 struct mwSession *session; | |
| 878 GList *list; | |
| 879 | |
| 880 g_return_if_fail(chan != NULL); | |
| 881 | |
| 882 session = chan->session; | |
| 883 g_return_if_fail(session != NULL); | |
| 884 | |
| 885 for(list = mwSession_getCiphers(session); list; list = list->next) { | |
| 886 struct mwCipherInstance *ci = mwCipher_newInstance(list->data, chan); | |
| 887 if(! ci) continue; | |
| 888 put_supported(chan, ci); | |
| 889 } | |
| 890 } | |
| 891 | |
| 892 | |
| 893 void mwChannel_addSupportedCipherInstance(struct mwChannel *chan, | |
| 894 struct mwCipherInstance *ci) { | |
| 895 g_return_if_fail(chan != NULL); | |
| 896 g_message("channel 0x%08x added cipher %s", chan->id, | |
| 897 NSTR(mwCipher_getName(mwCipherInstance_getCipher(ci)))); | |
| 898 put_supported(chan, ci); | |
| 899 } | |
| 900 | |
| 901 | |
| 902 static void collect(gpointer a, gpointer b, gpointer c) { | |
| 903 GList **list = c; | |
| 904 *list = g_list_append(*list, b); | |
| 905 } | |
| 906 | |
| 907 | |
| 908 GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan) { | |
| 909 GList *list = NULL; | |
| 910 | |
| 911 g_return_val_if_fail(chan != NULL, NULL); | |
| 912 g_hash_table_foreach(chan->supported, collect, &list); | |
| 913 | |
| 914 return list; | |
| 915 } | |
| 916 | |
| 917 | |
| 918 void mwChannel_selectCipherInstance(struct mwChannel *chan, | |
| 919 struct mwCipherInstance *ci) { | |
| 920 struct mwCipher *c; | |
| 921 | |
| 922 g_return_if_fail(chan != NULL); | |
| 923 g_return_if_fail(chan->supported != NULL); | |
| 924 | |
| 925 chan->cipher = ci; | |
| 926 if(ci) { | |
| 927 guint cid; | |
| 928 | |
| 929 c = mwCipherInstance_getCipher(ci); | |
| 930 cid = mwCipher_getType(c); | |
| 931 | |
| 932 g_hash_table_steal(chan->supported, GUINT_TO_POINTER(cid)); | |
| 933 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
934 switch(mwCipher_getType(c)) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
935 case mwCipher_RC2_40: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
936 chan->policy = mwEncrypt_RC2_40; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
937 break; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
938 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
939 case mwCipher_RC2_128: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
940 chan->policy = mwEncrypt_RC2_128; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
941 break; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
942 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
943 default: |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
944 /* unsure if this is bad */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
945 chan->policy = mwEncrypt_WHATEVER; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
946 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
947 |
| 10969 | 948 g_message("channel 0x%08x selected cipher %s", |
| 949 chan->id, NSTR(mwCipher_getName(c))); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
950 |
| 10969 | 951 } else { |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
952 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
953 chan->policy = mwEncrypt_NONE; |
| 10969 | 954 g_message("channel 0x%08x selected no cipher", chan->id); |
| 955 } | |
| 956 | |
| 957 g_hash_table_destroy(chan->supported); | |
| 958 chan->supported = NULL; | |
| 959 } | |
| 960 | |
| 961 |
