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); /* SECTION_PART may have been called already */ if(! pm) return 0; if(srvc->handler && srvc->handler->peerParted) srvc->handler->peerParted(place, &pm->idb); REMOVE_MEMBER(place, pm); return ret; }
static void recv_list(struct mwServiceDirectory *srvc, struct mwOpaque *data) { struct mwGetBuffer *b; guint32 request, code, count; gboolean foo_1; guint16 foo_2; b = mwGetBuffer_wrap(data); guint32_get(b, &request); guint32_get(b, &code); guint32_get(b, &count); gboolean_get(b, &foo_1); guint16_get(b, &foo_2); if(foo_1 || foo_2) { mw_mailme_opaque(data, "received strange address book list"); mwGetBuffer_free(b); return; } while(!mwGetBuffer_error(b) && count--) { guint32 id; char *name = NULL; guint32_get(b, &id); mwString_get(b, &name); book_new(srvc, name, id); g_free(name); } }
static void data_recv(struct mwServiceConference *srvc, struct mwConference *conf, struct mwLoginInfo *m, struct mwGetBuffer *b) { /* this function acts a lot like receiving an IM Data message. The data message has a type, a subtype, and an opaque. We only support typing notification though. */ /** @todo it's possible that some clients send text in a data message, as we've seen rarely in the IM service. Have to add support for that here */ guint32 type, subtype; struct mwConferenceHandler *h; guint32_get(b, &type); guint32_get(b, &subtype); if(mwGetBuffer_error(b)) return; /* don't know how to deal with any others yet */ if(type != 0x01) { g_message("unknown data message type (0x%08x, 0x%08x)", type, subtype); return; } h = srvc->handler; if(h->on_typing) { h->on_typing(conf, m, !subtype); } }
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 void WELCOME_recv(struct mwServiceConference *srvc, struct mwConference *conf, struct mwGetBuffer *b) { struct mwConferenceHandler *h; guint16 tmp16; guint32 tmp32; guint32 count; GList *l = NULL; /* re-read name and title */ g_free(conf->name); g_free(conf->title); conf->name = NULL; conf->title = NULL; mwString_get(b, &conf->name); mwString_get(b, &conf->title); /* some numbers we don't care about, then a count of members */ guint16_get(b, &tmp16); guint32_get(b, &tmp32); guint32_get(b, &count); if(mwGetBuffer_error(b)) { g_warning("error parsing welcome message for conference"); mwConference_destroy(conf, ERR_FAILURE, NULL); return; } while(count--) { guint16 member_id; struct mwLoginInfo *member = g_new0(struct mwLoginInfo, 1); guint16_get(b, &member_id); mwLoginInfo_get(b, member); if(mwGetBuffer_error(b)) { login_free(member); break; } MEMBER_ADD(conf, member_id, member); l = g_list_append(l, member); } conf_state(conf, mwConference_OPEN); h = srvc->handler; if(h->conf_opened) h->conf_opened(conf, l); /* get rid of the GList, but not its contents */ g_list_free(l); }
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 void recv_channelCreate(struct mwServiceFileTransfer *srvc, struct mwChannel *chan, struct mwMsgChannelCreate *msg) { struct mwFileTransferHandler *handler; struct mwGetBuffer *b; char *fnm, *txt; guint32 size, junk; gboolean b_err; g_return_if_fail(srvc->handler != NULL); handler = srvc->handler; b = mwGetBuffer_wrap(&msg->addtl); guint32_get(b, &junk); /* unknown */ mwString_get(b, &fnm); /* offered filename */ mwString_get(b, &txt); /* offering message */ guint32_get(b, &size); /* size of offered file */ /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/ft_fix.diff /* guint32_get(b, &junk); */ /* unknown */ /// Miranda NG adaptation - end /* and we just skip an unknown guint16 at the end */ b_err = mwGetBuffer_error(b); mwGetBuffer_free(b); if(b_err) { g_warning("bad/malformed addtl in File Transfer service"); mwChannel_destroy(chan, ERR_FAILURE, NULL); } else { struct mwIdBlock idb; struct mwFileTransfer *ft; login_into_id(&idb, mwChannel_getUser(chan)); ft = mwFileTransfer_new(srvc, &idb, txt, fnm, size); ft->channel = chan; ft_state(ft, mwFileTransfer_PENDING); mwChannel_setServiceData(chan, ft, NULL); if(handler->ft_offered) handler->ft_offered(ft); } g_free(fnm); g_free(txt); }
static void HANDSHAKE_get(struct mwGetBuffer *b, struct mwMsgHandshake *msg) { if(mwGetBuffer_error(b)) return; guint16_get(b, &msg->major); guint16_get(b, &msg->minor); guint32_get(b, &msg->head.channel); guint32_get(b, &msg->srvrcalc_addr); guint16_get(b, &msg->login_type); guint32_get(b, &msg->loclcalc_addr); if(msg->major >= 0x001e && msg->minor >= 0x001d) { guint16_get(b, &msg->unknown_a); guint32_get(b, &msg->unknown_b); mwString_get(b, &msg->local_host); } }
static int recv_SECTION_PART(struct mwPlace *place, struct mwGetBuffer *b) { /* look up user in place remove user from place trigger event */ struct mwServicePlace *srvc; guint32 pm_id; struct place_member *pm; srvc = place->service; guint32_get(b, &pm_id); pm = GET_MEMBER(place, pm_id); /* SECTION_PEER_PART may have been called already */ if(! pm) return 0; if(srvc->handler && srvc->handler->peerParted) srvc->handler->peerParted(place, &pm->idb); REMOVE_MEMBER(place, pm); return 0; }
static void recv_channelCreate(struct mwService *srvc, struct mwChannel *chan, struct mwMsgChannelCreate *msg) { /* - this is how we really receive invitations - create a conference and associate it with the channel - obtain the invite data from the msg addtl info - mark the conference as INVITED - trigger the got_invite event */ struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc; struct mwConference *conf; struct mwGetBuffer *b; char *invite = NULL; guint tmp; conf = conf_new(srvc_conf); conf->channel = chan; b = mwGetBuffer_wrap(&msg->addtl); guint32_get(b, &tmp); mwString_get(b, &conf->name); mwString_get(b, &conf->title); guint32_get(b, &tmp); mwLoginInfo_get(b, &conf->owner); guint32_get(b, &tmp); mwString_get(b, &invite); if(mwGetBuffer_error(b)) { g_warning("failure parsing addtl for conference invite"); mwConference_destroy(conf, ERR_FAILURE, NULL); } else { struct mwConferenceHandler *h = srvc_conf->handler; conf_state(conf, mwConference_INVITED); if(h->on_invited) h->on_invited(conf, &conf->owner, invite); } mwGetBuffer_free(b); g_free(invite); }
static void HANDSHAKE_ACK_get(struct mwGetBuffer *b, struct mwMsgHandshakeAck *msg) { if(mwGetBuffer_error(b)) return; guint16_get(b, &msg->major); guint16_get(b, &msg->minor); guint32_get(b, &msg->srvrcalc_addr); /** @todo: get a better handle on what versions support what parts of this message. eg: minor version 0x0018 doesn't send the following */ if(msg->major >= 0x1e && msg->minor > 0x18) { guint32_get(b, &msg->magic); mwOpaque_get(b, &msg->data); } }
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 void request_get(struct mwGetBuffer *b, struct mwStorageReq *req) { guint32 id, count, junk; if(mwGetBuffer_error(b)) return; guint32_get(b, &id); guint32_get(b, &req->result_code); if(req->action == action_loaded) { guint32_get(b, &count); if(count > 0) { guint32_get(b, &junk); guint32_get(b, &req->item->key); mwOpaque_clear(&req->item->data); mwOpaque_get(b, &req->item->data); } } }
static void mwMessageHead_get(struct mwGetBuffer *b, struct mwMessage *msg) { if(mwGetBuffer_error(b)) return; guint16_get(b, &msg->type); guint16_get(b, &msg->options); guint32_get(b, &msg->channel); if(msg->options & mwMessageOption_HAS_ATTRIBS) mwOpaque_get(b, &msg->attribs); }
static void MESSAGE_recv(struct mwServiceConference *srvc, struct mwConference *conf, struct mwGetBuffer *b) { /* - look up who send the message by their id - trigger the event */ guint16 id; guint32 type; struct mwLoginInfo *m; /* an empty buffer isn't an error, just ignored */ if(! mwGetBuffer_remaining(b)) return; guint16_get(b, &id); guint32_get(b, &type); /* reuse type variable */ guint32_get(b, &type); if(mwGetBuffer_error(b)) return; m = MEMBER_FIND(conf, id); if(! m) { g_warning("received message type 0x%04x from" " unknown conference member %u", type, id); return; } switch(type) { case 0x01: /* type is text */ text_recv(srvc, conf, m, b); break; case 0x02: /* type is data */ data_recv(srvc, conf, m, b); break; default: g_warning("unknown message type 0x%4x received in conference", type); } }
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; /* no messages before becoming fully open, please */ g_return_val_if_fail(place->state == mwPlace_OPEN, -1); /* regarding unkn_a and unkn_b: they're probably a section indicator and a message count, I'm just not sure which is which. Until this implementation supports place sections in the API, it really doesn't matter. */ 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); /* actually an opaque length */ 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 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) { /* this is a place info rather than member info */ 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 void enc_offer_get(struct mwGetBuffer *b, struct mwEncryptOffer *enc) { guint32 skip; if(mwGetBuffer_error(b)) return; guint16_get(b, &enc->mode); guint32_get(b, &skip); if(skip >= 7) { guint32 count; guint32_get(b, &count); while(count-- && (! mwGetBuffer_error(b))) { struct mwEncryptItem *ei = g_new0(struct mwEncryptItem, 1); mwEncryptItem_get(b, ei); enc->items = g_list_append(enc->items, ei); } guint16_get(b, &enc->extra); gboolean_get(b, &enc->flag); }
guint32 mwStorageUnit_asInteger(struct mwStorageUnit *item, guint32 val) { struct mwGetBuffer *b; guint32 v; g_return_val_if_fail(item != NULL, val); b = mwGetBuffer_wrap(&item->data); guint32_get(b, &v); if(! mwGetBuffer_error(b)) val = v; mwGetBuffer_free(b); return val; }
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_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; }