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.h>
23 #include <glib.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_GOT_UNKNOWN = 0x025b,  /**< UNKNOWN */
117 
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 
aware_entry_free(struct aware_entry * ae)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 
attrib_entry_free(struct attrib_entry * ae)132 static void attrib_entry_free(struct attrib_entry *ae) {
133   g_list_free(ae->membership);
134   g_free(ae);
135 }
136 
137 
attrib_free(struct mwAwareAttribute * attrib)138 static void attrib_free(struct mwAwareAttribute *attrib) {
139   mwOpaque_clear(&attrib->data);
140   g_free(attrib);
141 }
142 
143 
aware_find(struct mwServiceAware * srvc,struct mwAwareIdBlock * srch)144 static struct aware_entry *aware_find(struct mwServiceAware *srvc,
145 				      struct mwAwareIdBlock *srch) {
146   g_return_val_if_fail(srvc != NULL, NULL);
147   g_return_val_if_fail(srvc->entries != NULL, NULL);
148   g_return_val_if_fail(srch != NULL, NULL);
149 
150   return g_hash_table_lookup(srvc->entries, srch);
151 }
152 
153 
list_aware_find(struct mwAwareList * list,struct mwAwareIdBlock * srch)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 
compose_list(struct mwPutBuffer * b,GList * id_list)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 
send_add(struct mwChannel * chan,GList * id_list)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 
176   g_return_val_if_fail(chan != NULL, 0);
177 
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 
send_rem(struct mwChannel * chan,GList * id_list)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 
194   g_return_val_if_fail(chan != NULL, 0);
195 
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 
collect_dead(gpointer key,gpointer val,gpointer data)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 
remove_unused(struct mwServiceAware * srvc)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 
send_attrib_list(struct mwServiceAware * srvc)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 
258   g_return_val_if_fail(srvc != NULL, -1);
259   g_return_val_if_fail(srvc->channel != NULL, 0);
260 
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 
collect_attrib_dead(gpointer key,gpointer val,gpointer data)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 
remove_unused_attrib(struct mwServiceAware * srvc)297 static int remove_unused_attrib(struct mwServiceAware *srvc) {
298   GList *dead = NULL;
299 
300   if(srvc->attribs) {
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 
310   return MW_SERVICE_IS_LIVE(srvc)? send_attrib_list(srvc): 0;
311 }
312 
313 
recv_accept(struct mwServiceAware * srvc,struct mwChannel * chan,struct mwMsgChannelAccept * msg)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 
recv_destroy(struct mwServiceAware * srvc,struct mwChannel * chan,struct mwMsgChannelDestroy * msg)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 */
status_recv(struct mwServiceAware * srvc,struct mwAwareSnapshot * idb)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 
attrib_recv(struct mwServiceAware * srvc,struct mwAwareIdBlock * idb,struct mwAwareAttribute * attrib)381 static void attrib_recv(struct mwServiceAware *srvc,
382 			struct mwAwareIdBlock *idb,
383 			struct mwAwareAttribute *attrib) {
384 
385   struct aware_entry *aware;
386   struct mwAwareAttribute *old_attrib = NULL;
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 
397   if(aware->attribs)
398     old_attrib = g_hash_table_lookup(aware->attribs, k);
399 
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 
413     if(h && h->on_attrib &&
414        list->attribs && g_hash_table_lookup(list->attribs, k))
415 
416       h->on_attrib(list, idb, old_attrib);
417   }
418 }
419 
420 
list_add(struct mwAwareList * list,struct mwAwareIdBlock * id)421 static gboolean list_add(struct mwAwareList *list,
422 			 struct mwAwareIdBlock *id) {
423 
424   struct mwServiceAware *srvc = list->service;
425   struct aware_entry *aware;
426 
427   g_return_val_if_fail(id->user != NULL, FALSE);
428   g_return_val_if_fail(strlen(id->user) > 0, FALSE);
429 
430   if(! list->entries)
431     list->entries = g_hash_table_new((GHashFunc) mwAwareIdBlock_hash,
432 				     (GEqualFunc) mwAwareIdBlock_equal);
433 
434   aware = list_aware_find(list, id);
435   if(aware) return FALSE;
436 
437   aware = aware_find(srvc, id);
438   if(! aware) {
439     aware = g_new0(struct aware_entry, 1);
440     aware->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
441 					   (GDestroyNotify) attrib_free);
442     mwAwareIdBlock_clone(ENTRY_KEY(aware), id);
443 
444     g_hash_table_insert(srvc->entries, ENTRY_KEY(aware), aware);
445   }
446 
447   aware->membership = g_list_append(aware->membership, list);
448 
449   g_hash_table_insert(list->entries, ENTRY_KEY(aware), aware);
450 
451   return TRUE;
452 }
453 
454 
group_member_recv(struct mwServiceAware * srvc,struct mwAwareSnapshot * idb)455 static void group_member_recv(struct mwServiceAware *srvc,
456 			      struct mwAwareSnapshot *idb) {
457   /* @todo
458      - look up group by id
459      - find each list group belongs to
460      - add user to lists
461   */
462 
463   struct mwAwareIdBlock gsrch = { mwAware_GROUP, idb->group, NULL };
464   struct aware_entry *grp;
465   GList *l, *m;
466 
467   grp = aware_find(srvc, &gsrch);
468   g_return_if_fail(grp != NULL); /* this could happen, with timing. */
469 
470   l = g_list_prepend(NULL, &idb->id);
471 
472   for(m = grp->membership; m; m = m->next) {
473 
474     /* if we just list_add, we won't receive updates for attributes,
475        so annoyingly we have to turn around and send out an add aware
476        message for each incoming group member */
477 
478     /* list_add(m->data, &idb->id); */
479     mwAwareList_addAware(m->data, l);
480   }
481 
482   g_list_free(l);
483 }
484 
485 
recv_SNAPSHOT(struct mwServiceAware * srvc,struct mwGetBuffer * b)486 static void recv_SNAPSHOT(struct mwServiceAware *srvc,
487 			  struct mwGetBuffer *b) {
488 
489   guint32 count;
490 
491   struct mwAwareSnapshot *snap;
492   snap = g_new0(struct mwAwareSnapshot, 1);
493 
494   guint32_get(b, &count);
495 
496   while(count--) {
497     mwAwareSnapshot_get(b, snap);
498 
499     if(mwGetBuffer_error(b)) {
500       mwAwareSnapshot_clear(snap);
501       break;
502     }
503 
504     if(snap->group)
505       group_member_recv(srvc, snap);
506 
507     status_recv(srvc, snap);
508     mwAwareSnapshot_clear(snap);
509   }
510 
511   g_free(snap);
512 }
513 
514 
recv_UPDATE(struct mwServiceAware * srvc,struct mwGetBuffer * b)515 static void recv_UPDATE(struct mwServiceAware *srvc,
516 			struct mwGetBuffer *b) {
517 
518   struct mwAwareSnapshot *snap;
519 
520   snap = g_new0(struct mwAwareSnapshot, 1);
521   mwAwareSnapshot_get(b, snap);
522 
523   if(snap->group)
524     group_member_recv(srvc, snap);
525 
526   if(! mwGetBuffer_error(b))
527     status_recv(srvc, snap);
528 
529   mwAwareSnapshot_clear(snap);
530   g_free(snap);
531 }
532 
533 
recv_GROUP(struct mwServiceAware * srvc,struct mwGetBuffer * b)534 static void recv_GROUP(struct mwServiceAware *srvc,
535 		       struct mwGetBuffer *b) {
536 
537   struct mwAwareIdBlock idb = { 0, 0, 0 };
538 
539   /* really nothing to be done with this. The group should have
540      already been added to the list and service, and is now simply
541      awaiting a snapshot/update with users listed as belonging in said
542      group. */
543 
544   mwAwareIdBlock_get(b, &idb);
545   mwAwareIdBlock_clear(&idb);
546 }
547 
548 
recv_OPT_GOT_SET(struct mwServiceAware * srvc,struct mwGetBuffer * b)549 static void recv_OPT_GOT_SET(struct mwServiceAware *srvc,
550 			     struct mwGetBuffer *b) {
551 
552   struct mwAwareAttribute attrib;
553   struct mwAwareIdBlock idb;
554   guint32 junk, check;
555 
556   guint32_get(b, &junk);
557   mwAwareIdBlock_get(b, &idb);
558   guint32_get(b, &junk);
559   guint32_get(b, &check);
560   guint32_get(b, &junk);
561   guint32_get(b, &attrib.key);
562 
563   if(check) {
564     mwOpaque_get(b, &attrib.data);
565   } else {
566     attrib.data.len = 0;
567     attrib.data.data = NULL;
568   }
569 
570   attrib_recv(srvc, &idb, &attrib);
571 
572   mwAwareIdBlock_clear(&idb);
573   mwOpaque_clear(&attrib.data);
574 }
575 
576 
recv_OPT_GOT_UNSET(struct mwServiceAware * srvc,struct mwGetBuffer * b)577 static void recv_OPT_GOT_UNSET(struct mwServiceAware *srvc,
578 			       struct mwGetBuffer *b) {
579 
580   struct mwAwareAttribute attrib;
581   struct mwAwareIdBlock idb;
582   guint32 junk;
583 
584   attrib.key = 0;
585   attrib.data.len = 0;
586   attrib.data.data = NULL;
587 
588   guint32_get(b, &junk);
589   mwAwareIdBlock_get(b, &idb);
590   guint32_get(b, &attrib.key);
591 
592   attrib_recv(srvc, &idb, &attrib);
593 
594   mwAwareIdBlock_clear(&idb);
595 }
596 
597 
recv(struct mwService * srvc,struct mwChannel * chan,guint16 type,struct mwOpaque * data)598 static void recv(struct mwService *srvc, struct mwChannel *chan,
599 		 guint16 type, struct mwOpaque *data) {
600 
601   struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc;
602   struct mwGetBuffer *b;
603 
604   g_return_if_fail(srvc_aware->channel == chan);
605   g_return_if_fail(srvc->session == mwChannel_getSession(chan));
606   g_return_if_fail(data != NULL);
607 
608   b = mwGetBuffer_wrap(data);
609 
610   switch(type) {
611   case msg_AWARE_SNAPSHOT:
612     recv_SNAPSHOT(srvc_aware, b);
613     break;
614 
615   case msg_AWARE_UPDATE:
616     recv_UPDATE(srvc_aware, b);
617     break;
618 
619   case msg_AWARE_GROUP:
620     recv_GROUP(srvc_aware, b);
621     break;
622 
623   case msg_OPT_GOT_SET:
624     recv_OPT_GOT_SET(srvc_aware, b);
625     break;
626 
627   case msg_OPT_GOT_UNSET:
628     recv_OPT_GOT_UNSET(srvc_aware, b);
629     break;
630 
631   case msg_OPT_GOT_UNKNOWN:
632   case msg_OPT_DID_SET:
633   case msg_OPT_DID_UNSET:
634   case msg_OPT_DID_ERROR:
635     break;
636 
637   default:
638     mw_mailme_opaque(data, "unknown message in aware service: 0x%04x", type);
639   }
640 
641   mwGetBuffer_free(b);
642 }
643 
644 
clear(struct mwService * srvc)645 static void clear(struct mwService *srvc) {
646   struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc;
647 
648   g_return_if_fail(srvc != NULL);
649 
650   while(srvc_aware->lists)
651     mwAwareList_free( (struct mwAwareList *) srvc_aware->lists->data );
652 
653   g_hash_table_destroy(srvc_aware->entries);
654   srvc_aware->entries = NULL;
655 
656   g_hash_table_destroy(srvc_aware->attribs);
657   srvc_aware->attribs = NULL;
658 }
659 
660 
name(struct mwService * srvc)661 static const char *name(struct mwService *srvc) {
662   return "Presence Awareness";
663 }
664 
665 
desc(struct mwService * srvc)666 static const char *desc(struct mwService *srvc) {
667   return "Buddy list service with support for server-side groups";
668 }
669 
670 
make_blist(struct mwServiceAware * srvc,struct mwChannelSet * cs)671 static struct mwChannel *make_blist(struct mwServiceAware *srvc,
672 				    struct mwChannelSet *cs) {
673 
674   struct mwChannel *chan = mwChannel_newOutgoing(cs);
675 
676   mwChannel_setService(chan, MW_SERVICE(srvc));
677   mwChannel_setProtoType(chan, 0x00000011);
678   mwChannel_setProtoVer(chan, 0x00030005);
679 
680   return mwChannel_create(chan)? NULL: chan;
681 }
682 
683 
start(struct mwService * srvc)684 static void start(struct mwService *srvc) {
685   struct mwServiceAware *srvc_aware;
686   struct mwChannel *chan = NULL;
687 
688   srvc_aware = (struct mwServiceAware *) srvc;
689   chan = make_blist(srvc_aware, mwSession_getChannels(srvc->session));
690 
691   if(chan != NULL) {
692     srvc_aware->channel = chan;
693   } else {
694     mwService_stopped(srvc);
695   }
696 }
697 
698 
stop(struct mwService * srvc)699 static void stop(struct mwService *srvc) {
700   struct mwServiceAware *srvc_aware;
701 
702   srvc_aware = (struct mwServiceAware *) srvc;
703 
704   if(srvc_aware->channel) {
705     mwChannel_destroy(srvc_aware->channel, ERR_SUCCESS, NULL);
706     srvc_aware->channel = NULL;
707   }
708 
709   mwService_stopped(srvc);
710 }
711 
712 
713 struct mwServiceAware *
mwServiceAware_new(struct mwSession * session,struct mwAwareHandler * handler)714 mwServiceAware_new(struct mwSession *session,
715 		   struct mwAwareHandler *handler) {
716 
717   struct mwService *service;
718   struct mwServiceAware *srvc;
719 
720   g_return_val_if_fail(session != NULL, NULL);
721   g_return_val_if_fail(handler != NULL, NULL);
722 
723   srvc = g_new0(struct mwServiceAware, 1);
724   srvc->handler = handler;
725   srvc->entries = g_hash_table_new_full((GHashFunc) mwAwareIdBlock_hash,
726 					(GEqualFunc) mwAwareIdBlock_equal,
727 					NULL,
728 					(GDestroyNotify) aware_entry_free);
729 
730   srvc->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
731 					(GDestroyNotify) attrib_entry_free);
732 
733   service = MW_SERVICE(srvc);
734   mwService_init(service, session, mwService_AWARE);
735 
736   service->recv_accept = (mwService_funcRecvAccept) recv_accept;
737   service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
738   service->recv = recv;
739   service->start = start;
740   service->stop = stop;
741   service->clear = clear;
742   service->get_name = name;
743   service->get_desc = desc;
744 
745   return srvc;
746 }
747 
748 
mwServiceAware_setAttribute(struct mwServiceAware * srvc,guint32 key,struct mwOpaque * data)749 int mwServiceAware_setAttribute(struct mwServiceAware *srvc,
750 				guint32 key, struct mwOpaque *data) {
751   struct mwPutBuffer *b;
752   struct mwOpaque o;
753   int ret;
754 
755   b = mwPutBuffer_new();
756 
757   guint32_put(b, 0x00);
758   guint32_put(b, data->len);
759   guint32_put(b, 0x00);
760   guint32_put(b, key);
761   mwOpaque_put(b, data);
762 
763   mwPutBuffer_finalize(&o, b);
764   ret = mwChannel_send(srvc->channel, msg_OPT_DO_SET, &o);
765   mwOpaque_clear(&o);
766 
767   return ret;
768 }
769 
770 
mwServiceAware_setAttributeBoolean(struct mwServiceAware * srvc,guint32 key,gboolean val)771 int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc,
772 				       guint32 key, gboolean val) {
773   int ret;
774   struct mwPutBuffer *b;
775   struct mwOpaque o;
776 
777   b = mwPutBuffer_new();
778 
779   gboolean_put(b, FALSE);
780   gboolean_put(b, val);
781 
782   mwPutBuffer_finalize(&o, b);
783 
784   ret = mwServiceAware_setAttribute(srvc, key, &o);
785   mwOpaque_clear(&o);
786 
787   return ret;
788 }
789 
790 
mwServiceAware_setAttributeInteger(struct mwServiceAware * srvc,guint32 key,guint32 val)791 int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc,
792 				       guint32 key, guint32 val) {
793   int ret;
794   struct mwPutBuffer *b;
795   struct mwOpaque o;
796 
797   b = mwPutBuffer_new();
798   guint32_put(b, val);
799 
800   mwPutBuffer_finalize(&o, b);
801 
802   ret = mwServiceAware_setAttribute(srvc, key, &o);
803   mwOpaque_clear(&o);
804 
805   return ret;
806 }
807 
808 
mwServiceAware_setAttributeString(struct mwServiceAware * srvc,guint32 key,const char * str)809 int mwServiceAware_setAttributeString(struct mwServiceAware *srvc,
810 				      guint32 key, const char *str) {
811   int ret;
812   struct mwPutBuffer *b;
813   struct mwOpaque o;
814 
815   b = mwPutBuffer_new();
816   mwString_put(b, str);
817 
818   mwPutBuffer_finalize(&o, b);
819 
820   ret = mwServiceAware_setAttribute(srvc, key, &o);
821   mwOpaque_clear(&o);
822 
823   return ret;
824 }
825 
826 
mwServiceAware_unsetAttribute(struct mwServiceAware * srvc,guint32 key)827 int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc,
828 				  guint32 key) {
829   struct mwPutBuffer *b;
830   struct mwOpaque o;
831   int ret;
832 
833   b = mwPutBuffer_new();
834 
835   guint32_put(b, 0x00);
836   guint32_put(b, key);
837 
838   mwPutBuffer_finalize(&o, b);
839   ret = mwChannel_send(srvc->channel, msg_OPT_DO_UNSET, &o);
840   mwOpaque_clear(&o);
841 
842   return ret;
843 }
844 
845 
mwAwareAttribute_getKey(const struct mwAwareAttribute * attrib)846 guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib) {
847   g_return_val_if_fail(attrib != NULL, 0x00);
848   return attrib->key;
849 }
850 
851 
mwAwareAttribute_asBoolean(const struct mwAwareAttribute * attrib)852 gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib) {
853   struct mwGetBuffer *b;
854   gboolean ret;
855 
856   if(! attrib) return FALSE;
857 
858   b = mwGetBuffer_wrap(&attrib->data);
859   if(attrib->data.len >= 4) {
860     guint32 r32 = 0x00;
861     guint32_get(b, &r32);
862     ret = !! r32;
863 
864   } else if(attrib->data.len >= 2) {
865     guint16 r16 = 0x00;
866     guint16_get(b, &r16);
867     ret = !! r16;
868 
869   } else if(attrib->data.len) {
870     gboolean_get(b, &ret);
871   }
872 
873   mwGetBuffer_free(b);
874 
875   return ret;
876 }
877 
878 
mwAwareAttribute_asInteger(const struct mwAwareAttribute * attrib)879 guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib) {
880   struct mwGetBuffer *b;
881   guint32 r32 = 0x00;
882 
883   if(! attrib) return 0x00;
884 
885   b = mwGetBuffer_wrap(&attrib->data);
886   if(attrib->data.len >= 4) {
887     guint32_get(b, &r32);
888 
889   } else if(attrib->data.len == 3) {
890     gboolean rb = FALSE;
891     guint16 r16 = 0x00;
892     gboolean_get(b, &rb);
893     guint16_get(b, &r16);
894     r32 = (guint32) r16;
895 
896   } else if(attrib->data.len == 2) {
897     guint16 r16 = 0x00;
898     guint16_get(b, &r16);
899     r32 = (guint32) r16;
900 
901   } else if(attrib->data.len) {
902     gboolean rb = FALSE;
903     gboolean_get(b, &rb);
904     r32 = (guint32) rb;
905   }
906 
907   mwGetBuffer_free(b);
908 
909   return r32;
910 }
911 
912 
mwAwareAttribute_asString(const struct mwAwareAttribute * attrib)913 char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib) {
914   struct mwGetBuffer *b;
915   char *ret = NULL;
916 
917   if(! attrib) return NULL;
918 
919   b = mwGetBuffer_wrap(&attrib->data);
920   mwString_get(b, &ret);
921   mwGetBuffer_free(b);
922 
923   return ret;
924 }
925 
926 
927 const struct mwOpaque *
mwAwareAttribute_asOpaque(const struct mwAwareAttribute * attrib)928 mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib) {
929   g_return_val_if_fail(attrib != NULL, NULL);
930   return &attrib->data;
931 }
932 
933 
934 struct mwAwareList *
mwAwareList_new(struct mwServiceAware * srvc,struct mwAwareListHandler * handler)935 mwAwareList_new(struct mwServiceAware *srvc,
936 		struct mwAwareListHandler *handler) {
937 
938   struct mwAwareList *al;
939 
940   g_return_val_if_fail(srvc != NULL, NULL);
941   g_return_val_if_fail(handler != NULL, NULL);
942 
943   al = g_new0(struct mwAwareList, 1);
944   al->service = srvc;
945   al->handler = handler;
946 
947   srvc->lists = g_list_prepend(srvc->lists, al);
948 
949   return al;
950 }
951 
952 
mwAwareList_free(struct mwAwareList * list)953 void mwAwareList_free(struct mwAwareList *list) {
954   struct mwServiceAware *srvc;
955   struct mwAwareListHandler *handler;
956 
957   g_return_if_fail(list != NULL);
958   g_return_if_fail(list->service != NULL);
959 
960   srvc = list->service;
961   srvc->lists = g_list_remove_all(srvc->lists, list);
962 
963   handler = list->handler;
964   if(handler && handler->clear) {
965     handler->clear(list);
966     list->handler = NULL;
967   }
968 
969   mw_datum_clear(&list->client_data);
970 
971   mwAwareList_unwatchAllAttributes(list);
972   mwAwareList_removeAllAware(list);
973 
974   list->service = NULL;
975 
976   g_free(list);
977 }
978 
979 
mwAwareList_getHandler(struct mwAwareList * list)980 struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list) {
981   g_return_val_if_fail(list != NULL, NULL);
982   return list->handler;
983 }
984 
985 
watch_add(struct mwAwareList * list,guint32 key)986 static void watch_add(struct mwAwareList *list, guint32 key) {
987   struct mwServiceAware *srvc;
988   struct attrib_entry *watch;
989   gpointer k = GUINT_TO_POINTER(key);
990 
991   if(! list->attribs)
992     list->attribs = g_hash_table_new(g_direct_hash, g_direct_equal);
993 
994   if(g_hash_table_lookup(list->attribs, k))
995     return;
996 
997   srvc = list->service;
998 
999   watch = g_hash_table_lookup(srvc->attribs, k);
1000   if(! watch) {
1001     watch = g_new0(struct attrib_entry, 1);
1002     watch->key = key;
1003     g_hash_table_insert(srvc->attribs, k, watch);
1004   }
1005 
1006   g_hash_table_insert(list->attribs, k, watch);
1007 
1008   watch->membership = g_list_prepend(watch->membership, list);
1009 }
1010 
1011 
watch_remove(struct mwAwareList * list,guint32 key)1012 static void watch_remove(struct mwAwareList *list, guint32 key) {
1013   struct attrib_entry *watch = NULL;
1014   gpointer k = GUINT_TO_POINTER(key);
1015 
1016   if(list->attribs)
1017     watch = g_hash_table_lookup(list->attribs, k);
1018 
1019   g_return_if_fail(watch != NULL);
1020 
1021   g_hash_table_remove(list->attribs, k);
1022   watch->membership = g_list_remove(watch->membership, list);
1023 }
1024 
1025 
mwAwareList_watchAttributeArray(struct mwAwareList * list,guint32 * keys)1026 int mwAwareList_watchAttributeArray(struct mwAwareList *list,
1027 				    guint32 *keys) {
1028   guint32 k;
1029 
1030   g_return_val_if_fail(list != NULL, -1);
1031   g_return_val_if_fail(list->service != NULL, -1);
1032 
1033   if(! keys) return 0;
1034 
1035   for(k = *keys; k; keys++)
1036     watch_add(list, k);
1037 
1038   return send_attrib_list(list->service);
1039 }
1040 
1041 
mwAwareList_watchAttributes(struct mwAwareList * list,guint32 key,...)1042 int mwAwareList_watchAttributes(struct mwAwareList *list,
1043 				guint32 key, ...) {
1044   guint32 k;
1045   va_list args;
1046 
1047   g_return_val_if_fail(list != NULL, -1);
1048   g_return_val_if_fail(list->service != NULL, -1);
1049 
1050   va_start(args, key);
1051   for(k = key; k; k = va_arg(args, guint32))
1052     watch_add(list, k);
1053   va_end(args);
1054 
1055   return send_attrib_list(list->service);
1056 }
1057 
1058 
mwAwareList_unwatchAttributeArray(struct mwAwareList * list,guint32 * keys)1059 int mwAwareList_unwatchAttributeArray(struct mwAwareList *list,
1060 				      guint32 *keys) {
1061   guint32 k;
1062 
1063   g_return_val_if_fail(list != NULL, -1);
1064   g_return_val_if_fail(list->service != NULL, -1);
1065 
1066   if(! keys) return 0;
1067 
1068   for(k = *keys; k; keys++)
1069     watch_add(list, k);
1070 
1071   return remove_unused_attrib(list->service);
1072 }
1073 
1074 
mwAwareList_unwatchAttributes(struct mwAwareList * list,guint32 key,...)1075 int mwAwareList_unwatchAttributes(struct mwAwareList *list,
1076 				  guint32 key, ...) {
1077   guint32 k;
1078   va_list args;
1079 
1080   g_return_val_if_fail(list != NULL, -1);
1081   g_return_val_if_fail(list->service != NULL, -1);
1082 
1083   va_start(args, key);
1084   for(k = key; k; k = va_arg(args, guint32))
1085     watch_remove(list, k);
1086   va_end(args);
1087 
1088   return remove_unused_attrib(list->service);
1089 }
1090 
1091 
dismember_attrib(gpointer k,struct attrib_entry * watch,struct mwAwareList * list)1092 static void dismember_attrib(gpointer k, struct attrib_entry *watch,
1093 			    struct mwAwareList *list) {
1094 
1095   watch->membership = g_list_remove(watch->membership, list);
1096 }
1097 
1098 
mwAwareList_unwatchAllAttributes(struct mwAwareList * list)1099 int mwAwareList_unwatchAllAttributes(struct mwAwareList *list) {
1100 
1101   struct mwServiceAware *srvc;
1102 
1103   g_return_val_if_fail(list != NULL, -1);
1104   srvc = list->service;
1105 
1106   if(list->attribs) {
1107     g_hash_table_foreach(list->attribs, (GHFunc) dismember_attrib, list);
1108     g_hash_table_destroy(list->attribs);
1109   }
1110 
1111   return remove_unused_attrib(srvc);
1112 }
1113 
1114 
collect_attrib_keys(gpointer key,struct attrib_entry * attrib,guint32 ** ck)1115 static void collect_attrib_keys(gpointer key, struct attrib_entry *attrib,
1116 				guint32 **ck) {
1117   guint32 *keys = (*ck)++;
1118   *keys = GPOINTER_TO_UINT(key);
1119 }
1120 
1121 
mwAwareList_getWatchedAttributes(struct mwAwareList * list)1122 guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list) {
1123   guint32 *keys, **ck;
1124   guint count;
1125 
1126   g_return_val_if_fail(list != NULL, NULL);
1127   g_return_val_if_fail(list->attribs != NULL, NULL);
1128 
1129   count = g_hash_table_size(list->attribs);
1130   keys = g_new0(guint32, count + 1);
1131 
1132   ck = &keys;
1133   g_hash_table_foreach(list->attribs, (GHFunc) collect_attrib_keys, ck);
1134 
1135   return keys;
1136 }
1137 
1138 
mwAwareList_addAware(struct mwAwareList * list,GList * id_list)1139 int mwAwareList_addAware(struct mwAwareList *list, GList *id_list) {
1140 
1141   /* for each awareness id:
1142      - if it's already in the list, continue
1143      - if it's not in the service list:
1144        - create an awareness
1145        - add it to the service list
1146      - add this list to the membership
1147      - add to the list
1148   */
1149 
1150   struct mwServiceAware *srvc;
1151   GList *additions = NULL;
1152   int ret = 0;
1153 
1154   g_return_val_if_fail(list != NULL, -1);
1155 
1156   srvc = list->service;
1157   g_return_val_if_fail(srvc != NULL, -1);
1158 
1159   for(; id_list; id_list = id_list->next) {
1160     if(list_add(list, id_list->data))
1161       additions = g_list_prepend(additions, id_list->data);
1162   }
1163 
1164   /* if the service is alive-- or getting there-- we'll need to send
1165      these additions upstream */
1166   if(MW_SERVICE_IS_LIVE(srvc) && additions)
1167     ret = send_add(srvc->channel, additions);
1168 
1169   g_list_free(additions);
1170   return ret;
1171 }
1172 
1173 
mwAwareList_removeAware(struct mwAwareList * list,GList * id_list)1174 int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list) {
1175 
1176   /* for each awareness id:
1177      - if it's not in the list, forget it
1178      - remove from the list
1179      - remove list from the membership
1180 
1181      - call remove round
1182   */
1183 
1184   struct mwServiceAware *srvc;
1185   struct mwAwareIdBlock *id;
1186   struct aware_entry *aware;
1187 
1188   g_return_val_if_fail(list != NULL, -1);
1189 
1190   srvc = list->service;
1191   g_return_val_if_fail(srvc != NULL, -1);
1192 
1193   for(; id_list; id_list = id_list->next) {
1194     id = id_list->data;
1195     aware = list_aware_find(list, id);
1196 
1197     if(! aware) {
1198       g_warning("buddy %s, %s not in list",
1199 		NSTR(id->user),
1200 		NSTR(id->community));
1201       continue;
1202     }
1203 
1204     aware->membership = g_list_remove(aware->membership, list);
1205     g_hash_table_remove(list->entries, id);
1206   }
1207 
1208   return remove_unused(srvc);
1209 }
1210 
1211 
dismember_aware(gpointer k,struct aware_entry * aware,struct mwAwareList * list)1212 static void dismember_aware(gpointer k, struct aware_entry *aware,
1213 			    struct mwAwareList *list) {
1214 
1215   aware->membership = g_list_remove(aware->membership, list);
1216 }
1217 
1218 
mwAwareList_removeAllAware(struct mwAwareList * list)1219 int mwAwareList_removeAllAware(struct mwAwareList *list) {
1220   struct mwServiceAware *srvc;
1221 
1222   g_return_val_if_fail(list != NULL, -1);
1223   srvc = list->service;
1224 
1225   g_return_val_if_fail(srvc != NULL, -1);
1226 
1227   /* for each entry, remove the aware list from the service entry's
1228      membership collection */
1229   if(list->entries) {
1230     g_hash_table_foreach(list->entries, (GHFunc) dismember_aware, list);
1231     g_hash_table_destroy(list->entries);
1232   }
1233 
1234   return remove_unused(srvc);
1235 }
1236 
1237 
mwAwareList_setClientData(struct mwAwareList * list,gpointer data,GDestroyNotify clear)1238 void mwAwareList_setClientData(struct mwAwareList *list,
1239 			       gpointer data, GDestroyNotify clear) {
1240 
1241   g_return_if_fail(list != NULL);
1242   mw_datum_set(&list->client_data, data, clear);
1243 }
1244 
1245 
mwAwareList_getClientData(struct mwAwareList * list)1246 gpointer mwAwareList_getClientData(struct mwAwareList *list) {
1247   g_return_val_if_fail(list != NULL, NULL);
1248   return mw_datum_get(&list->client_data);
1249 }
1250 
1251 
mwAwareList_removeClientData(struct mwAwareList * list)1252 void mwAwareList_removeClientData(struct mwAwareList *list) {
1253   g_return_if_fail(list != NULL);
1254   mw_datum_clear(&list->client_data);
1255 }
1256 
1257 
mwServiceAware_setStatus(struct mwServiceAware * srvc,struct mwAwareIdBlock * user,struct mwUserStatus * stat)1258 void mwServiceAware_setStatus(struct mwServiceAware *srvc,
1259 			      struct mwAwareIdBlock *user,
1260 			      struct mwUserStatus *stat) {
1261 
1262   struct mwAwareSnapshot idb;
1263 
1264   g_return_if_fail(srvc != NULL);
1265   g_return_if_fail(user != NULL);
1266   g_return_if_fail(stat != NULL);
1267 
1268   /* just reference the strings. then we don't need to free them */
1269   idb.id.type = user->type;
1270   idb.id.user = user->user;
1271   idb.id.community = user->community;
1272 
1273   idb.group = NULL;
1274   idb.online = TRUE;
1275   idb.alt_id = NULL;
1276 
1277   idb.status.status = stat->status;
1278   idb.status.time = stat->time;
1279   idb.status.desc = stat->desc;
1280 
1281   idb.name = NULL;
1282 
1283   status_recv(srvc, &idb);
1284 }
1285 
1286 
1287 const struct mwAwareAttribute *
mwServiceAware_getAttribute(struct mwServiceAware * srvc,struct mwAwareIdBlock * user,guint32 key)1288 mwServiceAware_getAttribute(struct mwServiceAware *srvc,
1289 			    struct mwAwareIdBlock *user,
1290 			    guint32 key) {
1291 
1292   struct aware_entry *aware;
1293 
1294   g_return_val_if_fail(srvc != NULL, NULL);
1295   g_return_val_if_fail(user != NULL, NULL);
1296   g_return_val_if_fail(key != 0x00, NULL);
1297 
1298   aware = aware_find(srvc, user);
1299   g_return_val_if_fail(aware != NULL, NULL);
1300 
1301   return g_hash_table_lookup(aware->attribs, GUINT_TO_POINTER(key));
1302 }
1303 
1304 
mwServiceAware_getText(struct mwServiceAware * srvc,struct mwAwareIdBlock * user)1305 const char *mwServiceAware_getText(struct mwServiceAware *srvc,
1306 				   struct mwAwareIdBlock *user) {
1307 
1308   struct aware_entry *aware;
1309 
1310   g_return_val_if_fail(srvc != NULL, NULL);
1311   g_return_val_if_fail(user != NULL, NULL);
1312 
1313   aware = aware_find(srvc, user);
1314   if(! aware) return NULL;
1315 
1316   return aware->aware.status.desc;
1317 }
1318 
1319 
1320