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
|
|
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
|