source: protocols/oscar/chatnav.c @ 4e365ce

Last change on this file since 4e365ce was 5ebff60, checked in by dequis <dx@…>, at 2015-02-20T22:50:54Z

Reindent everything to K&R style with tabs

Used uncrustify, with the configuration file in ./doc/uncrustify.cfg

Commit author set to "Indent <please@…>" so that it's easier to
skip while doing git blame.

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/*
2 * Handle ChatNav.
3 *
4 * [The ChatNav(igation) service does various things to keep chat
5 *  alive.  It provides room information, room searching and creating,
6 *  as well as giving users the right ("permission") to use chat.]
7 *
8 */
9
10#include <aim.h>
11#include "chatnav.h"
12
13/*
14 * conn must be a chatnav connection!
15 */
16int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn)
17{
18        return aim_genericreq_n_snacid(sess, conn, 0x000d, 0x0002);
19}
20
21int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, guint16 exchange)
22{
23        static const char ck[] = { "create" };
24        static const char lang[] = { "en" };
25        static const char charset[] = { "us-ascii" };
26        aim_frame_t *fr;
27        aim_snacid_t snacid;
28        aim_tlvlist_t *tl = NULL;
29
30        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) {
31                return -ENOMEM;
32        }
33
34        snacid = aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0);
35        aim_putsnac(&fr->data, 0x000d, 0x0008, 0x0000, snacid);
36
37        /* exchange */
38        aimbs_put16(&fr->data, exchange);
39
40        /*
41         * This looks to be a big hack.  You'll note that this entire
42         * SNAC is just a room info structure, but the hard room name,
43         * here, is set to "create".
44         *
45         * Either this goes on the "list of questions concerning
46         * why-the-hell-did-you-do-that", or this value is completly
47         * ignored.  Without experimental evidence, but a good knowledge of
48         * AOL style, I'm going to guess that it is the latter, and that
49         * the value of the room name in create requests is ignored.
50         */
51        aimbs_put8(&fr->data, strlen(ck));
52        aimbs_putraw(&fr->data, (guint8 *) ck, strlen(ck));
53
54        /*
55         * instance
56         *
57         * Setting this to 0xffff apparently assigns the last instance.
58         *
59         */
60        aimbs_put16(&fr->data, 0xffff);
61
62        /* detail level */
63        aimbs_put8(&fr->data, 0x01);
64
65        aim_addtlvtochain_raw(&tl, 0x00d3, strlen(name), (guint8 *) name);
66        aim_addtlvtochain_raw(&tl, 0x00d6, strlen(charset), (guint8 *) charset);
67        aim_addtlvtochain_raw(&tl, 0x00d7, strlen(lang), (guint8 *) lang);
68
69        /* tlvcount */
70        aimbs_put16(&fr->data, aim_counttlvchain(&tl));
71        aim_writetlvchain(&fr->data, &tl);
72
73        aim_freetlvchain(&tl);
74
75        aim_tx_enqueue(sess, fr);
76
77        return 0;
78}
79
80static int parseinfo_perms(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
81                           aim_bstream_t *bs, aim_snac_t *snac2)
82{
83        aim_rxcallback_t userfunc;
84        int ret = 0;
85        struct aim_chat_exchangeinfo *exchanges = NULL;
86        int curexchange;
87        aim_tlv_t *exchangetlv;
88        guint8 maxrooms = 0;
89        aim_tlvlist_t *tlvlist, *innerlist;
90
91        tlvlist = aim_readtlvchain(bs);
92
93        /*
94         * Type 0x0002: Maximum concurrent rooms.
95         */
96        if (aim_gettlv(tlvlist, 0x0002, 1)) {
97                maxrooms = aim_gettlv8(tlvlist, 0x0002, 1);
98        }
99
100        /*
101         * Type 0x0003: Exchange information
102         *
103         * There can be any number of these, each one
104         * representing another exchange.
105         *
106         */
107        for (curexchange = 0; ((exchangetlv = aim_gettlv(tlvlist, 0x0003, curexchange + 1))); ) {
108                aim_bstream_t tbs;
109
110                aim_bstream_init(&tbs, exchangetlv->value, exchangetlv->length);
111
112                curexchange++;
113
114                exchanges = g_realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo));
115
116                /* exchange number */
117                exchanges[curexchange - 1].number = aimbs_get16(&tbs);
118                innerlist = aim_readtlvchain(&tbs);
119
120                /*
121                 * Type 0x000a: Unknown.
122                 *
123                 * Usually three bytes: 0x0114 (exchange 1) or 0x010f (others).
124                 *
125                 */
126                if (aim_gettlv(innerlist, 0x000a, 1)) {
127                        ;
128                }
129
130                /*
131                 * Type 0x000d: Unknown.
132                 */
133                if (aim_gettlv(innerlist, 0x000d, 1)) {
134                        ;
135                }
136
137                /*
138                 * Type 0x0004: Unknown
139                 */
140                if (aim_gettlv(innerlist, 0x0004, 1)) {
141                        ;
142                }
143
144                /*
145                 * Type 0x0002: Unknown
146                 */
147                if (aim_gettlv(innerlist, 0x0002, 1)) {
148                        ;
149                }
150
151                /*
152                 * Type 0x00c9: Flags
153                 *
154                 * 1 Evilable
155                 * 2 Nav Only
156                 * 4 Instancing Allowed
157                 * 8 Occupant Peek Allowed
158                 *
159                 */
160                if (aim_gettlv(innerlist, 0x00c9, 1)) {
161                        exchanges[curexchange - 1].flags = aim_gettlv16(innerlist, 0x00c9, 1);
162                }
163
164                /*
165                 * Type 0x00ca: Creation Date
166                 */
167                if (aim_gettlv(innerlist, 0x00ca, 1)) {
168                        ;
169                }
170
171                /*
172                 * Type 0x00d0: Mandatory Channels?
173                 */
174                if (aim_gettlv(innerlist, 0x00d0, 1)) {
175                        ;
176                }
177
178                /*
179                 * Type 0x00d1: Maximum Message length
180                 */
181                if (aim_gettlv(innerlist, 0x00d1, 1)) {
182                        ;
183                }
184
185                /*
186                 * Type 0x00d2: Maximum Occupancy?
187                 */
188                if (aim_gettlv(innerlist, 0x00d2, 1)) {
189                        ;
190                }
191
192                /*
193                 * Type 0x00d3: Exchange Description
194                 */
195                if (aim_gettlv(innerlist, 0x00d3, 1)) {
196                        exchanges[curexchange - 1].name = aim_gettlv_str(innerlist, 0x00d3, 1);
197                } else {
198                        exchanges[curexchange - 1].name = NULL;
199                }
200
201                /*
202                 * Type 0x00d4: Exchange Description URL
203                 */
204                if (aim_gettlv(innerlist, 0x00d4, 1)) {
205                        ;
206                }
207
208                /*
209                 * Type 0x00d5: Creation Permissions
210                 *
211                 * 0  Creation not allowed
212                 * 1  Room creation allowed
213                 * 2  Exchange creation allowed
214                 *
215                 */
216                if (aim_gettlv(innerlist, 0x00d5, 1)) {
217                        aim_gettlv8(innerlist, 0x00d5, 1); /* createperms */
218                }
219
220                /*
221                 * Type 0x00d6: Character Set (First Time)
222                 */
223                if (aim_gettlv(innerlist, 0x00d6, 1)) {
224                        exchanges[curexchange - 1].charset1 = aim_gettlv_str(innerlist, 0x00d6, 1);
225                } else {
226                        exchanges[curexchange - 1].charset1 = NULL;
227                }
228
229                /*
230                 * Type 0x00d7: Language (First Time)
231                 */
232                if (aim_gettlv(innerlist, 0x00d7, 1)) {
233                        exchanges[curexchange - 1].lang1 = aim_gettlv_str(innerlist, 0x00d7, 1);
234                } else {
235                        exchanges[curexchange - 1].lang1 = NULL;
236                }
237
238                /*
239                 * Type 0x00d8: Character Set (Second Time)
240                 */
241                if (aim_gettlv(innerlist, 0x00d8, 1)) {
242                        exchanges[curexchange - 1].charset2 = aim_gettlv_str(innerlist, 0x00d8, 1);
243                } else {
244                        exchanges[curexchange - 1].charset2 = NULL;
245                }
246
247                /*
248                 * Type 0x00d9: Language (Second Time)
249                 */
250                if (aim_gettlv(innerlist, 0x00d9, 1)) {
251                        exchanges[curexchange - 1].lang2 = aim_gettlv_str(innerlist, 0x00d9, 1);
252                } else {
253                        exchanges[curexchange - 1].lang2 = NULL;
254                }
255
256                /*
257                 * Type 0x00da: Unknown
258                 */
259                if (aim_gettlv(innerlist, 0x00da, 1)) {
260                        ;
261                }
262
263                aim_freetlvchain(&innerlist);
264        }
265
266        /*
267         * Call client.
268         */
269        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
270                ret = userfunc(sess, rx, snac2->type, maxrooms, curexchange, exchanges);
271        }
272
273        for (curexchange--; curexchange >= 0; curexchange--) {
274                g_free(exchanges[curexchange].name);
275                g_free(exchanges[curexchange].charset1);
276                g_free(exchanges[curexchange].lang1);
277                g_free(exchanges[curexchange].charset2);
278                g_free(exchanges[curexchange].lang2);
279        }
280        g_free(exchanges);
281        aim_freetlvchain(&tlvlist);
282
283        return ret;
284}
285
286static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac,
287                            aim_bstream_t *bs, aim_snac_t *snac2)
288{
289        aim_rxcallback_t userfunc;
290        aim_tlvlist_t *tlvlist, *innerlist;
291        char *ck = NULL, *fqcn = NULL, *name = NULL;
292        guint16 exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0;
293        guint32 createtime = 0;
294        guint8 createperms = 0, detaillevel;
295        int cklen;
296        aim_tlv_t *bigblock;
297        int ret = 0;
298        aim_bstream_t bbbs;
299
300        tlvlist = aim_readtlvchain(bs);
301
302        if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) {
303                imcb_error(sess->aux_data, "no bigblock in top tlv in create room response");
304
305                aim_freetlvchain(&tlvlist);
306                return 0;
307        }
308
309        aim_bstream_init(&bbbs, bigblock->value, bigblock->length);
310
311        exchange = aimbs_get16(&bbbs);
312        cklen = aimbs_get8(&bbbs);
313        ck = aimbs_getstr(&bbbs, cklen);
314        instance = aimbs_get16(&bbbs);
315        detaillevel = aimbs_get8(&bbbs);
316
317        if (detaillevel != 0x02) {
318                imcb_error(sess->aux_data, "unknown detaillevel in create room response");
319                aim_freetlvchain(&tlvlist);
320                g_free(ck);
321                return 0;
322        }
323
324        unknown = aimbs_get16(&bbbs);
325
326        innerlist = aim_readtlvchain(&bbbs);
327
328        if (aim_gettlv(innerlist, 0x006a, 1)) {
329                fqcn = aim_gettlv_str(innerlist, 0x006a, 1);
330        }
331
332        if (aim_gettlv(innerlist, 0x00c9, 1)) {
333                flags = aim_gettlv16(innerlist, 0x00c9, 1);
334        }
335
336        if (aim_gettlv(innerlist, 0x00ca, 1)) {
337                createtime = aim_gettlv32(innerlist, 0x00ca, 1);
338        }
339
340        if (aim_gettlv(innerlist, 0x00d1, 1)) {
341                maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1);
342        }
343
344        if (aim_gettlv(innerlist, 0x00d2, 1)) {
345                maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1);
346        }
347
348        if (aim_gettlv(innerlist, 0x00d3, 1)) {
349                name = aim_gettlv_str(innerlist, 0x00d3, 1);
350        }
351
352        if (aim_gettlv(innerlist, 0x00d5, 1)) {
353                createperms = aim_gettlv8(innerlist, 0x00d5, 1);
354        }
355
356        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
357                ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen,
358                               maxoccupancy, createperms, unknown, name, ck);
359        }
360
361        g_free(ck);
362        g_free(name);
363        g_free(fqcn);
364        aim_freetlvchain(&innerlist);
365        aim_freetlvchain(&tlvlist);
366
367        return ret;
368}
369
370/*
371 * Since multiple things can trigger this callback, we must lookup the
372 * snacid to determine the original snac subtype that was called.
373 *
374 * XXX This isn't really how this works.  But this is:  Every d/9 response
375 * has a 16bit value at the beginning. That matches to:
376 *    Short Desc = 1
377 *    Full Desc = 2
378 *    Instance Info = 4
379 *    Nav Short Desc = 8
380 *    Nav Instance Info = 16
381 * And then everything is really asynchronous.  There is no specific
382 * attachment of a response to a create room request, for example.  Creating
383 * the room yields no different a response than requesting the room's info.
384 *
385 */
386static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
387{
388        aim_snac_t *snac2;
389        int ret = 0;
390
391        if (!(snac2 = aim_remsnac(sess, snac->id))) {
392                imcb_error(sess->aux_data, "received response to unknown request!");
393                return 0;
394        }
395
396        if (snac2->family != 0x000d) {
397                imcb_error(sess->aux_data, "received response that maps to corrupt request!");
398                return 0;
399        }
400
401        /*
402         * We now know what the original SNAC subtype was.
403         */
404        if (snac2->type == 0x0002) { /* request chat rights */
405                ret = parseinfo_perms(sess, mod, rx, snac, bs, snac2);
406        } else if (snac2->type == 0x0003) {
407        }                                  /* request exchange info */
408        else if (snac2->type == 0x0004) {
409        }                                  /* request room info */
410        else if (snac2->type == 0x0005) {
411        }                                  /* request more room info */
412        else if (snac2->type == 0x0006) {
413        }                                  /* request occupant list */
414        else if (snac2->type == 0x0007) {
415        }                                  /* search for a room */
416        else if (snac2->type == 0x0008) { /* create room */
417                ret = parseinfo_create(sess, mod, rx, snac, bs, snac2);
418        } else {
419                imcb_error(sess->aux_data, "unknown request subtype");
420        }
421
422        if (snac2) {
423                g_free(snac2->data);
424        }
425        g_free(snac2);
426
427        return ret;
428}
429
430static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
431{
432
433        if (snac->subtype == 0x0009) {
434                return parseinfo(sess, mod, rx, snac, bs);
435        }
436
437        return 0;
438}
439
440int chatnav_modfirst(aim_session_t *sess, aim_module_t *mod)
441{
442
443        mod->family = 0x000d;
444        mod->version = 0x0003;
445        mod->toolid = 0x0010;
446        mod->toolversion = 0x0629;
447        mod->flags = 0;
448        strncpy(mod->name, "chatnav", sizeof(mod->name));
449        mod->snachandler = snachandler;
450
451        return 0;
452}
Note: See TracBrowser for help on using the repository browser.