Annotation of ChivanetAimPidgin/oscarprpl/src/c/family_chat.c, revision 1.1.1.1

1.1       snw         1: /*
                      2:  * Purple's oscar protocol plugin
                      3:  * This file is the legal property of its developers.
                      4:  * Please see the AUTHORS file distributed alongside this file.
                      5:  *
                      6:  * This library is free software; you can redistribute it and/or
                      7:  * modify it under the terms of the GNU Lesser 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:  * Lesser General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU Lesser General Public
                     17:  * License along with this library; if not, write to the Free Software
                     18:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
                     19: */
                     20: 
                     21: /*
                     22:  * Family 0x000e - Routines for the Chat service.
                     23:  *
                     24:  */
                     25: 
                     26: #include "oscar.h"
                     27: 
                     28: #include <string.h>
                     29: 
                     30: /* Stored in the ->internal of chat connections */
                     31: struct chatconnpriv
                     32: {
                     33:        guint16 exchange;
                     34:        char *name;
                     35:        guint16 instance;
                     36: };
                     37: 
                     38: void
                     39: flap_connection_destroy_chat(OscarData *od, FlapConnection *conn)
                     40: {
                     41:        struct chatconnpriv *ccp = (struct chatconnpriv *)conn->internal;
                     42: 
                     43:        if (ccp)
                     44:                g_free(ccp->name);
                     45:        g_free(ccp);
                     46: 
                     47:        return;
                     48: }
                     49: 
                     50: int
                     51: aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
                     52: {
                     53:        if (!bs || !outinfo)
                     54:                return 0;
                     55: 
                     56:        outinfo->exchange = byte_stream_get16(bs);
                     57:        outinfo->namelen = byte_stream_get8(bs);
                     58:        outinfo->name = (char *)byte_stream_getraw(bs, outinfo->namelen);
                     59:        outinfo->instance = byte_stream_get16(bs);
                     60: 
                     61:        return 0;
                     62: }
                     63: 
                     64: /*
                     65:  * Subtype 0x0002 - General room information.  Lots of stuff.
                     66:  *
                     67:  * Values I know are in here but I haven't attached
                     68:  * them to any of the 'Unknown's:
                     69:  *     - Language (English)
                     70:  *
                     71:  */
                     72: static int
                     73: infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
                     74: {
                     75:        aim_rxcallback_t userfunc;
                     76:        int ret = 0;
                     77:        guint8 detaillevel = 0;
                     78:        struct aim_chat_roominfo roominfo;
                     79:        GSList *tlvlist;
                     80:        guint16 maxmsglen, maxvisiblemsglen;
                     81: 
                     82:        aim_chat_readroominfo(bs, &roominfo);
                     83: 
                     84:        detaillevel = byte_stream_get8(bs);
                     85: 
                     86:        if (detaillevel != 0x02) {
                     87:                purple_debug_misc("oscar", "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);
                     88:                return 1;
                     89:        }
                     90: 
                     91:        byte_stream_get16(bs); /* skip the TLV count */
                     92: 
                     93:        /*
                     94:         * Everything else are TLVs.
                     95:         */
                     96:        tlvlist = aim_tlvlist_read(bs);
                     97: 
                     98:        /*
                     99:         * Type 0x00d1: Maximum Message Length
                    100:         */
                    101:        maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1);
                    102: 
                    103:        /*
                    104:         * Type 0x00da: Maximum visible message length
                    105:         */
                    106:        maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1);
                    107: 
                    108:        if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
                    109:                ret = userfunc(od, conn, frame, maxmsglen, maxvisiblemsglen);
                    110:        }
                    111: 
                    112:        g_free(roominfo.name);
                    113: 
                    114:        aim_tlvlist_free(tlvlist);
                    115: 
                    116:        return ret;
                    117: }
                    118: 
                    119: /* Subtypes 0x0003 and 0x0004 */
                    120: static int
                    121: userlistchange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
                    122: {
                    123:        aim_userinfo_t *userinfo = NULL;
                    124:        aim_rxcallback_t userfunc;
                    125:        int curcount = 0, ret = 0;
                    126: 
                    127:        while (byte_stream_bytes_left(bs)) {
                    128:                curcount++;
                    129:                userinfo = g_realloc(userinfo, curcount * sizeof(aim_userinfo_t));
                    130:                aim_info_extract(od, bs, &userinfo[curcount-1]);
                    131:        }
                    132: 
                    133:        if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
                    134:                ret = userfunc(od, conn, frame, curcount, userinfo);
                    135: 
                    136:        aim_info_free(userinfo);
                    137:        g_free(userinfo);
                    138: 
                    139:        return ret;
                    140: }
                    141: 
                    142: /*
                    143:  * Subtype 0x0005 - Send a Chat Message.
                    144:  *
                    145:  * Possible flags:
                    146:  *   AIM_CHATFLAGS_NOREFLECT   --  Unset the flag that requests messages
                    147:  *                                 should be sent to their sender.
                    148:  *   AIM_CHATFLAGS_AWAY        --  Mark the message as an autoresponse
                    149:  *                                 (Note that WinAIM does not honor this,
                    150:  *                                 and displays the message as normal.)
                    151:  *
                    152:  * XXX convert this to use tlvchains
                    153:  */
                    154: int
                    155: aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language)
                    156: {
                    157:        int i;
                    158:        ByteStream bs;
                    159:        IcbmCookie *cookie;
                    160:        aim_snacid_t snacid;
                    161:        guint8 ckstr[8];
                    162:        GSList *tlvlist = NULL, *inner_tlvlist = NULL;
                    163: 
                    164:        if (!od || !conn || !msg || (msglen <= 0))
                    165:                return 0;
                    166: 
                    167:        byte_stream_new(&bs, 1142);
                    168: 
                    169:        snacid = aim_cachesnac(od, SNAC_FAMILY_CHAT, 0x0005, 0x0000, NULL, 0);
                    170: 
                    171:        /*
                    172:         * Cookie
                    173:         *
                    174:         * XXX mkcookie should generate the cookie and cache it in one
                    175:         * operation to preserve uniqueness.
                    176:         */
                    177:        for (i = 0; i < 8; i++)
                    178:                ckstr[i] = (guint8)rand();
                    179: 
                    180:        cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL);
                    181:        cookie->data = NULL; /* XXX store something useful here */
                    182: 
                    183:        aim_cachecookie(od, cookie);
                    184: 
                    185:        /* ICBM Header */
                    186:        byte_stream_putraw(&bs, ckstr, 8); /* Cookie */
                    187:        byte_stream_put16(&bs, 0x0003); /* Channel */
                    188: 
                    189:        /*
                    190:         * Type 1: Flag meaning this message is destined to the room.
                    191:         */
                    192:        aim_tlvlist_add_noval(&tlvlist, 0x0001);
                    193: 
                    194:        /*
                    195:         * Type 6: Reflect
                    196:         */
                    197:        if (!(flags & AIM_CHATFLAGS_NOREFLECT))
                    198:                aim_tlvlist_add_noval(&tlvlist, 0x0006);
                    199: 
                    200:        /*
                    201:         * Type 7: Autoresponse
                    202:         */
                    203:        if (flags & AIM_CHATFLAGS_AWAY)
                    204:                aim_tlvlist_add_noval(&tlvlist, 0x0007);
                    205: 
                    206:        /*
                    207:         * SubTLV: Type 1: Message
                    208:         */
                    209:        aim_tlvlist_add_raw(&inner_tlvlist, 0x0001, msglen, (guchar *)msg);
                    210: 
                    211:        /*
                    212:         * SubTLV: Type 2: Encoding
                    213:         */
                    214:        if (encoding != NULL)
                    215:                aim_tlvlist_add_str(&inner_tlvlist, 0x0002, encoding);
                    216: 
                    217:        /*
                    218:         * SubTLV: Type 3: Language
                    219:         */
                    220:        if (language != NULL)
                    221:                aim_tlvlist_add_str(&inner_tlvlist, 0x0003, language);
                    222: 
                    223:        /*
                    224:         * Type 5: Message block.  Contains more TLVs.
                    225:         *
                    226:         * This could include other information... We just
                    227:         * put in a message TLV however.
                    228:         *
                    229:         */
                    230:        aim_tlvlist_add_frozentlvlist(&tlvlist, 0x0005, &inner_tlvlist);
                    231: 
                    232:        aim_tlvlist_write(&bs, &tlvlist);
                    233: 
                    234:        aim_tlvlist_free(inner_tlvlist);
                    235:        aim_tlvlist_free(tlvlist);
                    236: 
                    237:        flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, snacid, &bs);
                    238: 
                    239:        byte_stream_destroy(&bs);
                    240: 
                    241:        return 0;
                    242: }
                    243: 
                    244: /*
                    245:  * Subtype 0x0006
                    246:  *
                    247:  * We could probably include this in the normal ICBM parsing
                    248:  * code as channel 0x0003, however, since only the start
                    249:  * would be the same, we might as well do it here.
                    250:  *
                    251:  * General outline of this SNAC:
                    252:  *   snac
                    253:  *   cookie
                    254:  *   channel id
                    255:  *   tlvlist
                    256:  *     unknown
                    257:  *     source user info
                    258:  *       name
                    259:  *       evility
                    260:  *       userinfo tlvs
                    261:  *         online time
                    262:  *         etc
                    263:  *     message metatlv
                    264:  *       message tlv
                    265:  *         message string
                    266:  *       possibly others
                    267:  *
                    268:  */
                    269: static int
                    270: incomingim_ch3(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
                    271: {
                    272:        int ret = 0, i;
                    273:        aim_rxcallback_t userfunc;
                    274:        aim_userinfo_t userinfo;
                    275:        guint8 cookie[8];
                    276:        guint16 channel;
                    277:        GSList *tlvlist;
                    278:        char *msg = NULL;
                    279:        int len = 0;
                    280:        char *encoding = NULL, *language = NULL;
                    281:        IcbmCookie *ck;
                    282:        aim_tlv_t *tlv;
                    283:        ByteStream tbs;
                    284: 
                    285:        memset(&userinfo, 0, sizeof(aim_userinfo_t));
                    286: 
                    287:        /*
                    288:         * Read ICBM Cookie.
                    289:         */
                    290:        for (i = 0; i < 8; i++)
                    291:                cookie[i] = byte_stream_get8(bs);
                    292: 
                    293:        if ((ck = aim_uncachecookie(od, cookie, AIM_COOKIETYPE_CHAT))) {
                    294:                g_free(ck->data);
                    295:                g_free(ck);
                    296:        }
                    297: 
                    298:        /*
                    299:         * Channel ID
                    300:         *
                    301:         * Channel 0x0003 is used for chat messages.
                    302:         *
                    303:         */
                    304:        channel = byte_stream_get16(bs);
                    305: 
                    306:        if (channel != 0x0003) {
                    307:                purple_debug_misc("oscar", "faim: chat_incoming: unknown channel! (0x%04x)\n", channel);
                    308:                return 0;
                    309:        }
                    310: 
                    311:        /*
                    312:         * Start parsing TLVs right away.
                    313:         */
                    314:        tlvlist = aim_tlvlist_read(bs);
                    315: 
                    316:        /*
                    317:         * Type 0x0003: Source User Information
                    318:         */
                    319:        tlv = aim_tlv_gettlv(tlvlist, 0x0003, 1);
                    320:        if (tlv != NULL)
                    321:        {
                    322:                byte_stream_init(&tbs, tlv->value, tlv->length);
                    323:                aim_info_extract(od, &tbs, &userinfo);
                    324:        }
                    325: 
                    326:        /*
                    327:         * Type 0x0005: Message Block.  Conains more TLVs.
                    328:         */
                    329:        tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1);
                    330:        if (tlv != NULL)
                    331:        {
                    332:                GSList *inner_tlvlist;
                    333:                aim_tlv_t *inner_tlv;
                    334: 
                    335:                byte_stream_init(&tbs, tlv->value, tlv->length);
                    336:                inner_tlvlist = aim_tlvlist_read(&tbs);
                    337: 
                    338:                /*
                    339:                 * Type 0x0001: Message.
                    340:                 */
                    341:                inner_tlv = aim_tlv_gettlv(inner_tlvlist, 0x0001, 1);
                    342:                if (inner_tlv != NULL)
                    343:                {
                    344:                        len = inner_tlv->length;
                    345:                        msg = aim_tlv_getvalue_as_string(inner_tlv);
                    346:                }
                    347: 
                    348:                /*
                    349:                 * Type 0x0002: Encoding.
                    350:                 */
                    351:                encoding = aim_tlv_getstr(inner_tlvlist, 0x0002, 1);
                    352: 
                    353:                /*
                    354:                 * Type 0x0003: Language.
                    355:                 */
                    356:                language = aim_tlv_getstr(inner_tlvlist, 0x0003, 1);
                    357: 
                    358:                aim_tlvlist_free(inner_tlvlist);
                    359:        }
                    360: 
                    361:        if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
                    362:                ret = userfunc(od, conn, frame, &userinfo, len, msg, encoding, language);
                    363: 
                    364:        aim_info_free(&userinfo);
                    365:        g_free(msg);
                    366:        g_free(encoding);
                    367:        g_free(language);
                    368:        aim_tlvlist_free(tlvlist);
                    369: 
                    370:        return ret;
                    371: }
                    372: 
                    373: static int
                    374: snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
                    375: {
                    376:        if (snac->subtype == 0x0002)
                    377:                return infoupdate(od, conn, mod, frame, snac, bs);
                    378:        else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004))
                    379:                return userlistchange(od, conn, mod, frame, snac, bs);
                    380:        else if (snac->subtype == 0x0006)
                    381:                return incomingim_ch3(od, conn, mod, frame, snac, bs);
                    382: 
                    383:        return 0;
                    384: }
                    385: 
                    386: int
                    387: chat_modfirst(OscarData *od, aim_module_t *mod)
                    388: {
                    389:        mod->family = SNAC_FAMILY_CHAT;
                    390:        mod->version = 0x0001;
                    391:        mod->toolid = 0x0010;
                    392:        mod->toolversion = 0x0629;
                    393:        mod->flags = 0;
                    394:        strncpy(mod->name, "chat", sizeof(mod->name));
                    395:        mod->snachandler = snachandler;
                    396: 
                    397:        return 0;
                    398: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>