Mercurial > pidgin
annotate src/protocols/sametime/meanwhile/srvc_aware.c @ 12192:fb89d3a31c19
[gaim-migrate @ 14494]
Deconflict key bindings and fix a capitalization normalization I missed. Keybindings suck. I agree that GTK+ should do this automagically.
committer: Tailor Script <tailor@pidgin.im>
| author | Richard Laager <rlaager@wiktel.com> |
|---|---|
| date | Tue, 22 Nov 2005 22:47:59 +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_debug.h" | |
| 28 #include "mw_error.h" | |
| 29 #include "mw_message.h" | |
| 30 #include "mw_service.h" | |
| 31 #include "mw_session.h" | |
| 32 #include "mw_srvc_aware.h" | |
| 33 #include "mw_util.h" | |
| 34 | |
| 35 | |
| 36 struct mwServiceAware { | |
| 37 struct mwService service; | |
| 38 | |
| 39 struct mwAwareHandler *handler; | |
| 40 | |
| 41 /** map of ENTRY_KEY(aware_entry):aware_entry */ | |
| 42 GHashTable *entries; | |
| 43 | |
| 44 /** set of guint32:attrib_watch_entry attribute keys */ | |
| 45 GHashTable *attribs; | |
| 46 | |
| 47 /** collection of lists of awareness for this service. Each item is | |
| 48 a mwAwareList */ | |
| 49 GList *lists; | |
| 50 | |
| 51 /** the buddy list channel */ | |
| 52 struct mwChannel *channel; | |
| 53 }; | |
| 54 | |
| 55 | |
| 56 struct mwAwareList { | |
| 57 | |
| 58 /** the owning service */ | |
| 59 struct mwServiceAware *service; | |
| 60 | |
| 61 /** map of ENTRY_KEY(aware_entry):aware_entry */ | |
| 62 GHashTable *entries; | |
| 63 | |
| 64 /** set of guint32:attrib_watch_entry attribute keys */ | |
| 65 GHashTable *attribs; | |
| 66 | |
| 67 struct mwAwareListHandler *handler; | |
| 68 struct mw_datum client_data; | |
| 69 }; | |
| 70 | |
| 71 | |
| 72 struct mwAwareAttribute { | |
| 73 guint32 key; | |
| 74 struct mwOpaque data; | |
| 75 }; | |
| 76 | |
| 77 | |
| 78 struct attrib_entry { | |
| 79 guint32 key; | |
| 80 GList *membership; | |
| 81 }; | |
| 82 | |
| 83 | |
| 84 /** an actual awareness entry, belonging to any number of aware lists */ | |
| 85 struct aware_entry { | |
| 86 struct mwAwareSnapshot aware; | |
| 87 | |
| 88 /** list of mwAwareList containing this entry */ | |
| 89 GList *membership; | |
| 90 | |
| 91 /** collection of attribute values for this entry. | |
| 92 map of ATTRIB_KEY(mwAwareAttribute):mwAwareAttribute */ | |
| 93 GHashTable *attribs; | |
| 94 }; | |
| 95 | |
| 96 | |
| 97 #define ENTRY_KEY(entry) &entry->aware.id | |
| 98 | |
| 99 | |
| 100 /** the channel send types used by this service */ | |
| 101 enum msg_types { | |
| 102 msg_AWARE_ADD = 0x0068, /**< remove an aware */ | |
| 103 msg_AWARE_REMOVE = 0x0069, /**< add an aware */ | |
| 104 | |
| 105 msg_OPT_DO_SET = 0x00c9, /**< set an attribute */ | |
| 106 msg_OPT_DO_UNSET = 0x00ca, /**< unset an attribute */ | |
| 107 msg_OPT_WATCH = 0x00cb, /**< set the attribute watch list */ | |
| 108 | |
| 109 msg_AWARE_SNAPSHOT = 0x01f4, /**< recv aware snapshot */ | |
| 110 msg_AWARE_UPDATE = 0x01f5, /**< recv aware update */ | |
| 111 msg_AWARE_GROUP = 0x01f6, /**< recv group aware */ | |
| 112 | |
| 113 msg_OPT_GOT_SET = 0x0259, /**< recv attribute set update */ | |
| 114 msg_OPT_GOT_UNSET = 0x025a, /**< recv attribute unset update */ | |
| 115 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
116 msg_OPT_GOT_UNKNOWN = 0x025b, /**< UNKNOWN */ |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
117 |
| 10969 | 118 msg_OPT_DID_SET = 0x025d, /**< attribute set response */ |
| 119 msg_OPT_DID_UNSET = 0x025e, /**< attribute unset response */ | |
| 120 msg_OPT_DID_ERROR = 0x025f, /**< attribute set/unset error */ | |
| 121 }; | |
| 122 | |
| 123 | |
| 124 static void aware_entry_free(struct aware_entry *ae) { | |
| 125 mwAwareSnapshot_clear(&ae->aware); | |
| 126 g_list_free(ae->membership); | |
| 127 g_hash_table_destroy(ae->attribs); | |
| 128 g_free(ae); | |
| 129 } | |
| 130 | |
| 131 | |
| 132 static void attrib_entry_free(struct attrib_entry *ae) { | |
| 133 g_list_free(ae->membership); | |
| 134 g_free(ae); | |
| 135 } | |
| 136 | |
| 137 | |
| 138 static void attrib_free(struct mwAwareAttribute *attrib) { | |
| 139 mwOpaque_clear(&attrib->data); | |
| 140 g_free(attrib); | |
| 141 } | |
| 142 | |
| 143 | |
| 144 static struct aware_entry *aware_find(struct mwServiceAware *srvc, | |
| 145 struct mwAwareIdBlock *srch) { | |
| 11291 | 146 g_return_val_if_fail(srvc != NULL, NULL); |
| 147 g_return_val_if_fail(srvc->entries != NULL, NULL); | |
| 10969 | 148 g_return_val_if_fail(srch != NULL, NULL); |
| 149 | |
| 150 return g_hash_table_lookup(srvc->entries, srch); | |
| 151 } | |
| 152 | |
| 153 | |
| 154 static struct aware_entry *list_aware_find(struct mwAwareList *list, | |
| 155 struct mwAwareIdBlock *srch) { | |
| 156 g_return_val_if_fail(list != NULL, NULL); | |
| 157 g_return_val_if_fail(list->entries != NULL, NULL); | |
| 158 g_return_val_if_fail(srch != NULL, NULL); | |
| 159 | |
| 160 return g_hash_table_lookup(list->entries, srch); | |
| 161 } | |
| 162 | |
| 163 | |
| 164 static void compose_list(struct mwPutBuffer *b, GList *id_list) { | |
| 165 guint32_put(b, g_list_length(id_list)); | |
| 166 for(; id_list; id_list = id_list->next) | |
| 167 mwAwareIdBlock_put(b, id_list->data); | |
| 168 } | |
| 169 | |
| 170 | |
| 171 static int send_add(struct mwChannel *chan, GList *id_list) { | |
| 172 struct mwPutBuffer *b = mwPutBuffer_new(); | |
| 173 struct mwOpaque o; | |
| 174 int ret; | |
| 175 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
176 g_return_val_if_fail(chan != NULL, 0); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
177 |
| 10969 | 178 compose_list(b, id_list); |
| 179 | |
| 180 mwPutBuffer_finalize(&o, b); | |
| 181 | |
| 182 ret = mwChannel_send(chan, msg_AWARE_ADD, &o); | |
| 183 mwOpaque_clear(&o); | |
| 184 | |
| 185 return ret; | |
| 186 } | |
| 187 | |
| 188 | |
| 189 static int send_rem(struct mwChannel *chan, GList *id_list) { | |
| 190 struct mwPutBuffer *b = mwPutBuffer_new(); | |
| 191 struct mwOpaque o; | |
| 192 int ret; | |
| 193 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
194 g_return_val_if_fail(chan != NULL, 0); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
195 |
| 10969 | 196 compose_list(b, id_list); |
| 197 mwPutBuffer_finalize(&o, b); | |
| 198 | |
| 199 ret = mwChannel_send(chan, msg_AWARE_REMOVE, &o); | |
| 200 mwOpaque_clear(&o); | |
| 201 | |
| 202 return ret; | |
| 203 } | |
| 204 | |
| 205 | |
| 206 static gboolean collect_dead(gpointer key, gpointer val, gpointer data) { | |
| 207 struct aware_entry *aware = val; | |
| 208 GList **dead = data; | |
| 209 | |
| 210 if(aware->membership == NULL) { | |
| 211 g_info(" removing %s, %s", | |
| 212 NSTR(aware->aware.id.user), NSTR(aware->aware.id.community)); | |
| 213 *dead = g_list_append(*dead, aware); | |
| 214 return TRUE; | |
| 215 | |
| 216 } else { | |
| 217 return FALSE; | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 | |
| 222 static int remove_unused(struct mwServiceAware *srvc) { | |
| 223 /* - create a GList of all the unused aware entries | |
| 224 - remove each unused aware from the service | |
| 225 - if the service is alive, send a removal message for the collected | |
| 226 unused. | |
| 227 */ | |
| 228 | |
| 229 int ret = 0; | |
| 230 GList *dead = NULL, *l; | |
| 231 | |
| 232 if(srvc->entries) { | |
| 233 g_info("bring out your dead *clang*"); | |
| 234 g_hash_table_foreach_steal(srvc->entries, collect_dead, &dead); | |
| 235 } | |
| 236 | |
| 237 if(dead) { | |
| 238 if(MW_SERVICE_IS_LIVE(srvc)) | |
| 239 ret = send_rem(srvc->channel, dead) || ret; | |
| 240 | |
| 241 for(l = dead; l; l = l->next) | |
| 242 aware_entry_free(l->data); | |
| 243 | |
| 244 g_list_free(dead); | |
| 245 } | |
| 246 | |
| 247 return ret; | |
| 248 } | |
| 249 | |
| 250 | |
| 251 static int send_attrib_list(struct mwServiceAware *srvc) { | |
| 252 struct mwPutBuffer *b; | |
| 253 struct mwOpaque o; | |
| 254 | |
| 255 int tmp; | |
| 256 GList *l; | |
| 257 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
258 g_return_val_if_fail(srvc != NULL, -1); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
259 g_return_val_if_fail(srvc->channel != NULL, 0); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
260 |
| 10969 | 261 l = map_collect_keys(srvc->attribs); |
| 262 tmp = g_list_length(l); | |
| 263 | |
| 264 b = mwPutBuffer_new(); | |
| 265 guint32_put(b, 0x00); | |
| 266 guint32_put(b, tmp); | |
| 267 | |
| 268 for(; l; l = g_list_delete_link(l, l)) { | |
| 269 guint32_put(b, GPOINTER_TO_UINT(l->data)); | |
| 270 } | |
| 271 | |
| 272 mwPutBuffer_finalize(&o, b); | |
| 273 tmp = mwChannel_send(srvc->channel, msg_OPT_WATCH, &o); | |
| 274 mwOpaque_clear(&o); | |
| 275 | |
| 276 return tmp; | |
| 277 } | |
| 278 | |
| 279 | |
| 280 static gboolean collect_attrib_dead(gpointer key, gpointer val, | |
| 281 gpointer data) { | |
| 282 | |
| 283 struct attrib_entry *attrib = val; | |
| 284 GList **dead = data; | |
| 285 | |
| 286 if(attrib->membership == NULL) { | |
| 287 g_info(" removing 0x%08x", GPOINTER_TO_UINT(key)); | |
| 288 *dead = g_list_append(*dead, attrib); | |
| 289 return TRUE; | |
| 290 | |
| 291 } else { | |
| 292 return FALSE; | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 | |
| 297 static int remove_unused_attrib(struct mwServiceAware *srvc) { | |
| 298 GList *dead = NULL; | |
| 299 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
300 if(srvc->attribs) { |
| 10969 | 301 g_info("collecting dead attributes"); |
| 302 g_hash_table_foreach_steal(srvc->attribs, collect_attrib_dead, &dead); | |
| 303 } | |
| 304 | |
| 305 /* since we stole them, we'll have to clean 'em up manually */ | |
| 306 for(; dead; dead = g_list_delete_link(dead, dead)) { | |
| 307 attrib_entry_free(dead->data); | |
| 308 } | |
| 309 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
310 return MW_SERVICE_IS_LIVE(srvc)? send_attrib_list(srvc): 0; |
| 10969 | 311 } |
| 312 | |
| 313 | |
| 314 static void recv_accept(struct mwServiceAware *srvc, | |
| 315 struct mwChannel *chan, | |
| 316 struct mwMsgChannelAccept *msg) { | |
| 317 | |
| 318 g_return_if_fail(srvc->channel != NULL); | |
| 319 g_return_if_fail(srvc->channel == chan); | |
| 320 | |
| 321 if(MW_SERVICE_IS_STARTING(MW_SERVICE(srvc))) { | |
| 322 GList *list = NULL; | |
| 323 | |
| 324 list = map_collect_values(srvc->entries); | |
| 325 send_add(chan, list); | |
| 326 g_list_free(list); | |
| 327 | |
| 328 send_attrib_list(srvc); | |
| 329 | |
| 330 mwService_started(MW_SERVICE(srvc)); | |
| 331 | |
| 332 } else { | |
| 333 mwChannel_destroy(chan, ERR_FAILURE, NULL); | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 | |
| 338 static void recv_destroy(struct mwServiceAware *srvc, | |
| 339 struct mwChannel *chan, | |
| 340 struct mwMsgChannelDestroy *msg) { | |
| 341 | |
| 342 srvc->channel = NULL; | |
| 343 mwService_stop(MW_SERVICE(srvc)); | |
| 344 | |
| 345 /** @todo session sense service and mwService_start */ | |
| 346 } | |
| 347 | |
| 348 | |
| 349 /** called from SNAPSHOT_recv, UPDATE_recv, and | |
| 350 mwServiceAware_setStatus */ | |
| 351 static void status_recv(struct mwServiceAware *srvc, | |
| 352 struct mwAwareSnapshot *idb) { | |
| 353 | |
| 354 struct aware_entry *aware; | |
| 355 GList *l; | |
| 356 | |
| 357 aware = aware_find(srvc, &idb->id); | |
| 358 | |
| 359 if(! aware) { | |
| 360 /* we don't deal with receiving status for something we're not | |
| 361 monitoring, but it will happen sometimes, eg from manually set | |
| 362 status */ | |
| 363 return; | |
| 364 } | |
| 365 | |
| 366 /* clear the existing status, then clone in the new status */ | |
| 367 mwAwareSnapshot_clear(&aware->aware); | |
| 368 mwAwareSnapshot_clone(&aware->aware, idb); | |
| 369 | |
| 370 /* trigger each of the entry's lists */ | |
| 371 for(l = aware->membership; l; l = l->next) { | |
| 372 struct mwAwareList *alist = l->data; | |
| 373 struct mwAwareListHandler *handler = alist->handler; | |
| 374 | |
| 375 if(handler && handler->on_aware) | |
| 376 handler->on_aware(alist, idb); | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 | |
| 381 static void attrib_recv(struct mwServiceAware *srvc, | |
| 382 struct mwAwareIdBlock *idb, | |
| 383 struct mwAwareAttribute *attrib) { | |
| 384 | |
| 385 struct aware_entry *aware; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
386 struct mwAwareAttribute *old_attrib = NULL; |
| 10969 | 387 GList *l; |
| 388 guint32 key; | |
| 389 gpointer k; | |
| 390 | |
| 391 aware = aware_find(srvc, idb); | |
| 392 g_return_if_fail(aware != NULL); | |
| 393 | |
| 394 key = attrib->key; | |
| 395 k = GUINT_TO_POINTER(key); | |
| 396 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
397 if(aware->attribs) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
398 old_attrib = g_hash_table_lookup(aware->attribs, k); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
399 |
| 10969 | 400 if(! old_attrib) { |
| 401 old_attrib = g_new0(struct mwAwareAttribute, 1); | |
| 402 old_attrib->key = key; | |
| 403 g_hash_table_insert(aware->attribs, k, old_attrib); | |
| 404 } | |
| 405 | |
| 406 mwOpaque_clear(&old_attrib->data); | |
| 407 mwOpaque_clone(&old_attrib->data, &attrib->data); | |
| 408 | |
| 409 for(l = aware->membership; l; l = l->next) { | |
| 410 struct mwAwareList *list = l->data; | |
| 411 struct mwAwareListHandler *h = list->handler; | |
| 412 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
413 if(h && h->on_attrib && |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
414 list->attribs && g_hash_table_lookup(list->attribs, k)) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
415 |
| 10969 | 416 h->on_attrib(list, idb, old_attrib); |
| 417 } | |
| 418 } | |
| 419 | |
| 420 | |
| 421 gboolean list_add(struct mwAwareList *list, struct mwAwareIdBlock *id) { | |
| 422 | |
| 423 struct mwServiceAware *srvc = list->service; | |
| 424 struct aware_entry *aware; | |
| 425 | |
| 426 g_return_val_if_fail(id->user != NULL, FALSE); | |
| 427 g_return_val_if_fail(strlen(id->user) > 0, FALSE); | |
| 428 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
429 if(! list->entries) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
430 list->entries = g_hash_table_new((GHashFunc) mwAwareIdBlock_hash, |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
431 (GEqualFunc) mwAwareIdBlock_equal); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
432 |
| 10969 | 433 aware = list_aware_find(list, id); |
| 434 if(aware) return FALSE; | |
| 435 | |
| 436 aware = aware_find(srvc, id); | |
| 437 if(! aware) { | |
| 438 aware = g_new0(struct aware_entry, 1); | |
| 439 aware->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, | |
| 440 (GDestroyNotify) attrib_free); | |
| 441 mwAwareIdBlock_clone(ENTRY_KEY(aware), id); | |
| 442 | |
| 443 g_hash_table_insert(srvc->entries, ENTRY_KEY(aware), aware); | |
| 444 } | |
| 445 | |
| 446 aware->membership = g_list_append(aware->membership, list); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
447 |
| 10969 | 448 g_hash_table_insert(list->entries, ENTRY_KEY(aware), aware); |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
449 |
| 10969 | 450 return TRUE; |
| 451 } | |
| 452 | |
| 453 | |
| 454 static void group_member_recv(struct mwServiceAware *srvc, | |
| 455 struct mwAwareSnapshot *idb) { | |
| 456 /* @todo | |
| 457 - look up group by id | |
| 458 - find each list group belongs to | |
| 459 - add user to lists | |
| 460 */ | |
| 461 | |
| 462 struct mwAwareIdBlock gsrch = { mwAware_GROUP, idb->group, NULL }; | |
| 463 struct aware_entry *grp; | |
| 464 GList *l, *m; | |
| 465 | |
| 466 grp = aware_find(srvc, &gsrch); | |
| 467 g_return_if_fail(grp != NULL); /* this could happen, with timing. */ | |
| 468 | |
| 469 l = g_list_prepend(NULL, &idb->id); | |
| 470 | |
| 471 for(m = grp->membership; m; m = m->next) { | |
| 472 | |
| 473 /* if we just list_add, we won't receive updates for attributes, | |
| 474 so annoyingly we have to turn around and send out an add aware | |
| 475 message for each incoming group member */ | |
| 476 | |
| 477 /* list_add(m->data, &idb->id); */ | |
| 478 mwAwareList_addAware(m->data, l); | |
| 479 } | |
| 480 | |
| 481 g_list_free(l); | |
| 482 } | |
| 483 | |
| 484 | |
| 485 static void recv_SNAPSHOT(struct mwServiceAware *srvc, | |
| 486 struct mwGetBuffer *b) { | |
| 487 | |
| 488 guint32 count; | |
| 489 | |
| 490 struct mwAwareSnapshot *snap; | |
| 491 snap = g_new0(struct mwAwareSnapshot, 1); | |
| 492 | |
| 493 guint32_get(b, &count); | |
| 494 | |
| 495 while(count--) { | |
| 496 mwAwareSnapshot_get(b, snap); | |
| 497 | |
| 498 if(mwGetBuffer_error(b)) { | |
| 499 mwAwareSnapshot_clear(snap); | |
| 500 break; | |
| 501 } | |
| 502 | |
| 503 if(snap->group) | |
| 504 group_member_recv(srvc, snap); | |
| 505 | |
| 506 status_recv(srvc, snap); | |
| 507 mwAwareSnapshot_clear(snap); | |
| 508 } | |
| 509 | |
| 510 g_free(snap); | |
| 511 } | |
| 512 | |
| 513 | |
| 514 static void recv_UPDATE(struct mwServiceAware *srvc, | |
| 515 struct mwGetBuffer *b) { | |
| 516 | |
| 517 struct mwAwareSnapshot *snap; | |
| 518 | |
| 519 snap = g_new0(struct mwAwareSnapshot, 1); | |
| 520 mwAwareSnapshot_get(b, snap); | |
| 521 | |
| 522 if(snap->group) | |
| 523 group_member_recv(srvc, snap); | |
| 524 | |
| 525 if(! mwGetBuffer_error(b)) | |
| 526 status_recv(srvc, snap); | |
| 527 | |
| 528 mwAwareSnapshot_clear(snap); | |
| 529 g_free(snap); | |
| 530 } | |
| 531 | |
| 532 | |
| 533 static void recv_GROUP(struct mwServiceAware *srvc, | |
| 534 struct mwGetBuffer *b) { | |
| 535 | |
| 536 struct mwAwareIdBlock idb = { 0, 0, 0 }; | |
| 537 | |
| 538 /* really nothing to be done with this. The group should have | |
| 539 already been added to the list and service, and is now simply | |
| 540 awaiting a snapshot/update with users listed as belonging in said | |
| 541 group. */ | |
| 542 | |
| 543 mwAwareIdBlock_get(b, &idb); | |
| 544 mwAwareIdBlock_clear(&idb); | |
| 545 } | |
| 546 | |
| 547 | |
| 548 static void recv_OPT_GOT_SET(struct mwServiceAware *srvc, | |
| 549 struct mwGetBuffer *b) { | |
| 550 | |
| 551 struct mwAwareAttribute attrib; | |
| 552 struct mwAwareIdBlock idb; | |
| 553 guint32 junk, check; | |
| 554 | |
| 555 guint32_get(b, &junk); | |
| 556 mwAwareIdBlock_get(b, &idb); | |
| 557 guint32_get(b, &junk); | |
| 558 guint32_get(b, &check); | |
| 559 guint32_get(b, &junk); | |
| 560 guint32_get(b, &attrib.key); | |
| 561 | |
| 562 if(check) { | |
| 563 mwOpaque_get(b, &attrib.data); | |
| 564 } else { | |
| 565 attrib.data.len = 0; | |
| 566 attrib.data.data = NULL; | |
| 567 } | |
| 568 | |
| 569 attrib_recv(srvc, &idb, &attrib); | |
| 570 | |
| 571 mwAwareIdBlock_clear(&idb); | |
| 572 mwOpaque_clear(&attrib.data); | |
| 573 } | |
| 574 | |
| 575 | |
| 576 static void recv_OPT_GOT_UNSET(struct mwServiceAware *srvc, | |
| 577 struct mwGetBuffer *b) { | |
| 578 | |
| 579 struct mwAwareAttribute attrib; | |
| 580 struct mwAwareIdBlock idb; | |
| 581 guint32 junk; | |
| 582 | |
| 583 attrib.key = 0; | |
| 584 attrib.data.len = 0; | |
| 585 attrib.data.data = NULL; | |
| 586 | |
| 587 guint32_get(b, &junk); | |
| 588 mwAwareIdBlock_get(b, &idb); | |
| 589 guint32_get(b, &attrib.key); | |
| 590 | |
| 591 attrib_recv(srvc, &idb, &attrib); | |
| 592 | |
| 593 mwAwareIdBlock_clear(&idb); | |
| 594 } | |
| 595 | |
| 596 | |
| 597 static void recv(struct mwService *srvc, struct mwChannel *chan, | |
| 598 guint16 type, struct mwOpaque *data) { | |
| 599 | |
| 600 struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc; | |
| 601 struct mwGetBuffer *b; | |
| 602 | |
| 603 g_return_if_fail(srvc_aware->channel == chan); | |
| 604 g_return_if_fail(srvc->session == mwChannel_getSession(chan)); | |
| 605 g_return_if_fail(data != NULL); | |
| 606 | |
| 607 b = mwGetBuffer_wrap(data); | |
| 608 | |
| 609 switch(type) { | |
| 610 case msg_AWARE_SNAPSHOT: | |
| 611 recv_SNAPSHOT(srvc_aware, b); | |
| 612 break; | |
| 613 | |
| 614 case msg_AWARE_UPDATE: | |
| 615 recv_UPDATE(srvc_aware, b); | |
| 616 break; | |
| 617 | |
| 618 case msg_AWARE_GROUP: | |
| 619 recv_GROUP(srvc_aware, b); | |
| 620 break; | |
| 621 | |
| 622 case msg_OPT_GOT_SET: | |
| 623 recv_OPT_GOT_SET(srvc_aware, b); | |
| 624 break; | |
| 625 | |
| 626 case msg_OPT_GOT_UNSET: | |
| 627 recv_OPT_GOT_UNSET(srvc_aware, b); | |
| 628 break; | |
| 629 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
630 case msg_OPT_GOT_UNKNOWN: |
| 10969 | 631 case msg_OPT_DID_SET: |
| 632 case msg_OPT_DID_UNSET: | |
| 633 case msg_OPT_DID_ERROR: | |
| 634 break; | |
| 635 | |
| 636 default: | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
637 mw_mailme_opaque(data, "unknown message in aware service: 0x%04x", type); |
| 10969 | 638 } |
| 639 | |
| 640 mwGetBuffer_free(b); | |
| 641 } | |
| 642 | |
| 643 | |
| 644 static void clear(struct mwService *srvc) { | |
| 645 struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc; | |
| 646 | |
| 647 g_return_if_fail(srvc != NULL); | |
| 648 | |
| 649 while(srvc_aware->lists) | |
| 650 mwAwareList_free( (struct mwAwareList *) srvc_aware->lists->data ); | |
| 651 | |
| 652 g_hash_table_destroy(srvc_aware->entries); | |
| 653 srvc_aware->entries = NULL; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
654 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
655 g_hash_table_destroy(srvc_aware->attribs); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
656 srvc_aware->attribs = NULL; |
| 10969 | 657 } |
| 658 | |
| 659 | |
| 660 static const char *name(struct mwService *srvc) { | |
| 661 return "Presence Awareness"; | |
| 662 } | |
| 663 | |
| 664 | |
| 665 static const char *desc(struct mwService *srvc) { | |
| 666 return "Buddy list service with support for server-side groups"; | |
| 667 } | |
| 668 | |
| 669 | |
| 670 static struct mwChannel *make_blist(struct mwServiceAware *srvc, | |
| 671 struct mwChannelSet *cs) { | |
| 672 | |
| 673 struct mwChannel *chan = mwChannel_newOutgoing(cs); | |
| 674 | |
| 675 mwChannel_setService(chan, MW_SERVICE(srvc)); | |
| 676 mwChannel_setProtoType(chan, 0x00000011); | |
| 677 mwChannel_setProtoVer(chan, 0x00030005); | |
| 678 | |
| 679 return mwChannel_create(chan)? NULL: chan; | |
| 680 } | |
| 681 | |
| 682 | |
| 683 static void start(struct mwService *srvc) { | |
| 684 struct mwServiceAware *srvc_aware; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
685 struct mwChannel *chan = NULL; |
| 10969 | 686 |
| 687 srvc_aware = (struct mwServiceAware *) srvc; | |
| 688 chan = make_blist(srvc_aware, mwSession_getChannels(srvc->session)); | |
| 689 | |
| 690 if(chan != NULL) { | |
| 691 srvc_aware->channel = chan; | |
| 692 } else { | |
| 693 mwService_stopped(srvc); | |
| 694 } | |
| 695 } | |
| 696 | |
| 697 | |
| 698 static void stop(struct mwService *srvc) { | |
| 699 struct mwServiceAware *srvc_aware; | |
| 700 | |
| 701 srvc_aware = (struct mwServiceAware *) srvc; | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
702 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
703 if(srvc_aware->channel) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
704 mwChannel_destroy(srvc_aware->channel, ERR_SUCCESS, NULL); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
705 srvc_aware->channel = NULL; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
706 } |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
707 |
| 10969 | 708 mwService_stopped(srvc); |
| 709 } | |
| 710 | |
| 711 | |
| 712 struct mwServiceAware * | |
| 713 mwServiceAware_new(struct mwSession *session, | |
| 714 struct mwAwareHandler *handler) { | |
| 715 | |
| 716 struct mwService *service; | |
| 717 struct mwServiceAware *srvc; | |
| 718 | |
| 719 g_return_val_if_fail(session != NULL, NULL); | |
| 720 g_return_val_if_fail(handler != NULL, NULL); | |
| 721 | |
| 722 srvc = g_new0(struct mwServiceAware, 1); | |
| 723 srvc->handler = handler; | |
| 724 srvc->entries = g_hash_table_new_full((GHashFunc) mwAwareIdBlock_hash, | |
| 725 (GEqualFunc) mwAwareIdBlock_equal, | |
| 726 NULL, | |
| 727 (GDestroyNotify) aware_entry_free); | |
| 728 | |
| 729 srvc->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, | |
| 730 (GDestroyNotify) attrib_entry_free); | |
| 731 | |
| 732 service = MW_SERVICE(srvc); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
733 mwService_init(service, session, mwService_AWARE); |
| 10969 | 734 |
| 735 service->recv_accept = (mwService_funcRecvAccept) recv_accept; | |
| 736 service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy; | |
| 737 service->recv = recv; | |
| 738 service->start = start; | |
| 739 service->stop = stop; | |
| 740 service->clear = clear; | |
| 741 service->get_name = name; | |
| 742 service->get_desc = desc; | |
| 743 | |
| 744 return srvc; | |
| 745 } | |
| 746 | |
| 747 | |
| 748 int mwServiceAware_setAttribute(struct mwServiceAware *srvc, | |
| 749 guint32 key, struct mwOpaque *data) { | |
| 750 struct mwPutBuffer *b; | |
| 751 struct mwOpaque o; | |
| 752 int ret; | |
| 753 | |
| 754 b = mwPutBuffer_new(); | |
| 755 | |
| 756 guint32_put(b, 0x00); | |
| 757 guint32_put(b, data->len); | |
| 758 guint32_put(b, 0x00); | |
| 759 guint32_put(b, key); | |
| 760 mwOpaque_put(b, data); | |
| 761 | |
| 762 mwPutBuffer_finalize(&o, b); | |
| 763 ret = mwChannel_send(srvc->channel, msg_OPT_DO_SET, &o); | |
| 764 mwOpaque_clear(&o); | |
| 765 | |
| 766 return ret; | |
| 767 } | |
| 768 | |
| 769 | |
| 770 int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc, | |
| 771 guint32 key, gboolean val) { | |
| 772 int ret; | |
| 773 struct mwPutBuffer *b; | |
| 774 struct mwOpaque o; | |
| 775 | |
| 776 b = mwPutBuffer_new(); | |
| 777 | |
| 778 gboolean_put(b, FALSE); | |
| 779 gboolean_put(b, val); | |
| 780 | |
| 781 mwPutBuffer_finalize(&o, b); | |
| 782 | |
| 783 ret = mwServiceAware_setAttribute(srvc, key, &o); | |
| 784 mwOpaque_clear(&o); | |
| 785 | |
| 786 return ret; | |
| 787 } | |
| 788 | |
| 789 | |
| 790 int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc, | |
| 791 guint32 key, guint32 val) { | |
| 792 int ret; | |
| 793 struct mwPutBuffer *b; | |
| 794 struct mwOpaque o; | |
| 795 | |
| 796 b = mwPutBuffer_new(); | |
| 797 guint32_put(b, val); | |
| 798 | |
| 799 mwPutBuffer_finalize(&o, b); | |
| 800 | |
| 801 ret = mwServiceAware_setAttribute(srvc, key, &o); | |
| 802 mwOpaque_clear(&o); | |
| 803 | |
| 804 return ret; | |
| 805 } | |
| 806 | |
| 807 | |
| 808 int mwServiceAware_setAttributeString(struct mwServiceAware *srvc, | |
| 809 guint32 key, const char *str) { | |
| 810 int ret; | |
| 811 struct mwPutBuffer *b; | |
| 812 struct mwOpaque o; | |
| 813 | |
| 814 b = mwPutBuffer_new(); | |
| 815 mwString_put(b, str); | |
| 816 | |
| 817 mwPutBuffer_finalize(&o, b); | |
| 818 | |
| 819 ret = mwServiceAware_setAttribute(srvc, key, &o); | |
| 820 mwOpaque_clear(&o); | |
| 821 | |
| 822 return ret; | |
| 823 } | |
| 824 | |
| 825 | |
| 826 int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc, | |
| 827 guint32 key) { | |
| 828 struct mwPutBuffer *b; | |
| 829 struct mwOpaque o; | |
| 830 int ret; | |
| 831 | |
| 832 b = mwPutBuffer_new(); | |
| 833 | |
| 834 guint32_put(b, 0x00); | |
| 835 guint32_put(b, key); | |
| 836 | |
| 837 mwPutBuffer_finalize(&o, b); | |
| 838 ret = mwChannel_send(srvc->channel, msg_OPT_DO_UNSET, &o); | |
| 839 mwOpaque_clear(&o); | |
| 840 | |
| 841 return ret; | |
| 842 } | |
| 843 | |
| 844 | |
| 845 guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib) { | |
| 846 g_return_val_if_fail(attrib != NULL, 0x00); | |
| 847 return attrib->key; | |
| 848 } | |
| 849 | |
| 850 | |
| 851 gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib) { | |
| 852 struct mwGetBuffer *b; | |
| 853 gboolean ret; | |
| 854 | |
| 855 if(! attrib) return FALSE; | |
| 856 | |
| 857 b = mwGetBuffer_wrap(&attrib->data); | |
| 858 if(attrib->data.len >= 4) { | |
| 859 guint32 r32 = 0x00; | |
| 860 guint32_get(b, &r32); | |
| 861 ret = !! r32; | |
| 862 | |
| 863 } else if(attrib->data.len >= 2) { | |
| 864 guint16 r16 = 0x00; | |
| 865 guint16_get(b, &r16); | |
| 866 ret = !! r16; | |
| 867 | |
| 868 } else if(attrib->data.len) { | |
| 869 gboolean_get(b, &ret); | |
| 870 } | |
| 871 | |
| 872 mwGetBuffer_free(b); | |
| 873 | |
| 874 return ret; | |
| 875 } | |
| 876 | |
| 877 | |
| 878 guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib) { | |
| 879 struct mwGetBuffer *b; | |
| 880 guint32 r32 = 0x00; | |
| 881 | |
| 882 if(! attrib) return 0x00; | |
| 883 | |
| 884 b = mwGetBuffer_wrap(&attrib->data); | |
| 885 if(attrib->data.len >= 4) { | |
| 886 guint32_get(b, &r32); | |
| 887 | |
| 888 } else if(attrib->data.len == 3) { | |
| 889 gboolean rb = FALSE; | |
| 890 guint16 r16 = 0x00; | |
| 891 gboolean_get(b, &rb); | |
| 892 guint16_get(b, &r16); | |
| 893 r32 = (guint32) r16; | |
| 894 | |
| 895 } else if(attrib->data.len == 2) { | |
| 896 guint16 r16 = 0x00; | |
| 897 guint16_get(b, &r16); | |
| 898 r32 = (guint32) r16; | |
| 899 | |
| 900 } else if(attrib->data.len) { | |
| 901 gboolean rb = FALSE; | |
| 902 gboolean_get(b, &rb); | |
| 903 r32 = (guint32) rb; | |
| 904 } | |
| 905 | |
| 906 mwGetBuffer_free(b); | |
| 907 | |
| 908 return r32; | |
| 909 } | |
| 910 | |
| 911 | |
| 912 char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib) { | |
| 913 struct mwGetBuffer *b; | |
| 914 char *ret = NULL; | |
| 915 | |
| 916 if(! attrib) return NULL; | |
| 917 | |
| 918 b = mwGetBuffer_wrap(&attrib->data); | |
| 919 mwString_get(b, &ret); | |
| 920 mwGetBuffer_free(b); | |
| 921 | |
| 922 return ret; | |
| 923 } | |
| 924 | |
| 925 | |
| 926 const struct mwOpaque * | |
| 927 mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib) { | |
| 928 g_return_val_if_fail(attrib != NULL, NULL); | |
| 929 return &attrib->data; | |
| 930 } | |
| 931 | |
| 932 | |
| 933 struct mwAwareList * | |
| 934 mwAwareList_new(struct mwServiceAware *srvc, | |
| 935 struct mwAwareListHandler *handler) { | |
| 936 | |
| 937 struct mwAwareList *al; | |
| 938 | |
| 939 g_return_val_if_fail(srvc != NULL, NULL); | |
| 940 g_return_val_if_fail(handler != NULL, NULL); | |
| 941 | |
| 942 al = g_new0(struct mwAwareList, 1); | |
| 943 al->service = srvc; | |
| 944 al->handler = handler; | |
| 945 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
946 srvc->lists = g_list_prepend(srvc->lists, al); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
947 |
| 10969 | 948 return al; |
| 949 } | |
| 950 | |
| 951 | |
| 952 void mwAwareList_free(struct mwAwareList *list) { | |
| 953 struct mwServiceAware *srvc; | |
| 954 struct mwAwareListHandler *handler; | |
| 955 | |
| 956 g_return_if_fail(list != NULL); | |
| 957 g_return_if_fail(list->service != NULL); | |
| 958 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
959 srvc = list->service; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
960 srvc->lists = g_list_remove_all(srvc->lists, list); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
961 |
| 10969 | 962 handler = list->handler; |
| 963 if(handler && handler->clear) { | |
| 964 handler->clear(list); | |
| 965 list->handler = NULL; | |
| 966 } | |
| 967 | |
| 968 mw_datum_clear(&list->client_data); | |
| 969 | |
| 970 mwAwareList_unwatchAllAttributes(list); | |
| 971 mwAwareList_removeAllAware(list); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
972 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
973 list->service = NULL; |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
974 |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
975 g_free(list); |
| 10969 | 976 } |
| 977 | |
| 978 | |
| 979 struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list) { | |
| 980 g_return_val_if_fail(list != NULL, NULL); | |
| 981 return list->handler; | |
| 982 } | |
| 983 | |
| 984 | |
| 985 static void watch_add(struct mwAwareList *list, guint32 key) { | |
| 986 struct mwServiceAware *srvc; | |
| 987 struct attrib_entry *watch; | |
| 988 gpointer k = GUINT_TO_POINTER(key); | |
| 989 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
990 if(! list->attribs) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
991 list->attribs = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
992 |
| 10969 | 993 if(g_hash_table_lookup(list->attribs, k)) |
| 994 return; | |
| 995 | |
| 996 srvc = list->service; | |
| 997 | |
| 998 watch = g_hash_table_lookup(srvc->attribs, k); | |
| 999 if(! watch) { | |
| 1000 watch = g_new0(struct attrib_entry, 1); | |
| 1001 watch->key = key; | |
| 1002 g_hash_table_insert(srvc->attribs, k, watch); | |
| 1003 } | |
| 1004 | |
| 1005 g_hash_table_insert(list->attribs, k, watch); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1006 |
| 10969 | 1007 watch->membership = g_list_prepend(watch->membership, list); |
| 1008 } | |
| 1009 | |
| 1010 | |
| 1011 static void watch_remove(struct mwAwareList *list, guint32 key) { | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1012 struct attrib_entry *watch = NULL; |
| 10969 | 1013 gpointer k = GUINT_TO_POINTER(key); |
| 1014 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1015 if(list->attribs) |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1016 watch = g_hash_table_lookup(list->attribs, k); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1017 |
| 10969 | 1018 g_return_if_fail(watch != NULL); |
| 1019 | |
| 1020 g_hash_table_remove(list->attribs, k); | |
| 1021 watch->membership = g_list_remove(watch->membership, list); | |
| 1022 } | |
| 1023 | |
| 1024 | |
| 1025 int mwAwareList_watchAttributeArray(struct mwAwareList *list, | |
| 1026 guint32 *keys) { | |
| 1027 guint32 k; | |
| 1028 | |
| 1029 g_return_val_if_fail(list != NULL, -1); | |
| 1030 g_return_val_if_fail(list->service != NULL, -1); | |
| 1031 | |
| 1032 if(! keys) return 0; | |
| 1033 | |
| 1034 for(k = *keys; k; keys++) | |
| 1035 watch_add(list, k); | |
| 1036 | |
| 1037 return send_attrib_list(list->service); | |
| 1038 } | |
| 1039 | |
| 1040 | |
| 1041 int mwAwareList_watchAttributes(struct mwAwareList *list, | |
| 1042 guint32 key, ...) { | |
| 1043 guint32 k; | |
| 1044 va_list args; | |
| 1045 | |
| 1046 g_return_val_if_fail(list != NULL, -1); | |
| 1047 g_return_val_if_fail(list->service != NULL, -1); | |
| 1048 | |
| 1049 va_start(args, key); | |
| 1050 for(k = key; k; k = va_arg(args, guint32)) | |
| 1051 watch_add(list, k); | |
| 1052 va_end(args); | |
| 1053 | |
| 1054 return send_attrib_list(list->service); | |
| 1055 } | |
| 1056 | |
| 1057 | |
| 1058 int mwAwareList_unwatchAttributeArray(struct mwAwareList *list, | |
| 1059 guint32 *keys) { | |
| 1060 guint32 k; | |
| 1061 | |
| 1062 g_return_val_if_fail(list != NULL, -1); | |
| 1063 g_return_val_if_fail(list->service != NULL, -1); | |
| 1064 | |
| 1065 if(! keys) return 0; | |
| 1066 | |
| 1067 for(k = *keys; k; keys++) | |
| 1068 watch_add(list, k); | |
| 1069 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1070 return remove_unused_attrib(list->service); |
| 10969 | 1071 } |
| 1072 | |
| 1073 | |
| 1074 int mwAwareList_unwatchAttributes(struct mwAwareList *list, | |
| 1075 guint32 key, ...) { | |
| 1076 guint32 k; | |
| 1077 va_list args; | |
| 1078 | |
| 1079 g_return_val_if_fail(list != NULL, -1); | |
| 1080 g_return_val_if_fail(list->service != NULL, -1); | |
| 1081 | |
| 1082 va_start(args, key); | |
| 1083 for(k = key; k; k = va_arg(args, guint32)) | |
| 1084 watch_remove(list, k); | |
| 1085 va_end(args); | |
| 1086 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1087 return remove_unused_attrib(list->service); |
| 10969 | 1088 } |
| 1089 | |
| 1090 | |
| 1091 static void dismember_attrib(gpointer k, struct attrib_entry *watch, | |
| 1092 struct mwAwareList *list) { | |
| 1093 | |
| 1094 watch->membership = g_list_remove(watch->membership, list); | |
| 1095 } | |
| 1096 | |
| 1097 | |
| 1098 int mwAwareList_unwatchAllAttributes(struct mwAwareList *list) { | |
| 1099 | |
| 1100 struct mwServiceAware *srvc; | |
| 1101 | |
| 1102 g_return_val_if_fail(list != NULL, -1); | |
| 1103 srvc = list->service; | |
| 1104 | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1105 if(list->attribs) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1106 g_hash_table_foreach(list->attribs, (GHFunc) dismember_attrib, list); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1107 g_hash_table_destroy(list->attribs); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1108 } |
| 10969 | 1109 |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1110 return remove_unused_attrib(srvc); |
| 10969 | 1111 } |
| 1112 | |
| 1113 | |
| 1114 static void collect_attrib_keys(gpointer key, struct attrib_entry *attrib, | |
| 1115 guint32 **ck) { | |
| 1116 guint32 *keys = (*ck)++; | |
| 1117 *keys = GPOINTER_TO_UINT(key); | |
| 1118 } | |
| 1119 | |
| 1120 | |
| 1121 guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list) { | |
| 1122 guint32 *keys, **ck; | |
| 1123 guint count; | |
| 1124 | |
| 1125 g_return_val_if_fail(list != NULL, NULL); | |
| 1126 g_return_val_if_fail(list->attribs != NULL, NULL); | |
| 1127 | |
| 1128 count = g_hash_table_size(list->attribs); | |
| 1129 keys = g_new0(guint32, count + 1); | |
| 1130 | |
| 1131 ck = &keys; | |
| 1132 g_hash_table_foreach(list->attribs, (GHFunc) collect_attrib_keys, ck); | |
| 1133 | |
| 1134 return keys; | |
| 1135 } | |
| 1136 | |
| 1137 | |
| 1138 int mwAwareList_addAware(struct mwAwareList *list, GList *id_list) { | |
| 1139 | |
| 1140 /* for each awareness id: | |
| 1141 - if it's already in the list, continue | |
| 1142 - if it's not in the service list: | |
| 1143 - create an awareness | |
| 1144 - add it to the service list | |
| 1145 - add this list to the membership | |
| 1146 - add to the list | |
| 1147 */ | |
| 1148 | |
| 1149 struct mwServiceAware *srvc; | |
| 1150 GList *additions = NULL; | |
| 1151 int ret = 0; | |
| 1152 | |
| 1153 g_return_val_if_fail(list != NULL, -1); | |
| 1154 | |
| 1155 srvc = list->service; | |
| 1156 g_return_val_if_fail(srvc != NULL, -1); | |
| 1157 | |
| 1158 for(; id_list; id_list = id_list->next) { | |
| 1159 if(list_add(list, id_list->data)) | |
| 1160 additions = g_list_prepend(additions, id_list->data); | |
| 1161 } | |
| 1162 | |
| 1163 /* if the service is alive-- or getting there-- we'll need to send | |
| 1164 these additions upstream */ | |
| 1165 if(MW_SERVICE_IS_LIVE(srvc) && additions) | |
| 1166 ret = send_add(srvc->channel, additions); | |
| 1167 | |
| 1168 g_list_free(additions); | |
| 1169 return ret; | |
| 1170 } | |
| 1171 | |
| 1172 | |
| 1173 int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list) { | |
| 1174 | |
| 1175 /* for each awareness id: | |
| 1176 - if it's not in the list, forget it | |
| 1177 - remove from the list | |
| 1178 - remove list from the membership | |
| 1179 | |
| 1180 - call remove round | |
| 1181 */ | |
| 1182 | |
| 1183 struct mwServiceAware *srvc; | |
| 1184 struct mwAwareIdBlock *id; | |
| 1185 struct aware_entry *aware; | |
| 1186 | |
| 1187 g_return_val_if_fail(list != NULL, -1); | |
| 1188 | |
| 1189 srvc = list->service; | |
| 1190 g_return_val_if_fail(srvc != NULL, -1); | |
| 1191 | |
| 1192 for(; id_list; id_list = id_list->next) { | |
| 1193 id = id_list->data; | |
| 1194 aware = list_aware_find(list, id); | |
| 1195 | |
| 1196 if(! aware) { | |
| 1197 g_warning("buddy %s, %s not in list", | |
| 1198 NSTR(id->user), | |
| 1199 NSTR(id->community)); | |
| 1200 continue; | |
| 1201 } | |
| 1202 | |
| 1203 aware->membership = g_list_remove(aware->membership, list); | |
| 1204 g_hash_table_remove(list->entries, id); | |
| 1205 } | |
| 1206 | |
| 1207 return remove_unused(srvc); | |
| 1208 } | |
| 1209 | |
| 1210 | |
| 1211 static void dismember_aware(gpointer k, struct aware_entry *aware, | |
| 1212 struct mwAwareList *list) { | |
| 1213 | |
| 1214 aware->membership = g_list_remove(aware->membership, list); | |
| 1215 } | |
| 1216 | |
| 1217 | |
| 1218 int mwAwareList_removeAllAware(struct mwAwareList *list) { | |
| 1219 struct mwServiceAware *srvc; | |
| 1220 | |
| 1221 g_return_val_if_fail(list != NULL, -1); | |
| 1222 srvc = list->service; | |
| 1223 | |
| 1224 g_return_val_if_fail(srvc != NULL, -1); | |
| 1225 | |
| 1226 /* for each entry, remove the aware list from the service entry's | |
| 1227 membership collection */ | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1228 if(list->entries) { |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1229 g_hash_table_foreach(list->entries, (GHFunc) dismember_aware, list); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1230 g_hash_table_destroy(list->entries); |
|
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1231 } |
| 10969 | 1232 |
| 1233 return remove_unused(srvc); | |
| 1234 } | |
| 1235 | |
| 1236 | |
| 1237 void mwAwareList_setClientData(struct mwAwareList *list, | |
| 1238 gpointer data, GDestroyNotify clear) { | |
| 1239 | |
| 1240 g_return_if_fail(list != NULL); | |
| 1241 mw_datum_set(&list->client_data, data, clear); | |
| 1242 } | |
| 1243 | |
| 1244 | |
| 1245 gpointer mwAwareList_getClientData(struct mwAwareList *list) { | |
| 1246 g_return_val_if_fail(list != NULL, NULL); | |
| 1247 return mw_datum_get(&list->client_data); | |
| 1248 } | |
| 1249 | |
| 1250 | |
| 1251 void mwAwareList_removeClientData(struct mwAwareList *list) { | |
| 1252 g_return_if_fail(list != NULL); | |
| 1253 mw_datum_clear(&list->client_data); | |
| 1254 } | |
| 1255 | |
| 1256 | |
| 1257 void mwServiceAware_setStatus(struct mwServiceAware *srvc, | |
| 1258 struct mwAwareIdBlock *user, | |
| 1259 struct mwUserStatus *stat) { | |
| 1260 | |
| 1261 struct mwAwareSnapshot idb; | |
| 1262 | |
| 1263 g_return_if_fail(srvc != NULL); | |
| 1264 g_return_if_fail(user != NULL); | |
| 1265 g_return_if_fail(stat != NULL); | |
| 1266 | |
| 1267 /* just reference the strings. then we don't need to free them */ | |
| 1268 idb.id.type = user->type; | |
| 1269 idb.id.user = user->user; | |
| 1270 idb.id.community = user->community; | |
| 1271 | |
| 1272 idb.group = NULL; | |
| 1273 idb.online = TRUE; | |
| 1274 idb.alt_id = NULL; | |
| 1275 | |
| 1276 idb.status.status = stat->status; | |
| 1277 idb.status.time = stat->time; | |
| 1278 idb.status.desc = stat->desc; | |
| 1279 | |
| 1280 idb.name = NULL; | |
| 1281 | |
| 1282 status_recv(srvc, &idb); | |
| 1283 } | |
| 1284 | |
| 1285 | |
| 1286 const struct mwAwareAttribute * | |
| 1287 mwServiceAware_getAttribute(struct mwServiceAware *srvc, | |
| 1288 struct mwAwareIdBlock *user, | |
| 1289 guint32 key) { | |
| 1290 | |
| 1291 struct aware_entry *aware; | |
| 1292 | |
| 1293 g_return_val_if_fail(srvc != NULL, NULL); | |
| 1294 g_return_val_if_fail(user != NULL, NULL); | |
| 1295 g_return_val_if_fail(key != 0x00, NULL); | |
| 1296 | |
| 1297 aware = aware_find(srvc, user); | |
| 1298 g_return_val_if_fail(aware != NULL, NULL); | |
| 1299 | |
| 1300 return g_hash_table_lookup(aware->attribs, GUINT_TO_POINTER(key)); | |
| 1301 } | |
| 1302 | |
| 1303 | |
| 1304 const char *mwServiceAware_getText(struct mwServiceAware *srvc, | |
| 1305 struct mwAwareIdBlock *user) { | |
| 1306 | |
| 1307 struct aware_entry *aware; | |
| 1308 | |
| 1309 g_return_val_if_fail(srvc != NULL, NULL); | |
| 1310 g_return_val_if_fail(user != NULL, NULL); | |
| 1311 | |
| 1312 aware = aware_find(srvc, user); | |
|
11943
0110fc7c6a8a
[gaim-migrate @ 14234]
Christopher O'Brien <siege@pidgin.im>
parents:
11291
diff
changeset
|
1313 if(! aware) return NULL; |
| 10969 | 1314 |
| 1315 return aware->aware.status.desc; | |
| 1316 } | |
| 1317 | |
| 1318 |
