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