| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <glib.h> |
| #include <glib/ghash.h> |
| #include <glib/glist.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include "mw_channel.h" |
| #include "mw_common.h" |
| #include "mw_debug.h" |
| #include "mw_error.h" |
| #include "mw_message.h" |
| #include "mw_service.h" |
| #include "mw_session.h" |
| #include "mw_srvc_place.h" |
| #include "mw_util.h" |
| |
| |
| #define PROTOCOL_TYPE 0x00 |
| #define PROTOCOL_VER 0x05 |
| |
| |
| enum incoming_msg { |
| msg_in_JOIN_RESPONSE = 0x0000, |
| msg_in_INFO = 0x0002, |
| msg_in_MESSAGE = 0x0004, |
| msg_in_SECTION = 0x0014, |
| msg_in_UNKNOWNa = 0x0015, |
| }; |
| |
| |
| enum in_section_subtype { |
| msg_in_SECTION_LIST = 0x0000, |
| msg_in_SECTION_PEER = 0x0001, |
| msg_in_SECTION_PART = 0x0003, |
| }; |
| |
| |
| enum in_section_peer_subtype { |
| msg_in_SECTION_PEER_JOIN = 0x0000, |
| msg_in_SECTION_PEER_PART = 0x0001, |
| msg_in_SECTION_PEER_CLEAR_ATTR = 0x0003, |
| msg_in_SECTION_PEER_SET_ATTR = 0x0004, |
| }; |
| |
| |
| enum outgoing_msg { |
| msg_out_JOIN_PLACE = 0x0000, |
| msg_out_PEER_INFO = 0x0002, |
| msg_out_MESSAGE = 0x0003, |
| msg_out_OLD_INVITE = 0x0005, |
| msg_out_SET_ATTR = 0x000a, |
| msg_out_CLEAR_ATTR = 0x000b, |
| msg_out_SECTION = 0x0014, |
| msg_out_UNKNOWNb = 0x001e, |
| }; |
| |
| |
| enum out_section_subtype { |
| msg_out_SECTION_LIST = 0x0002, |
| msg_out_SECTION_PART = 0x0003, |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct mwServicePlace { |
| struct mwService service; |
| struct mwPlaceHandler *handler; |
| GList *places; |
| }; |
| |
| |
| enum mwPlaceState { |
| mwPlace_NEW, |
| mwPlace_PENDING, |
| mwPlace_JOINING, |
| mwPlace_JOINED, |
| mwPlace_OPEN, |
| mwPlace_CLOSING, |
| mwPlace_ERROR, |
| mwPlace_UNKNOWN, |
| }; |
| |
| |
| struct mwPlace { |
| struct mwServicePlace *service; |
| |
| enum mwPlaceState state; |
| struct mwChannel *channel; |
| |
| char *name; |
| char *title; |
| GHashTable *members; |
| guint32 our_id; |
| guint32 section; |
| |
| guint32 requests; |
| |
| struct mw_datum client_data; |
| }; |
| |
| |
| struct place_member { |
| guint32 place_id; |
| guint16 member_type; |
| struct mwIdBlock idb; |
| char *login_id; |
| char *name; |
| guint16 login_type; |
| guint32 unknown_a; |
| guint32 unknown_b; |
| }; |
| |
| |
| #define GET_MEMBER(place, id) \ |
| (g_hash_table_lookup(place->members, GUINT_TO_POINTER(id))) |
| |
| |
| #define PUT_MEMBER(place, member) \ |
| (g_hash_table_insert(place->members, \ |
| GUINT_TO_POINTER(member->place_id), member)) |
| |
| |
| #define REMOVE_MEMBER_ID(place, id) \ |
| (g_hash_table_remove(place->members, GUINT_TO_POINTER(id))) |
| |
| |
| #define REMOVE_MEMBER(place, member) \ |
| REMOVE_MEMBER_ID(place, member->place_id) |
| |
| |
| static void member_free(struct place_member *p) { |
| mwIdBlock_clear(&p->idb); |
| g_free(p->login_id); |
| g_free(p->name); |
| g_free(p); |
| } |
| |
| |
| __attribute__((used)) |
| static const struct mwLoginInfo * |
| member_as_login_info(struct place_member *p) { |
| static struct mwLoginInfo li; |
| |
| li.login_id = p->login_id; |
| li.type = p->login_type; |
| li.user_id = p->idb.user; |
| li.user_name = p->name; |
| li.community = p->idb.community; |
| li.full = FALSE; |
| |
| return &li; |
| } |
| |
| |
| static const char *place_state_str(enum mwPlaceState s) { |
| switch(s) { |
| case mwPlace_NEW: return "new"; |
| case mwPlace_PENDING: return "pending"; |
| case mwPlace_JOINING: return "joining"; |
| case mwPlace_JOINED: return "joined"; |
| case mwPlace_OPEN: return "open"; |
| case mwPlace_CLOSING: return "closing"; |
| case mwPlace_ERROR: return "error"; |
| |
| case mwPlace_UNKNOWN: |
| default: return "UNKNOWN"; |
| } |
| } |
| |
| |
| static void place_state(struct mwPlace *place, enum mwPlaceState s) { |
| g_return_if_fail(place != NULL); |
| |
| if(place->state == s) return; |
| |
| place->state = s; |
| g_message("place %s state: %s", NSTR(place->name), place_state_str(s)); |
| } |
| |
| |
| static void place_free(struct mwPlace *place) { |
| struct mwServicePlace *srvc; |
| |
| if(! place) return; |
| |
| srvc = place->service; |
| g_return_if_fail(srvc != NULL); |
| |
| srvc->places = g_list_remove_all(srvc->places, place); |
| |
| mw_datum_clear(&place->client_data); |
| |
| g_hash_table_destroy(place->members); |
| |
| g_free(place->name); |
| g_free(place->title); |
| g_free(place); |
| } |
| |
| |
| static int recv_JOIN_RESPONSE(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| |
| int ret = 0; |
| guint32 our_id, section; |
| |
| guint32_get(b, &our_id); |
| guint32_get(b, §ion); |
| |
| place->our_id = our_id; |
| place->section = section; |
| |
| return ret; |
| } |
| |
| |
| static int send_SECTION_LIST(struct mwPlace *place, guint32 section) { |
| int ret = 0; |
| struct mwOpaque o = {0, 0}; |
| struct mwPutBuffer *b; |
| |
| b = mwPutBuffer_new(); |
| guint16_put(b, msg_out_SECTION_LIST); |
| guint32_put(b, section); |
| gboolean_put(b, FALSE); |
| guint32_put(b, ++place->requests); |
| mwPutBuffer_finalize(&o, b); |
| |
| ret = mwChannel_send(place->channel, msg_out_SECTION, &o); |
| mwOpaque_clear(&o); |
| |
| return ret; |
| } |
| |
| |
| static int recv_INFO(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| |
| int ret = 0; |
| guint32 skip = 0; |
| guint32 section = 0; |
| |
| guint32_get(b, &skip); |
| guint32_get(b, §ion); |
| mwGetBuffer_advance(b, skip); |
| |
| if(! section) { |
| |
| if(place->title) g_free(place->title); |
| mwGetBuffer_advance(b, 2); |
| mwString_get(b, &place->title); |
| |
| place_state(place, mwPlace_JOINED); |
| ret = send_SECTION_LIST(place, place->section); |
| } |
| |
| return ret; |
| } |
| |
| |
| static int recv_MESSAGE(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| |
| struct mwServicePlace *srvc; |
| guint32 pm_id; |
| guint32 unkn_a, unkn_b, ign; |
| struct place_member *pm; |
| char *msg = NULL; |
| int ret = 0; |
| |
| srvc = place->service; |
| |
| |
| g_return_val_if_fail(place->state == mwPlace_OPEN, -1); |
| |
| |
| |
| |
| |
| |
| |
| guint32_get(b, &pm_id); |
| pm = GET_MEMBER(place, pm_id); |
| g_return_val_if_fail(pm != NULL, -1); |
| |
| guint32_get(b, &unkn_a); |
| guint32_get(b, &ign); |
| |
| if(! ign) return ret; |
| |
| guint32_get(b, &unkn_b); |
| mwString_get(b, &msg); |
| |
| if(srvc->handler && srvc->handler->message) |
| srvc->handler->message(place, &pm->idb, msg); |
| |
| g_free(msg); |
| |
| return ret; |
| } |
| |
| |
| static void place_opened(struct mwPlace *place) { |
| struct mwServicePlace *srvc; |
| |
| place_state(place, mwPlace_OPEN); |
| |
| srvc = place->service; |
| if(srvc->handler && srvc->handler->opened) |
| srvc->handler->opened(place); |
| } |
| |
| |
| static int recv_SECTION_PEER_JOIN(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| struct mwServicePlace *srvc; |
| struct place_member *pm; |
| guint32 section; |
| int ret = 0; |
| |
| srvc = place->service; |
| |
| guint32_get(b, §ion); |
| if(! section) { |
| g_info("SECTION_PEER_JOIN with section 0x00"); |
| return 0; |
| } |
| |
| mwGetBuffer_advance(b, 4); |
| |
| pm = g_new0(struct place_member, 1); |
| guint32_get(b, &pm->place_id); |
| guint16_get(b, &pm->member_type); |
| mwIdBlock_get(b, &pm->idb); |
| mwString_get(b, &pm->login_id); |
| mwString_get(b, &pm->name); |
| guint16_get(b, &pm->login_type); |
| guint32_get(b, &pm->unknown_a); |
| guint32_get(b, &pm->unknown_b); |
| |
| PUT_MEMBER(place, pm); |
| if(srvc->handler && srvc->handler->peerJoined) |
| srvc->handler->peerJoined(place, &pm->idb); |
| |
| if(pm->place_id == place->our_id) |
| place_opened(place); |
| |
| return ret; |
| } |
| |
| |
| static int recv_SECTION_PEER_PART(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| struct mwServicePlace *srvc; |
| int ret = 0; |
| guint32 section, id; |
| struct place_member *pm; |
| |
| srvc = place->service; |
| |
| guint32_get(b, §ion); |
| g_return_val_if_fail(section == place->section, 0); |
| |
| guint32_get(b, &id); |
| pm = GET_MEMBER(place, id); |
| |
| |
| if(! pm) return 0; |
| |
| if(srvc->handler && srvc->handler->peerParted) |
| srvc->handler->peerParted(place, &pm->idb); |
| |
| REMOVE_MEMBER(place, pm); |
| |
| return ret; |
| } |
| |
| |
| static int recv_SECTION_PEER_CLEAR_ATTR(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| struct mwServicePlace *srvc; |
| int ret = 0; |
| guint32 id, attr; |
| struct place_member *pm; |
| |
| srvc = place->service; |
| |
| guint32_get(b, &id); |
| guint32_get(b, &attr); |
| |
| pm = GET_MEMBER(place, id); |
| g_return_val_if_fail(pm != NULL, -1); |
| |
| if(srvc->handler && srvc->handler->peerUnsetAttribute) |
| srvc->handler->peerUnsetAttribute(place, &pm->idb, attr); |
| |
| return ret; |
| } |
| |
| |
| static int recv_SECTION_PEER_SET_ATTR(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| struct mwServicePlace *srvc; |
| int ret = 0; |
| guint32 id, attr; |
| struct mwOpaque o = {0,0}; |
| struct place_member *pm; |
| |
| srvc = place->service; |
| |
| guint32_get(b, &id); |
| mwGetBuffer_advance(b, 4); |
| mwOpaque_get(b, &o); |
| mwGetBuffer_advance(b, 4); |
| guint32_get(b, &attr); |
| |
| pm = GET_MEMBER(place, id); |
| g_return_val_if_fail(pm != NULL, -1); |
| |
| if(srvc->handler && srvc->handler->peerSetAttribute) |
| srvc->handler->peerSetAttribute(place, &pm->idb, attr, &o); |
| |
| mwOpaque_clear(&o); |
| |
| return ret; |
| } |
| |
| |
| static int recv_SECTION_PEER(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| guint16 subtype; |
| int res; |
| |
| guint16_get(b, &subtype); |
| |
| g_return_val_if_fail(! mwGetBuffer_error(b), -1); |
| |
| switch(subtype) { |
| case msg_in_SECTION_PEER_JOIN: |
| res = recv_SECTION_PEER_JOIN(place, b); |
| break; |
| |
| case msg_in_SECTION_PEER_PART: |
| res = recv_SECTION_PEER_PART(place, b); |
| break; |
| |
| case msg_in_SECTION_PEER_CLEAR_ATTR: |
| res = recv_SECTION_PEER_CLEAR_ATTR(place, b); |
| break; |
| |
| case msg_in_SECTION_PEER_SET_ATTR: |
| res = recv_SECTION_PEER_SET_ATTR(place, b); |
| break; |
| |
| default: |
| res = -1; |
| } |
| |
| return res; |
| } |
| |
| |
| static int recv_SECTION_LIST(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| int ret = 0; |
| guint32 sec, count; |
| |
| mwGetBuffer_advance(b, 4); |
| guint32_get(b, &sec); |
| |
| g_return_val_if_fail(sec == place->section, -1); |
| |
| mwGetBuffer_advance(b, 8); |
| guint32_get(b, &count); |
| mwGetBuffer_advance(b, 8); |
| |
| while(count--) { |
| struct place_member *m; |
| |
| m = g_new0(struct place_member, 1); |
| mwGetBuffer_advance(b, 4); |
| guint32_get(b, &m->place_id); |
| guint16_get(b, &m->member_type); |
| mwIdBlock_get(b, &m->idb); |
| mwString_get(b, &m->login_id); |
| mwString_get(b, &m->name); |
| guint16_get(b, &m->login_type); |
| guint32_get(b, &m->unknown_a); |
| guint32_get(b, &m->unknown_b); |
| |
| PUT_MEMBER(place, m); |
| } |
| |
| if(place->state != mwPlace_OPEN) |
| place_opened(place); |
| |
| return ret; |
| } |
| |
| |
| static int recv_SECTION_PART(struct mwPlace *place, |
| struct mwGetBuffer *b) { |
| |
| |
| |
| |
| struct mwServicePlace *srvc; |
| guint32 pm_id; |
| struct place_member *pm; |
| |
| srvc = place->service; |
| |
| guint32_get(b, &pm_id); |
| pm = GET_MEMBER(place, pm_id); |
| |
| |
| if(! pm) return 0; |
| |
| if(srvc->handler && srvc->handler->peerParted) |
| srvc->handler->peerParted(place, &pm->idb); |
| |
| REMOVE_MEMBER(place, pm); |
| |
| return 0; |
| } |
| |
| |
| static int recv_SECTION(struct mwPlace *place, struct mwGetBuffer *b) { |
| guint16 subtype; |
| int res; |
| |
| guint16_get(b, &subtype); |
| |
| g_return_val_if_fail(! mwGetBuffer_error(b), -1); |
| |
| switch(subtype) { |
| case msg_in_SECTION_LIST: |
| res = recv_SECTION_LIST(place, b); |
| break; |
| |
| case msg_in_SECTION_PEER: |
| res = recv_SECTION_PEER(place, b); |
| break; |
| |
| case msg_in_SECTION_PART: |
| res = recv_SECTION_PART(place, b); |
| break; |
| |
| default: |
| res = -1; |
| } |
| |
| return res; |
| } |
| |
| |
| static int recv_UNKNOWNa(struct mwPlace *place, struct mwGetBuffer *b) { |
| int res = 0; |
| |
| if(place->state == mwPlace_JOINING) { |
| ; |
| |
| |
| |
| } else if(place->state == mwPlace_JOINED) { |
| ; |
| |
| |
| } |
| |
| return res; |
| } |
| |
| |
| static void recv(struct mwService *service, struct mwChannel *chan, |
| guint16 type, struct mwOpaque *data) { |
| |
| struct mwPlace *place; |
| struct mwGetBuffer *b; |
| int res = 0; |
| |
| place = mwChannel_getServiceData(chan); |
| g_return_if_fail(place != NULL); |
| |
| b = mwGetBuffer_wrap(data); |
| switch(type) { |
| case msg_in_JOIN_RESPONSE: |
| res = recv_JOIN_RESPONSE(place, b); |
| break; |
| |
| case msg_in_INFO: |
| res = recv_INFO(place, b); |
| break; |
| |
| case msg_in_MESSAGE: |
| res = recv_MESSAGE(place, b); |
| break; |
| |
| case msg_in_SECTION: |
| res = recv_SECTION(place, b); |
| break; |
| |
| case msg_in_UNKNOWNa: |
| res = recv_UNKNOWNa(place, b); |
| break; |
| |
| default: |
| mw_mailme_opaque(data, "Received unknown message type 0x%x on place %s", |
| type, NSTR(place->name)); |
| } |
| |
| if(res) { |
| mw_mailme_opaque(data, "Troubling parsing message type 0x0%x on place %s", |
| type, NSTR(place->name)); |
| } |
| |
| mwGetBuffer_free(b); |
| } |
| |
| |
| static void stop(struct mwServicePlace *srvc) { |
| while(srvc->places) |
| mwPlace_destroy(srvc->places->data, ERR_SUCCESS); |
| |
| mwService_stopped(MW_SERVICE(srvc)); |
| } |
| |
| |
| static int send_JOIN_PLACE(struct mwPlace *place) { |
| struct mwOpaque o = {0, 0}; |
| struct mwPutBuffer *b; |
| int ret; |
| |
| b = mwPutBuffer_new(); |
| gboolean_put(b, FALSE); |
| guint16_put(b, 0x01); |
| guint16_put(b, 0x02); |
| guint16_put(b, 0x01); |
| |
| mwPutBuffer_finalize(&o, b); |
| |
| ret = mwChannel_send(place->channel, msg_out_JOIN_PLACE, &o); |
| |
| mwOpaque_clear(&o); |
| |
| if(ret) { |
| place_state(place, mwPlace_ERROR); |
| } else { |
| place_state(place, mwPlace_JOINING); |
| } |
| |
| return ret; |
| } |
| |
| |
| static void recv_channelAccept(struct mwService *service, |
| struct mwChannel *chan, |
| struct mwMsgChannelAccept *msg) { |
| struct mwServicePlace *srvc; |
| struct mwPlace *place; |
| int res; |
| |
| srvc = (struct mwServicePlace *) service; |
| g_return_if_fail(srvc != NULL); |
| |
| place = mwChannel_getServiceData(chan); |
| g_return_if_fail(place != NULL); |
| |
| res = send_JOIN_PLACE(place); |
| } |
| |
| |
| static void recv_channelDestroy(struct mwService *service, |
| struct mwChannel *chan, |
| struct mwMsgChannelDestroy *msg) { |
| struct mwServicePlace *srvc; |
| struct mwPlace *place; |
| |
| srvc = (struct mwServicePlace *) service; |
| g_return_if_fail(srvc != NULL); |
| |
| place = mwChannel_getServiceData(chan); |
| g_return_if_fail(place != NULL); |
| |
| place_state(place, mwPlace_ERROR); |
| |
| place->channel = NULL; |
| |
| if(srvc->handler && srvc->handler->closed) |
| srvc->handler->closed(place, msg->reason); |
| |
| mwPlace_destroy(place, msg->reason); |
| } |
| |
| |
| static void clear(struct mwServicePlace *srvc) { |
| |
| if(srvc->handler && srvc->handler->clear) |
| srvc->handler->clear(srvc); |
| |
| while(srvc->places) |
| place_free(srvc->places->data); |
| } |
| |
| |
| static const char *get_name(struct mwService *srvc) { |
| return "Places Conferencing"; |
| } |
| |
| |
| static const char *get_desc(struct mwService *srvc) { |
| return "Barebones conferencing via Places"; |
| } |
| |
| |
| struct mwServicePlace * |
| mwServicePlace_new(struct mwSession *session, |
| struct mwPlaceHandler *handler) { |
| |
| struct mwServicePlace *srvc_place; |
| struct mwService *srvc; |
| |
| g_return_val_if_fail(session != NULL, NULL); |
| g_return_val_if_fail(handler != NULL, NULL); |
| |
| srvc_place = g_new0(struct mwServicePlace, 1); |
| srvc_place->handler = handler; |
| |
| srvc = MW_SERVICE(srvc_place); |
| mwService_init(srvc, session, mwService_PLACE); |
| srvc->start = NULL; |
| srvc->stop = (mwService_funcStop) stop; |
| srvc->recv_create = NULL; |
| srvc->recv_accept = recv_channelAccept; |
| srvc->recv_destroy = recv_channelDestroy; |
| srvc->recv = recv; |
| srvc->clear = (mwService_funcClear) clear; |
| srvc->get_name = get_name; |
| srvc->get_desc = get_desc; |
| |
| return srvc_place; |
| } |
| |
| |
| struct mwPlaceHandler * |
| mwServicePlace_getHandler(struct mwServicePlace *srvc) { |
| g_return_val_if_fail(srvc != NULL, NULL); |
| return srvc->handler; |
| } |
| |
| |
| const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc) { |
| g_return_val_if_fail(srvc != NULL, NULL); |
| return srvc->places; |
| } |
| |
| |
| struct mwPlace *mwPlace_new(struct mwServicePlace *srvc, |
| const char *name, const char *title) { |
| struct mwPlace *place; |
| |
| g_return_val_if_fail(srvc != NULL, NULL); |
| |
| place = g_new0(struct mwPlace, 1); |
| place->service = srvc; |
| place->name = g_strdup(name); |
| place->title = g_strdup(title); |
| place->state = mwPlace_NEW; |
| |
| place->members = g_hash_table_new_full(g_direct_hash, g_direct_equal, |
| NULL, (GDestroyNotify) member_free); |
| |
| srvc->places = g_list_prepend(srvc->places, place); |
| |
| return place; |
| } |
| |
| |
| struct mwServicePlace *mwPlace_getService(struct mwPlace *place) { |
| g_return_val_if_fail(place != NULL, NULL); |
| return place->service; |
| } |
| |
| |
| static char *place_generate_name(const char *user) { |
| guint a, b; |
| char *ret; |
| |
| user = user? user: "meanwhile"; |
| |
| srand(clock() + rand()); |
| a = ((rand() & 0xff) << 8) | (rand() & 0xff); |
| b = time(NULL); |
| |
| ret = g_strdup_printf("%s(%08x,%04x)", user, b, a); |
| g_debug("generated random conference name: '%s'", ret); |
| return ret; |
| } |
| |
| |
| const char *mwPlace_getName(struct mwPlace *place) { |
| g_return_val_if_fail(place != NULL, NULL); |
| |
| if(! place->name) { |
| struct mwSession *session; |
| struct mwLoginInfo *li; |
| |
| session = mwService_getSession(MW_SERVICE(place->service)); |
| li = mwSession_getLoginInfo(session); |
| |
| place->name = place_generate_name(li? li->user_id: NULL); |
| } |
| |
| return place->name; |
| } |
| |
| |
| static char *place_generate_title(const char *user) { |
| char *ret; |
| |
| user = user? user: "Meanwhile"; |
| ret = g_strdup_printf("%s's Conference", user); |
| g_debug("generated conference title: %s", ret); |
| |
| return ret; |
| } |
| |
| |
| const char *mwPlace_getTitle(struct mwPlace *place) { |
| g_return_val_if_fail(place != NULL, NULL); |
| |
| if(! place->title) { |
| struct mwSession *session; |
| struct mwLoginInfo *li; |
| |
| session = mwService_getSession(MW_SERVICE(place->service)); |
| li = mwSession_getLoginInfo(session); |
| |
| place->title = place_generate_title(li? li->user_name: NULL); |
| } |
| |
| return place->title; |
| } |
| |
| |
| int mwPlace_open(struct mwPlace *p) { |
| struct mwSession *session; |
| struct mwChannelSet *cs; |
| struct mwChannel *chan; |
| struct mwPutBuffer *b; |
| int ret; |
| |
| g_return_val_if_fail(p != NULL, -1); |
| g_return_val_if_fail(p->service != NULL, -1); |
| |
| session = mwService_getSession(MW_SERVICE(p->service)); |
| g_return_val_if_fail(session != NULL, -1); |
| |
| cs = mwSession_getChannels(session); |
| g_return_val_if_fail(cs != NULL, -1); |
| |
| chan = mwChannel_newOutgoing(cs); |
| mwChannel_setService(chan, MW_SERVICE(p->service)); |
| mwChannel_setProtoType(chan, PROTOCOL_TYPE); |
| mwChannel_setProtoVer(chan, PROTOCOL_VER); |
| |
| mwChannel_populateSupportedCipherInstances(chan); |
| |
| b = mwPutBuffer_new(); |
| mwString_put(b, mwPlace_getName(p)); |
| mwString_put(b, mwPlace_getTitle(p)); |
| guint32_put(b, 0x00); |
| |
| mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); |
| |
| ret = mwChannel_create(chan); |
| if(ret) { |
| place_state(p, mwPlace_ERROR); |
| } else { |
| place_state(p, mwPlace_PENDING); |
| p->channel = chan; |
| mwChannel_setServiceData(chan, p, NULL); |
| } |
| |
| return ret; |
| } |
| |
| |
| int mwPlace_destroy(struct mwPlace *p, guint32 code) { |
| int ret = 0; |
| |
| place_state(p, mwPlace_CLOSING); |
| |
| if(p->channel) { |
| ret = mwChannel_destroy(p->channel, code, NULL); |
| p->channel = NULL; |
| } |
| |
| place_free(p); |
| |
| return ret; |
| } |
| |
| |
| GList *mwPlace_getMembers(struct mwPlace *place) { |
| GList *l, *ll; |
| |
| g_return_val_if_fail(place != NULL, NULL); |
| g_return_val_if_fail(place->members != NULL, NULL); |
| |
| ll = map_collect_values(place->members); |
| for(l = ll; l; l = l->next) { |
| struct place_member *pm = l->data; |
| l->data = &pm->idb; |
| g_info("collected member %u: %s, %s", pm->place_id, |
| NSTR(pm->idb.user), NSTR(pm->idb.community)); |
| } |
| |
| return ll; |
| } |
| |
| |
| int mwPlace_sendText(struct mwPlace *place, const char *msg) { |
| struct mwOpaque o = {0,0}; |
| struct mwPutBuffer *b; |
| int ret; |
| |
| b = mwPutBuffer_new(); |
| guint32_put(b, 0x01); |
| mwString_put(b, msg); |
| mwPutBuffer_finalize(&o, b); |
| |
| b = mwPutBuffer_new(); |
| guint32_put(b, place->section); |
| mwOpaque_put(b, &o); |
| mwOpaque_clear(&o); |
| mwPutBuffer_finalize(&o, b); |
| |
| ret = mwChannel_send(place->channel, msg_out_MESSAGE, &o); |
| mwOpaque_clear(&o); |
| return ret; |
| } |
| |
| |
| int mwPlace_legacyInvite(struct mwPlace *place, |
| struct mwIdBlock *idb, |
| const char *message) { |
| |
| struct mwOpaque o = {0,0}; |
| struct mwPutBuffer *b; |
| int ret; |
| |
| b = mwPutBuffer_new(); |
| mwIdBlock_put(b, idb); |
| mwString_put(b, idb->user); |
| mwString_put(b, idb->user); |
| mwString_put(b, message); |
| gboolean_put(b, FALSE); |
| mwPutBuffer_finalize(&o, b); |
| |
| ret = mwChannel_send(place->channel, msg_out_OLD_INVITE, &o); |
| mwOpaque_clear(&o); |
| return ret; |
| } |
| |
| |
| int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib, |
| struct mwOpaque *data) { |
| |
| struct mwOpaque o = {0,0}; |
| struct mwPutBuffer *b; |
| int ret; |
| |
| b = mwPutBuffer_new(); |
| guint32_put(b, place->our_id); |
| guint32_put(b, 0x00); |
| guint32_put(b, attrib); |
| mwOpaque_put(b, data); |
| |
| ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o); |
| mwOpaque_clear(&o); |
| return ret; |
| } |
| |
| |
| int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib) { |
| struct mwOpaque o = {0,0}; |
| struct mwPutBuffer *b; |
| int ret; |
| |
| b = mwPutBuffer_new(); |
| guint32_put(b, place->our_id); |
| guint32_put(b, attrib); |
| |
| ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o); |
| mwOpaque_clear(&o); |
| return ret; |
| } |
| |
| |
| void mwPlace_setClientData(struct mwPlace *place, |
| gpointer data, GDestroyNotify clear) { |
| |
| g_return_if_fail(place != NULL); |
| mw_datum_set(&place->client_data, data, clear); |
| } |
| |
| |
| gpointer mwPlace_getClientData(struct mwPlace *place) { |
| g_return_val_if_fail(place != NULL, NULL); |
| return mw_datum_get(&place->client_data); |
| } |
| |
| |
| void mwPlace_removeClientData(struct mwPlace *place) { |
| g_return_if_fail(place != NULL); |
| mw_datum_clear(&place->client_data); |
| } |