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, §ion);
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, §ion);
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, §ion);
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, §ion);
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