📄 family_oservice.c
字号:
/* * Purple's oscar protocol plugin * This file is the legal property of its developers. * Please see the AUTHORS file distributed alongside this file. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//* * Family 0x0001 - This is a very special group. All connections support * this group, as it does some particularly good things (like rate limiting). */#include "oscar.h"#include "cipher.h"/* Subtype 0x0002 - Client Online */voidaim_clientready(OscarData *od, FlapConnection *conn){ FlapFrame *frame; aim_snacid_t snacid; GSList *cur; frame = flap_frame_new(od, 0x02, 1152); snacid = aim_cachesnac(od, 0x0001, 0x0002, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0001, 0x0002, 0x0000, snacid); /* * Send only the tool versions that the server cares about (that it * marked as supporting in the server ready SNAC). */ for (cur = conn->groups; cur != NULL; cur = cur->next) { aim_module_t *mod; if ((mod = aim__findmodulebygroup(od, GPOINTER_TO_UINT(cur->data)))) { byte_stream_put16(&frame->data, mod->family); byte_stream_put16(&frame->data, mod->version); byte_stream_put16(&frame->data, mod->toolid); byte_stream_put16(&frame->data, mod->toolversion); } } flap_connection_send(conn, frame);}/* * Subtype 0x0003 - Host Online * * See comments in conn.c about how the group associations are supposed * to work, and how they really work. * * This info probably doesn't even need to make it to the client. * * We don't actually call the client here. This starts off the connection * initialization routine required by all AIM connections. The next time * the client is called is the CONNINITDONE callback, which should be * shortly after the rate information is acknowledged. * */static inthostonline(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs){ int group; while (byte_stream_empty(bs)) { group = byte_stream_get16(bs); conn->groups = g_slist_prepend(conn->groups, GUINT_TO_POINTER(group)); } /* * Next step is in the Host Versions handler. * * Note that we must send this before we request rates, since * the format of the rate information depends on the versions we * give it. * */ aim_srv_setversions(od, conn); return 1;}/* Subtype 0x0004 - Service request */voidaim_srv_requestnew(OscarData *od, guint16 serviceid){ FlapConnection *conn; conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS); if(!conn) return; aim_genericreq_s(od, conn, 0x0001, 0x0004, &serviceid);}/* * Join a room of name roomname. This is the first step to joining an * already created room. It's basically a Service Request for * family 0x000e, with a little added on to specify the exchange and room * name. */intaim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance){ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; GSList *tlvlist = NULL; struct chatsnacinfo csi; conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS); if (!conn || !roomname || !strlen(roomname)) return -EINVAL; frame = flap_frame_new(od, 0x02, 512); memset(&csi, 0, sizeof(csi)); csi.exchange = exchange; strncpy(csi.name, roomname, sizeof(csi.name)); csi.instance = instance; snacid = aim_cachesnac(od, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi)); aim_putsnac(&frame->data, 0x0001, 0x0004, 0x0000, snacid); /* * Requesting service chat (0x000e) */ byte_stream_put16(&frame->data, 0x000e); aim_tlvlist_add_chatroom(&tlvlist, 0x0001, exchange, roomname, instance); aim_tlvlist_write(&frame->data, &tlvlist); aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); return 0;}/* Subtype 0x0005 - Redirect */static intredirect(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs){ struct aim_redirect_data redir; aim_rxcallback_t userfunc; GSList *tlvlist; aim_snac_t *origsnac = NULL; int ret = 0; memset(&redir, 0, sizeof(redir)); tlvlist = aim_tlvlist_read(bs); if (!aim_tlv_gettlv(tlvlist, 0x000d, 1) || !aim_tlv_gettlv(tlvlist, 0x0005, 1) || !aim_tlv_gettlv(tlvlist, 0x0006, 1)) { aim_tlvlist_free(tlvlist); return 0; } redir.group = aim_tlv_get16(tlvlist, 0x000d, 1); redir.ip = aim_tlv_getstr(tlvlist, 0x0005, 1); redir.cookielen = aim_tlv_gettlv(tlvlist, 0x0006, 1)->length; redir.cookie = (guchar *)aim_tlv_getstr(tlvlist, 0x0006, 1); /* Fetch original SNAC so we can get csi if needed */ origsnac = aim_remsnac(od, snac->id); if ((redir.group == SNAC_FAMILY_CHAT) && origsnac) { struct chatsnacinfo *csi = (struct chatsnacinfo *)origsnac->data; redir.chat.exchange = csi->exchange; redir.chat.room = csi->name; redir.chat.instance = csi->instance; } if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, &redir); g_free((void *)redir.ip); g_free((void *)redir.cookie); if (origsnac) g_free(origsnac->data); g_free(origsnac); aim_tlvlist_free(tlvlist); return ret;}/* Subtype 0x0006 - Request Rate Information. */voidaim_srv_reqrates(OscarData *od, FlapConnection *conn){ aim_genericreq_n_snacid(od, conn, 0x0001, 0x0006);}/* * OSCAR defines several 'rate classes'. Each class has separate * rate limiting properties (limit level, alert level, disconnect * level, etc), and a set of SNAC family/type pairs associated with * it. The rate classes, their limiting properties, and the definitions * of which SNACs belong to which class are defined in the * Rate Response packet at login to each host. * * Logically, all rate offenses within one class count against further * offenses for other SNACs in the same class (ie, sending messages * too fast will limit the number of user info requests you can send, * since those two SNACs are in the same rate class). * * Since the rate classes are defined dynamically at login, the values * below may change. But they seem to be fairly constant. * * Currently, BOS defines five rate classes, with the commonly used * members as follows... * * Rate class 0x0001: * - Everything thats not in any of the other classes * * Rate class 0x0002: * - Buddy list add/remove * - Permit list add/remove * - Deny list add/remove * * Rate class 0x0003: * - User information requests * - Outgoing ICBMs * * Rate class 0x0004: * - A few unknowns: 2/9, 2/b, and f/2 * * Rate class 0x0005: * - Chat room create * - Outgoing chat ICBMs * * The only other thing of note is that class 5 (chat) has slightly looser * limiting properties than class 3 (normal messages). But thats just a * small bit of trivia for you. * * The last thing that needs to be learned about the rate limiting * system is how the actual numbers relate to the passing of time. This * seems to be a big mystery. * * See joscar's javadoc for the RateClassInfo class for a great * explanation. You might be able to find it at * http://dscoder.com/RateClassInfo.html */static struct rateclass *rateclass_find(GSList *rateclasses, guint16 id){ GSList *tmp; for (tmp = rateclasses; tmp != NULL; tmp = tmp->next) { struct rateclass *rateclass; rateclass = tmp->data; if (rateclass->classid == id) return rateclass; } return NULL;}/* Subtype 0x0007 - Rate Parameters */static intrateresp(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs){ guint16 numclasses, i; aim_rxcallback_t userfunc; /* * First are the parameters for each rate class. */ numclasses = byte_stream_get16(bs); for (i = 0; i < numclasses; i++) { struct rateclass *rateclass; rateclass = g_new0(struct rateclass, 1); rateclass->classid = byte_stream_get16(bs); rateclass->windowsize = byte_stream_get32(bs); rateclass->clear = byte_stream_get32(bs); rateclass->alert = byte_stream_get32(bs); rateclass->limit = byte_stream_get32(bs); rateclass->disconnect = byte_stream_get32(bs); rateclass->current = byte_stream_get32(bs); rateclass->max = byte_stream_get32(bs); /* * The server will send an extra five bytes of parameters * depending on the version we advertised in 1/17. If we * didn't send 1/17 (evil!), then this will crash and you * die, as it will default to the old version but we have * the new version hardcoded here. */ if (mod->version >= 3) byte_stream_getrawbuf(bs, rateclass->unknown, sizeof(rateclass->unknown)); rateclass->members = g_hash_table_new(g_direct_hash, g_direct_equal); rateclass->last.tv_sec = 0; rateclass->last.tv_usec = 0; conn->rateclasses = g_slist_prepend(conn->rateclasses, rateclass); } conn->rateclasses = g_slist_reverse(conn->rateclasses); /* * Then the members of each class. */ for (i = 0; i < numclasses; i++) { guint16 classid, count; struct rateclass *rateclass; int j; classid = byte_stream_get16(bs); count = byte_stream_get16(bs); rateclass = rateclass_find(conn->rateclasses, classid); for (j = 0; j < count; j++) { guint16 group, subtype; group = byte_stream_get16(bs); subtype = byte_stream_get16(bs); if (rateclass != NULL) g_hash_table_insert(rateclass->members, GUINT_TO_POINTER((group << 16) + subtype), GUINT_TO_POINTER(TRUE)); } } /* * We don't pass the rate information up to the client, as it really * doesn't care. The information is stored in the connection, however * so that we can do rate limiting management when sending SNACs. */ /* * Last step in the conn init procedure is to acknowledge that we * agree to these draconian limitations. */ aim_srv_rates_addparam(od, conn); /* * Finally, tell the client it's ready to go... */ if ((userfunc = aim_callhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE))) userfunc(od, conn, frame);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -