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 
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include "mw_channel.h"
29 #include "mw_common.h"
30 #include "mw_debug.h"
31 #include "mw_error.h"
32 #include "mw_message.h"
33 #include "mw_service.h"
34 #include "mw_session.h"
35 #include "mw_srvc_place.h"
36 #include "mw_util.h"
37 
38 
39 #define PROTOCOL_TYPE  0x00
40 #define PROTOCOL_VER   0x05
41 
42 
43 enum incoming_msg {
44   msg_in_JOIN_RESPONSE  = 0x0000,  /* ? */
45   msg_in_INFO           = 0x0002,
46   msg_in_MESSAGE        = 0x0004,
47   msg_in_SECTION        = 0x0014,  /* see in_section_subtype */
48   msg_in_UNKNOWNa       = 0x0015,
49 };
50 
51 
52 enum in_section_subtype {
53   msg_in_SECTION_LIST  = 0x0000,  /* list of section members */
54   msg_in_SECTION_PEER  = 0x0001,  /* see in_section_peer_subtye */
55   msg_in_SECTION_PART  = 0x0003,
56 };
57 
58 
59 enum in_section_peer_subtype {
60   msg_in_SECTION_PEER_JOIN        = 0x0000,
61   msg_in_SECTION_PEER_PART        = 0x0001,  /* after msg_in_SECTION_PART */
62   msg_in_SECTION_PEER_CLEAR_ATTR  = 0x0003,
63   msg_in_SECTION_PEER_SET_ATTR    = 0x0004,
64 };
65 
66 
67 enum outgoing_msg {
68   msg_out_JOIN_PLACE  = 0x0000,  /* ? */
69   msg_out_PEER_INFO   = 0x0002,  /* ? */
70   msg_out_MESSAGE     = 0x0003,
71   msg_out_OLD_INVITE  = 0x0005,  /* old-style conf. invitation */
72   msg_out_SET_ATTR    = 0x000a,
73   msg_out_CLEAR_ATTR  = 0x000b,
74   msg_out_SECTION     = 0x0014,  /* see out_section_subtype */
75   msg_out_UNKNOWNb    = 0x001e,  /* ? maybe enter stage ? */
76 };
77 
78 
79 enum out_section_subtype {
80   msg_out_SECTION_LIST  = 0x0002,  /* req list of members */
81   msg_out_SECTION_PART  = 0x0003,
82 };
83 
84 
85 /*
86   : allocate section
87   : state = NEW
88 
89   : create channel
90   : state = PENDING
91 
92   : channel accepted
93   : msg_out_JOIN_PLACE  (maybe create?)
94   : state = JOINING
95 
96   : msg_in_JOIN_RESPONSE (contains our place member ID and section ID)
97   : msg_in_INFO (for place, not peer)
98   : state = JOINED
99 
100   : msg_out_SECTION_LIST (asking for all sections) (optional)
101   : msg_in_SECTION_LIST (listing all sections, as requested above)
102 
103   : msg_out_PEER_INFO (with our place member ID) (optional)
104   : msg_in_INFO (peer info as requested above)
105 
106   : msg_out_SECTION_LIST (with our section ID) (sorta optional)
107   : msg_in_SECTION_LIST (section listing as requested above)
108 
109   : msg_out_UNKNOWNb
110   : msg_in_SECTION_PEER_JOINED (empty, with our place member ID)
111   : state = OPEN
112 
113   : stuff... (invites, joins, parts, messages, attr)
114 
115   : state = CLOSING
116   : msg_out_SECTION_PART
117   : destroy channel
118   : deallocate section
119 */
120 
121 
122 struct mwServicePlace {
123   struct mwService service;
124   struct mwPlaceHandler *handler;
125   GList *places;
126 };
127 
128 
129 enum mwPlaceState {
130   mwPlace_NEW,
131   mwPlace_PENDING,
132   mwPlace_JOINING,
133   mwPlace_JOINED,
134   mwPlace_OPEN,
135   mwPlace_CLOSING,
136   mwPlace_ERROR,
137   mwPlace_UNKNOWN,
138 };
139 
140 
141 struct mwPlace {
142   struct mwServicePlace *service;
143 
144   enum mwPlaceState state;
145   struct mwChannel *channel;
146 
147   char *name;
148   char *title;
149   GHashTable *members;  /* mapping of member ID: place_member */
150   guint32 our_id;       /* our member ID */
151   guint32 section;      /* the section we're using */
152 
153   guint32 requests;     /* counter for requests */
154 
155   struct mw_datum client_data;
156 };
157 
158 
159 struct place_member {
160   guint32 place_id;
161   guint16 member_type;
162   struct mwIdBlock idb;
163   char *login_id;
164   char *name;
165   guint16 login_type;
166   guint32 unknown_a;
167   guint32 unknown_b;
168 };
169 
170 
171 #define GET_MEMBER(place, id) \
172   (g_hash_table_lookup(place->members, GUINT_TO_POINTER(id)))
173 
174 
175 #define PUT_MEMBER(place, member) \
176   (g_hash_table_insert(place->members, \
177                        GUINT_TO_POINTER(member->place_id), member))
178 
179 
180 #define REMOVE_MEMBER_ID(place, id) \
181   (g_hash_table_remove(place->members, GUINT_TO_POINTER(id)))
182 
183 
184 #define REMOVE_MEMBER(place, member) \
185   REMOVE_MEMBER_ID(place, member->place_id)
186 
187 
member_free(struct place_member * p)188 static void member_free(struct place_member *p) {
189   mwIdBlock_clear(&p->idb);
190   g_free(p->login_id);
191   g_free(p->name);
192   g_free(p);
193 }
194 
195 
196 __attribute__((used))
197 static const struct mwLoginInfo *
member_as_login_info(struct place_member * p)198 member_as_login_info(struct place_member *p) {
199   static struct mwLoginInfo li;
200 
201   li.login_id = p->login_id;
202   li.type = p->login_type;
203   li.user_id = p->idb.user;
204   li.user_name = p->name;
205   li.community = p->idb.community;
206   li.full = FALSE;
207 
208   return &li;
209 }
210 
211 
place_state_str(enum mwPlaceState s)212 static const char *place_state_str(enum mwPlaceState s) {
213   switch(s) {
214   case mwPlace_NEW:      return "new";
215   case mwPlace_PENDING:  return "pending";
216   case mwPlace_JOINING:  return "joining";
217   case mwPlace_JOINED:   return "joined";
218   case mwPlace_OPEN:     return "open";
219   case mwPlace_CLOSING:  return "closing";
220   case mwPlace_ERROR:    return "error";
221 
222   case mwPlace_UNKNOWN:  /* fall-through */
223   default:               return "UNKNOWN";
224   }
225 }
226 
227 
place_state(struct mwPlace * place,enum mwPlaceState s)228 static void place_state(struct mwPlace *place, enum mwPlaceState s) {
229   g_return_if_fail(place != NULL);
230 
231   if(place->state == s) return;
232 
233   place->state = s;
234   g_message("place %s state: %s", NSTR(place->name), place_state_str(s));
235 }
236 
237 
place_free(struct mwPlace * place)238 static void place_free(struct mwPlace *place) {
239   struct mwServicePlace *srvc;
240 
241   if(! place) return;
242 
243   srvc = place->service;
244   g_return_if_fail(srvc != NULL);
245 
246   srvc->places = g_list_remove_all(srvc->places, place);
247 
248   mw_datum_clear(&place->client_data);
249 
250   g_hash_table_destroy(place->members);
251 
252   g_free(place->name);
253   g_free(place->title);
254   g_free(place);
255 }
256 
257 
recv_JOIN_RESPONSE(struct mwPlace * place,struct mwGetBuffer * b)258 static int recv_JOIN_RESPONSE(struct mwPlace *place,
259 			      struct mwGetBuffer *b) {
260 
261   int ret = 0;
262   guint32 our_id, section;
263 
264   guint32_get(b, &our_id);
265   guint32_get(b, &section);
266 
267   place->our_id = our_id;
268   place->section = section;
269 
270   return ret;
271 }
272 
273 
send_SECTION_LIST(struct mwPlace * place,guint32 section)274 static int send_SECTION_LIST(struct mwPlace *place, guint32 section) {
275   int ret = 0;
276   struct mwOpaque o = {0, 0};
277   struct mwPutBuffer *b;
278 
279   b = mwPutBuffer_new();
280   guint16_put(b, msg_out_SECTION_LIST);
281   guint32_put(b, section);
282   gboolean_put(b, FALSE);
283   guint32_put(b, ++place->requests);
284   mwPutBuffer_finalize(&o, b);
285 
286   ret = mwChannel_send(place->channel, msg_out_SECTION, &o);
287   mwOpaque_clear(&o);
288 
289   return ret;
290 }
291 
292 
recv_INFO(struct mwPlace * place,struct mwGetBuffer * b)293 static int recv_INFO(struct mwPlace *place,
294 		     struct mwGetBuffer *b) {
295 
296   int ret = 0;
297   guint32 skip = 0;
298   guint32 section = 0;
299 
300   guint32_get(b, &skip);
301   guint32_get(b, &section);
302   mwGetBuffer_advance(b, skip);
303 
304   if(! section) {
305     /* this is a place info rather than member info */
306     if(place->title) g_free(place->title);
307     mwGetBuffer_advance(b, 2);
308     mwString_get(b, &place->title);
309 
310     place_state(place, mwPlace_JOINED);
311     ret = send_SECTION_LIST(place, place->section);
312   }
313 
314   return ret;
315 }
316 
317 
recv_MESSAGE(struct mwPlace * place,struct mwGetBuffer * b)318 static int recv_MESSAGE(struct mwPlace *place,
319 			struct mwGetBuffer *b) {
320 
321   struct mwServicePlace *srvc;
322   guint32 pm_id;
323   guint32 unkn_a, unkn_b, ign;
324   struct place_member *pm;
325   char *msg = NULL;
326   int ret = 0;
327 
328   srvc = place->service;
329 
330   /* no messages before becoming fully open, please */
331   g_return_val_if_fail(place->state == mwPlace_OPEN, -1);
332 
333   /* regarding unkn_a and unkn_b:
334 
335      they're probably a section indicator and a message count, I'm
336      just not sure which is which. Until this implementation supports
337      place sections in the API, it really doesn't matter. */
338 
339   guint32_get(b, &pm_id);
340   pm = GET_MEMBER(place, pm_id);
341   g_return_val_if_fail(pm != NULL, -1);
342 
343   guint32_get(b, &unkn_a);
344   guint32_get(b, &ign);     /* actually an opaque length */
345 
346   if(! ign) return ret;
347 
348   guint32_get(b, &unkn_b);
349   mwString_get(b, &msg);
350 
351   if(srvc->handler && srvc->handler->message)
352     srvc->handler->message(place, &pm->idb, msg);
353 
354   g_free(msg);
355 
356   return ret;
357 }
358 
359 
place_opened(struct mwPlace * place)360 static void place_opened(struct mwPlace *place) {
361     struct mwServicePlace *srvc;
362 
363     place_state(place, mwPlace_OPEN);
364 
365     srvc = place->service;
366     if(srvc->handler && srvc->handler->opened)
367       srvc->handler->opened(place);
368 }
369 
370 
recv_SECTION_PEER_JOIN(struct mwPlace * place,struct mwGetBuffer * b)371 static int recv_SECTION_PEER_JOIN(struct mwPlace *place,
372 				  struct mwGetBuffer *b) {
373   struct mwServicePlace *srvc;
374   struct place_member *pm;
375   guint32 section;
376   int ret = 0;
377 
378   srvc = place->service;
379 
380   guint32_get(b, &section);
381   if(! section) {
382     g_info("SECTION_PEER_JOIN with section 0x00");
383     return 0;
384   }
385 
386   mwGetBuffer_advance(b, 4);
387 
388   pm = g_new0(struct place_member, 1);
389   guint32_get(b, &pm->place_id);
390   guint16_get(b, &pm->member_type);
391   mwIdBlock_get(b, &pm->idb);
392   mwString_get(b, &pm->login_id);
393   mwString_get(b, &pm->name);
394   guint16_get(b, &pm->login_type);
395   guint32_get(b, &pm->unknown_a);
396   guint32_get(b, &pm->unknown_b);
397 
398   PUT_MEMBER(place, pm);
399   if(srvc->handler && srvc->handler->peerJoined)
400     srvc->handler->peerJoined(place, &pm->idb);
401 
402   if(pm->place_id == place->our_id)
403     place_opened(place);
404 
405   return ret;
406 }
407 
408 
recv_SECTION_PEER_PART(struct mwPlace * place,struct mwGetBuffer * b)409 static int recv_SECTION_PEER_PART(struct mwPlace *place,
410 				  struct mwGetBuffer *b) {
411   struct mwServicePlace *srvc;
412   int ret = 0;
413   guint32 section, id;
414   struct place_member *pm;
415 
416   srvc = place->service;
417 
418   guint32_get(b, &section);
419   g_return_val_if_fail(section == place->section, 0);
420 
421   guint32_get(b, &id);
422   pm = GET_MEMBER(place, id);
423 
424   /* SECTION_PART may have been called already */
425   if(! pm) return 0;
426 
427   if(srvc->handler && srvc->handler->peerParted)
428     srvc->handler->peerParted(place, &pm->idb);
429 
430   REMOVE_MEMBER(place, pm);
431 
432   return ret;
433 }
434 
435 
recv_SECTION_PEER_CLEAR_ATTR(struct mwPlace * place,struct mwGetBuffer * b)436 static int recv_SECTION_PEER_CLEAR_ATTR(struct mwPlace *place,
437 					struct mwGetBuffer *b) {
438   struct mwServicePlace *srvc;
439   int ret = 0;
440   guint32 id, attr;
441   struct place_member *pm;
442 
443   srvc = place->service;
444 
445   guint32_get(b, &id);
446   guint32_get(b, &attr);
447 
448   pm = GET_MEMBER(place, id);
449   g_return_val_if_fail(pm != NULL, -1);
450 
451   if(srvc->handler && srvc->handler->peerUnsetAttribute)
452     srvc->handler->peerUnsetAttribute(place, &pm->idb, attr);
453 
454   return ret;
455 }
456 
457 
recv_SECTION_PEER_SET_ATTR(struct mwPlace * place,struct mwGetBuffer * b)458 static int recv_SECTION_PEER_SET_ATTR(struct mwPlace *place,
459 				      struct mwGetBuffer *b) {
460   struct mwServicePlace *srvc;
461   int ret = 0;
462   guint32 id, attr;
463   struct mwOpaque o = {0,0};
464   struct place_member *pm;
465 
466   srvc = place->service;
467 
468   guint32_get(b, &id);
469   mwGetBuffer_advance(b, 4);
470   mwOpaque_get(b, &o);
471   mwGetBuffer_advance(b, 4);
472   guint32_get(b, &attr);
473 
474   pm = GET_MEMBER(place, id);
475   g_return_val_if_fail(pm != NULL, -1);
476 
477   if(srvc->handler && srvc->handler->peerSetAttribute)
478     srvc->handler->peerSetAttribute(place, &pm->idb, attr, &o);
479 
480   mwOpaque_clear(&o);
481 
482   return ret;
483 }
484 
485 
recv_SECTION_PEER(struct mwPlace * place,struct mwGetBuffer * b)486 static int recv_SECTION_PEER(struct mwPlace *place,
487 			      struct mwGetBuffer *b) {
488   guint16 subtype;
489   int res;
490 
491   guint16_get(b, &subtype);
492 
493   g_return_val_if_fail(! mwGetBuffer_error(b), -1);
494 
495   switch(subtype) {
496   case msg_in_SECTION_PEER_JOIN:
497     res = recv_SECTION_PEER_JOIN(place, b);
498     break;
499 
500   case msg_in_SECTION_PEER_PART:
501     res = recv_SECTION_PEER_PART(place, b);
502     break;
503 
504   case msg_in_SECTION_PEER_CLEAR_ATTR:
505     res = recv_SECTION_PEER_CLEAR_ATTR(place, b);
506     break;
507 
508   case msg_in_SECTION_PEER_SET_ATTR:
509     res = recv_SECTION_PEER_SET_ATTR(place, b);
510     break;
511 
512   default:
513     res = -1;
514   }
515 
516   return res;
517 }
518 
519 
recv_SECTION_LIST(struct mwPlace * place,struct mwGetBuffer * b)520 static int recv_SECTION_LIST(struct mwPlace *place,
521 			     struct mwGetBuffer *b) {
522   int ret = 0;
523   guint32 sec, count;
524 
525   mwGetBuffer_advance(b, 4);
526   guint32_get(b, &sec);
527 
528   g_return_val_if_fail(sec == place->section, -1);
529 
530   mwGetBuffer_advance(b, 8);
531   guint32_get(b, &count);
532   mwGetBuffer_advance(b, 8);
533 
534   while(count--) {
535     struct place_member *m;
536 
537     m = g_new0(struct place_member, 1);
538     mwGetBuffer_advance(b, 4);
539     guint32_get(b, &m->place_id);
540     guint16_get(b, &m->member_type);
541     mwIdBlock_get(b, &m->idb);
542     mwString_get(b, &m->login_id);
543     mwString_get(b, &m->name);
544     guint16_get(b, &m->login_type);
545     guint32_get(b, &m->unknown_a);
546     guint32_get(b, &m->unknown_b);
547 
548     PUT_MEMBER(place, m);
549   }
550 
551   if(place->state != mwPlace_OPEN)
552     place_opened(place);
553 
554   return ret;
555 }
556 
557 
recv_SECTION_PART(struct mwPlace * place,struct mwGetBuffer * b)558 static int recv_SECTION_PART(struct mwPlace *place,
559 			     struct mwGetBuffer *b) {
560   /* look up user in place
561      remove user from place
562      trigger event */
563 
564   struct mwServicePlace *srvc;
565   guint32 pm_id;
566   struct place_member *pm;
567 
568   srvc = place->service;
569 
570   guint32_get(b, &pm_id);
571   pm = GET_MEMBER(place, pm_id);
572 
573   /* SECTION_PEER_PART may have been called already */
574   if(! pm) return 0;
575 
576   if(srvc->handler && srvc->handler->peerParted)
577     srvc->handler->peerParted(place, &pm->idb);
578 
579   REMOVE_MEMBER(place, pm);
580 
581   return 0;
582 }
583 
584 
recv_SECTION(struct mwPlace * place,struct mwGetBuffer * b)585 static int recv_SECTION(struct mwPlace *place, struct mwGetBuffer *b) {
586   guint16 subtype;
587   int res;
588 
589   guint16_get(b, &subtype);
590 
591   g_return_val_if_fail(! mwGetBuffer_error(b), -1);
592 
593   switch(subtype) {
594   case msg_in_SECTION_LIST:
595     res = recv_SECTION_LIST(place, b);
596     break;
597 
598   case msg_in_SECTION_PEER:
599     res = recv_SECTION_PEER(place, b);
600     break;
601 
602   case msg_in_SECTION_PART:
603     res = recv_SECTION_PART(place, b);
604     break;
605 
606   default:
607     res = -1;
608   }
609 
610   return res;
611 }
612 
613 
recv_UNKNOWNa(struct mwPlace * place,struct mwGetBuffer * b)614 static int recv_UNKNOWNa(struct mwPlace *place, struct mwGetBuffer *b) {
615   int res = 0;
616 
617   if(place->state == mwPlace_JOINING) {
618     ;
619     /* place_state(place, mwPlace_JOINED);
620        res = send_SECTION_LIST(place, place->section); */
621 
622   } else if(place->state == mwPlace_JOINED) {
623     ;
624     /* if(GET_MEMBER(place, place->our_id))
625        place_opened(place); */
626   }
627 
628   return res;
629 }
630 
631 
recv(struct mwService * service,struct mwChannel * chan,guint16 type,struct mwOpaque * data)632 static void recv(struct mwService *service, struct mwChannel *chan,
633 		 guint16 type, struct mwOpaque *data) {
634 
635   struct mwPlace *place;
636   struct mwGetBuffer *b;
637   int res = 0;
638 
639   place = mwChannel_getServiceData(chan);
640   g_return_if_fail(place != NULL);
641 
642   b = mwGetBuffer_wrap(data);
643   switch(type) {
644   case msg_in_JOIN_RESPONSE:
645     res = recv_JOIN_RESPONSE(place, b);
646     break;
647 
648   case msg_in_INFO:
649     res = recv_INFO(place, b);
650     break;
651 
652   case msg_in_MESSAGE:
653     res = recv_MESSAGE(place, b);
654     break;
655 
656   case msg_in_SECTION:
657     res = recv_SECTION(place, b);
658     break;
659 
660   case msg_in_UNKNOWNa:
661     res = recv_UNKNOWNa(place, b);
662     break;
663 
664   default:
665     mw_mailme_opaque(data, "Received unknown message type 0x%x on place %s",
666 		     type, NSTR(place->name));
667   }
668 
669   if(res) {
670     mw_mailme_opaque(data, "Troubling parsing message type 0x0%x on place %s",
671 		     type, NSTR(place->name));
672   }
673 
674   mwGetBuffer_free(b);
675 }
676 
677 
stop(struct mwServicePlace * srvc)678 static void stop(struct mwServicePlace *srvc) {
679   while(srvc->places)
680     mwPlace_destroy(srvc->places->data, ERR_SUCCESS);
681 
682   mwService_stopped(MW_SERVICE(srvc));
683 }
684 
685 
send_JOIN_PLACE(struct mwPlace * place)686 static int send_JOIN_PLACE(struct mwPlace *place) {
687   struct mwOpaque o = {0, 0};
688   struct mwPutBuffer *b;
689   int ret;
690 
691   b = mwPutBuffer_new();
692   gboolean_put(b, FALSE);
693   guint16_put(b, 0x01);
694   guint16_put(b, 0x02); /* 0x01 */
695   guint16_put(b, 0x01); /* 0x00 */
696 
697   mwPutBuffer_finalize(&o, b);
698 
699   ret = mwChannel_send(place->channel, msg_out_JOIN_PLACE, &o);
700 
701   mwOpaque_clear(&o);
702 
703   if(ret) {
704     place_state(place, mwPlace_ERROR);
705   } else {
706     place_state(place, mwPlace_JOINING);
707   }
708 
709   return ret;
710 }
711 
712 
recv_channelAccept(struct mwService * service,struct mwChannel * chan,struct mwMsgChannelAccept * msg)713 static void recv_channelAccept(struct mwService *service,
714 			       struct mwChannel *chan,
715 			       struct mwMsgChannelAccept *msg) {
716   struct mwServicePlace *srvc;
717   struct mwPlace *place;
718   int res;
719 
720   srvc = (struct mwServicePlace *) service;
721   g_return_if_fail(srvc != NULL);
722 
723   place = mwChannel_getServiceData(chan);
724   g_return_if_fail(place != NULL);
725 
726   res = send_JOIN_PLACE(place);
727 }
728 
729 
recv_channelDestroy(struct mwService * service,struct mwChannel * chan,struct mwMsgChannelDestroy * msg)730 static void recv_channelDestroy(struct mwService *service,
731 				struct mwChannel *chan,
732 				struct mwMsgChannelDestroy *msg) {
733   struct mwServicePlace *srvc;
734   struct mwPlace *place;
735 
736   srvc = (struct mwServicePlace *) service;
737   g_return_if_fail(srvc != NULL);
738 
739   place = mwChannel_getServiceData(chan);
740   g_return_if_fail(place != NULL);
741 
742   place_state(place, mwPlace_ERROR);
743 
744   place->channel = NULL;
745 
746   if(srvc->handler && srvc->handler->closed)
747     srvc->handler->closed(place, msg->reason);
748 
749   mwPlace_destroy(place, msg->reason);
750 }
751 
752 
clear(struct mwServicePlace * srvc)753 static void clear(struct mwServicePlace *srvc) {
754 
755   if(srvc->handler && srvc->handler->clear)
756     srvc->handler->clear(srvc);
757 
758   while(srvc->places)
759     place_free(srvc->places->data);
760 }
761 
762 
get_name(struct mwService * srvc)763 static const char *get_name(struct mwService *srvc) {
764   return "Places Conferencing";
765 }
766 
767 
get_desc(struct mwService * srvc)768 static const char *get_desc(struct mwService *srvc) {
769   return "Barebones conferencing via Places";
770 }
771 
772 
773 struct mwServicePlace *
mwServicePlace_new(struct mwSession * session,struct mwPlaceHandler * handler)774 mwServicePlace_new(struct mwSession *session,
775 		   struct mwPlaceHandler *handler) {
776 
777   struct mwServicePlace *srvc_place;
778   struct mwService *srvc;
779 
780   g_return_val_if_fail(session != NULL, NULL);
781   g_return_val_if_fail(handler != NULL, NULL);
782 
783   srvc_place = g_new0(struct mwServicePlace, 1);
784   srvc_place->handler = handler;
785 
786   srvc = MW_SERVICE(srvc_place);
787   mwService_init(srvc, session, mwService_PLACE);
788   srvc->start = NULL;
789   srvc->stop = (mwService_funcStop) stop;
790   srvc->recv_create = NULL;
791   srvc->recv_accept = recv_channelAccept;
792   srvc->recv_destroy = recv_channelDestroy;
793   srvc->recv = recv;
794   srvc->clear = (mwService_funcClear) clear;
795   srvc->get_name = get_name;
796   srvc->get_desc = get_desc;
797 
798   return srvc_place;
799 }
800 
801 
802 struct mwPlaceHandler *
mwServicePlace_getHandler(struct mwServicePlace * srvc)803 mwServicePlace_getHandler(struct mwServicePlace *srvc) {
804   g_return_val_if_fail(srvc != NULL, NULL);
805   return srvc->handler;
806 }
807 
808 
mwServicePlace_getPlaces(struct mwServicePlace * srvc)809 const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc) {
810   g_return_val_if_fail(srvc != NULL, NULL);
811   return srvc->places;
812 }
813 
814 
mwPlace_new(struct mwServicePlace * srvc,const char * name,const char * title)815 struct mwPlace *mwPlace_new(struct mwServicePlace *srvc,
816 			    const char *name, const char *title) {
817   struct mwPlace *place;
818 
819   g_return_val_if_fail(srvc != NULL, NULL);
820 
821   place = g_new0(struct mwPlace, 1);
822   place->service = srvc;
823   place->name = g_strdup(name);
824   place->title = g_strdup(title);
825   place->state = mwPlace_NEW;
826 
827   place->members = g_hash_table_new_full(g_direct_hash, g_direct_equal,
828 					 NULL, (GDestroyNotify) member_free);
829 
830   srvc->places = g_list_prepend(srvc->places, place);
831 
832   return place;
833 }
834 
835 
mwPlace_getService(struct mwPlace * place)836 struct mwServicePlace *mwPlace_getService(struct mwPlace *place) {
837   g_return_val_if_fail(place != NULL, NULL);
838   return place->service;
839 }
840 
841 
place_generate_name(const char * user)842 static char *place_generate_name(const char *user) {
843   guint a, b;
844   char *ret;
845 
846   user = user? user: "meanwhile";
847 
848   srand(clock() + rand());
849   a = ((rand() & 0xff) << 8) | (rand() & 0xff);
850   b = time(NULL);
851 
852   ret = g_strdup_printf("%s(%08x,%04x)", user, b, a);
853   g_debug("generated random conference name: '%s'", ret);
854   return ret;
855 }
856 
857 
mwPlace_getName(struct mwPlace * place)858 const char *mwPlace_getName(struct mwPlace *place) {
859   g_return_val_if_fail(place != NULL, NULL);
860 
861   if(! place->name) {
862     struct mwSession *session;
863     struct mwLoginInfo *li;
864 
865     session = mwService_getSession(MW_SERVICE(place->service));
866     li = mwSession_getLoginInfo(session);
867 
868     place->name = place_generate_name(li? li->user_id: NULL);
869   }
870 
871   return place->name;
872 }
873 
874 
place_generate_title(const char * user)875 static char *place_generate_title(const char *user) {
876   char *ret;
877 
878   user = user? user: "Meanwhile";
879   ret = g_strdup_printf("%s's Conference", user);
880   g_debug("generated conference title: %s", ret);
881 
882   return ret;
883 }
884 
885 
mwPlace_getTitle(struct mwPlace * place)886 const char *mwPlace_getTitle(struct mwPlace *place) {
887   g_return_val_if_fail(place != NULL, NULL);
888 
889   if(! place->title) {
890     struct mwSession *session;
891     struct mwLoginInfo *li;
892 
893     session = mwService_getSession(MW_SERVICE(place->service));
894     li = mwSession_getLoginInfo(session);
895 
896     place->title = place_generate_title(li? li->user_name: NULL);
897   }
898 
899   return place->title;
900 }
901 
902 
mwPlace_open(struct mwPlace * p)903 int mwPlace_open(struct mwPlace *p) {
904   struct mwSession *session;
905   struct mwChannelSet *cs;
906   struct mwChannel *chan;
907   struct mwPutBuffer *b;
908   int ret;
909 
910   g_return_val_if_fail(p != NULL, -1);
911   g_return_val_if_fail(p->service != NULL, -1);
912 
913   session = mwService_getSession(MW_SERVICE(p->service));
914   g_return_val_if_fail(session != NULL, -1);
915 
916   cs = mwSession_getChannels(session);
917   g_return_val_if_fail(cs != NULL, -1);
918 
919   chan = mwChannel_newOutgoing(cs);
920   mwChannel_setService(chan, MW_SERVICE(p->service));
921   mwChannel_setProtoType(chan, PROTOCOL_TYPE);
922   mwChannel_setProtoVer(chan, PROTOCOL_VER);
923 
924   mwChannel_populateSupportedCipherInstances(chan);
925 
926   b = mwPutBuffer_new();
927   mwString_put(b, mwPlace_getName(p));
928   mwString_put(b, mwPlace_getTitle(p));
929   guint32_put(b, 0x00); /* ? */
930 
931   mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
932 
933   ret = mwChannel_create(chan);
934   if(ret) {
935     place_state(p, mwPlace_ERROR);
936   } else {
937     place_state(p, mwPlace_PENDING);
938     p->channel = chan;
939     mwChannel_setServiceData(chan, p, NULL);
940   }
941 
942   return ret;
943 }
944 
945 
mwPlace_destroy(struct mwPlace * p,guint32 code)946 int mwPlace_destroy(struct mwPlace *p, guint32 code) {
947   int ret = 0;
948 
949   place_state(p, mwPlace_CLOSING);
950 
951   if(p->channel) {
952     ret = mwChannel_destroy(p->channel, code, NULL);
953     p->channel = NULL;
954   }
955 
956   place_free(p);
957 
958   return ret;
959 }
960 
961 
mwPlace_getMembers(struct mwPlace * place)962 GList *mwPlace_getMembers(struct mwPlace *place) {
963   GList *l, *ll;
964 
965   g_return_val_if_fail(place != NULL, NULL);
966   g_return_val_if_fail(place->members != NULL, NULL);
967 
968   ll = map_collect_values(place->members);
969   for(l = ll; l; l = l->next) {
970     struct place_member *pm = l->data;
971     l->data = &pm->idb;
972     g_info("collected member %u: %s, %s", pm->place_id,
973 	   NSTR(pm->idb.user), NSTR(pm->idb.community));
974   }
975 
976   return ll;
977 }
978 
979 
mwPlace_sendText(struct mwPlace * place,const char * msg)980 int mwPlace_sendText(struct mwPlace *place, const char *msg) {
981   struct mwOpaque o = {0,0};
982   struct mwPutBuffer *b;
983   int ret;
984 
985   b = mwPutBuffer_new();
986   guint32_put(b, 0x01);  /* probably a message type */
987   mwString_put(b, msg);
988   mwPutBuffer_finalize(&o, b);
989 
990   b = mwPutBuffer_new();
991   guint32_put(b, place->section);
992   mwOpaque_put(b, &o);
993   mwOpaque_clear(&o);
994   mwPutBuffer_finalize(&o, b);
995 
996   ret = mwChannel_send(place->channel, msg_out_MESSAGE, &o);
997   mwOpaque_clear(&o);
998   return ret;
999 }
1000 
1001 
mwPlace_legacyInvite(struct mwPlace * place,struct mwIdBlock * idb,const char * message)1002 int mwPlace_legacyInvite(struct mwPlace *place,
1003 			 struct mwIdBlock *idb,
1004 			 const char *message) {
1005 
1006   struct mwOpaque o = {0,0};
1007   struct mwPutBuffer *b;
1008   int ret;
1009 
1010   b = mwPutBuffer_new();
1011   mwIdBlock_put(b, idb);
1012   mwString_put(b, idb->user);
1013   mwString_put(b, idb->user);
1014   mwString_put(b, message);
1015   gboolean_put(b, FALSE);
1016   mwPutBuffer_finalize(&o, b);
1017 
1018   ret = mwChannel_send(place->channel, msg_out_OLD_INVITE, &o);
1019   mwOpaque_clear(&o);
1020   return ret;
1021 }
1022 
1023 
mwPlace_setAttribute(struct mwPlace * place,guint32 attrib,struct mwOpaque * data)1024 int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib,
1025 			 struct mwOpaque *data) {
1026 
1027   struct mwOpaque o = {0,0};
1028   struct mwPutBuffer *b;
1029   int ret;
1030 
1031   b = mwPutBuffer_new();
1032   guint32_put(b, place->our_id);
1033   guint32_put(b, 0x00);
1034   guint32_put(b, attrib);
1035   mwOpaque_put(b, data);
1036 
1037   ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o);
1038   mwOpaque_clear(&o);
1039   return ret;
1040 }
1041 
1042 
mwPlace_unsetAttribute(struct mwPlace * place,guint32 attrib)1043 int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib) {
1044   struct mwOpaque o = {0,0};
1045   struct mwPutBuffer *b;
1046   int ret;
1047 
1048   b = mwPutBuffer_new();
1049   guint32_put(b, place->our_id);
1050   guint32_put(b, attrib);
1051 
1052   ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o);
1053   mwOpaque_clear(&o);
1054   return ret;
1055 }
1056 
1057 
mwPlace_setClientData(struct mwPlace * place,gpointer data,GDestroyNotify clear)1058 void mwPlace_setClientData(struct mwPlace *place,
1059 			   gpointer data, GDestroyNotify clear) {
1060 
1061   g_return_if_fail(place != NULL);
1062   mw_datum_set(&place->client_data, data, clear);
1063 }
1064 
1065 
mwPlace_getClientData(struct mwPlace * place)1066 gpointer mwPlace_getClientData(struct mwPlace *place) {
1067   g_return_val_if_fail(place != NULL, NULL);
1068   return mw_datum_get(&place->client_data);
1069 }
1070 
1071 
mwPlace_removeClientData(struct mwPlace * place)1072 void mwPlace_removeClientData(struct mwPlace *place) {
1073   g_return_if_fail(place != NULL);
1074   mw_datum_clear(&place->client_data);
1075 }
1076