source: libfaim/info.c @ 5d9c664

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 5d9c664 was 862371b, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
*** empty log message ***
  • Property mode set to 100644
File size: 22.0 KB
Line 
1/*
2 * Family 0x0002 - Information.
3 *
4 * The functions here are responsible for requesting and parsing information-
5 * gathering SNACs.  Or something like that.
6 *
7 */
8
9#define FAIM_INTERNAL
10#include <aim.h>
11
12struct aim_priv_inforeq {
13        char sn[MAXSNLEN+1];
14        fu16_t infotype;
15};
16
17/*
18 * Subtype 0x0002
19 *
20 * Request Location services rights.
21 *
22 */
23faim_export int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn)
24{
25        return aim_genericreq_n(sess, conn, 0x0002, 0x0002);
26}
27
28/*
29 * Subtype 0x0004
30 *
31 * Gives BOS your profile.
32 *
33 */
34faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps)
35{
36        static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""};
37        aim_frame_t *fr;
38        aim_tlvlist_t *tl = NULL;
39        aim_snacid_t snacid;
40
41        /* Build to packet first to get real length */
42        if (profile) {
43                aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding);
44                aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile);
45        }
46
47        /*
48         * So here's how this works:
49         *   - You are away when you have a non-zero-length type 4 TLV stored.
50         *   - You become unaway when you clear the TLV with a zero-length
51         *       type 4 TLV.
52         *   - If you do not send the type 4 TLV, your status does not change
53         *       (that is, if you were away, you'll remain away).
54         */
55        if (awaymsg) {
56                if (strlen(awaymsg)) {
57                        aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding);
58                        aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg);
59                } else
60                        aim_addtlvtochain_noval(&tl, 0x0004);
61        }
62
63        aim_addtlvtochain_caps(&tl, 0x0005, caps);
64
65        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl))))
66                return -ENOMEM;
67
68        snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);
69
70        aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid);
71        aim_writetlvchain(&fr->data, &tl);
72        aim_freetlvchain(&tl);
73
74        aim_tx_enqueue(sess, fr);
75
76        return 0;
77}
78
79/*
80 * Subtype 0x0005 - Request info of another AIM user.
81 *
82 */
83faim_export int aim_getinfo(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu16_t infotype)
84{
85        struct aim_priv_inforeq privdata;
86        aim_frame_t *fr;
87        aim_snacid_t snacid;
88
89        if (!sess || !conn || !sn)
90                return -EINVAL;
91
92        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 12+1+strlen(sn))))
93                return -ENOMEM;
94
95        strncpy(privdata.sn, sn, sizeof(privdata.sn));
96        privdata.infotype = infotype;
97        snacid = aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq));
98       
99        aim_putsnac(&fr->data, 0x0002, 0x0005, 0x0000, snacid);
100        aimbs_put16(&fr->data, infotype);
101        aimbs_put8(&fr->data, strlen(sn));
102        aimbs_putraw(&fr->data, sn, strlen(sn));
103
104        aim_tx_enqueue(sess, fr);
105
106        return 0;
107}
108
109faim_export const char *aim_userinfo_sn(aim_userinfo_t *ui)
110{
111
112        if (!ui)
113                return NULL;
114
115        return ui->sn;
116}
117
118faim_export fu16_t aim_userinfo_flags(aim_userinfo_t *ui)
119{
120
121        if (!ui)
122                return 0;
123
124        return ui->flags;
125}
126
127faim_export fu16_t aim_userinfo_idle(aim_userinfo_t *ui)
128{
129
130        if (!ui)
131                return 0;
132
133        return ui->idletime;
134}
135
136faim_export float aim_userinfo_warnlevel(aim_userinfo_t *ui)
137{
138
139        if (!ui)
140                return 0.00;
141
142        return (ui->warnlevel / 10);
143}
144
145faim_export time_t aim_userinfo_createtime(aim_userinfo_t *ui)
146{
147
148        if (!ui)
149                return 0;
150
151        return (time_t)ui->createtime;
152}
153
154faim_export time_t aim_userinfo_membersince(aim_userinfo_t *ui)
155{
156
157        if (!ui)
158                return 0;
159
160        return (time_t)ui->membersince;
161}
162
163faim_export time_t aim_userinfo_onlinesince(aim_userinfo_t *ui)
164{
165
166        if (!ui)
167                return 0;
168
169        return (time_t)ui->onlinesince;
170}
171
172faim_export fu32_t aim_userinfo_sessionlen(aim_userinfo_t *ui)
173{
174
175        if (!ui)
176                return 0;
177
178        return ui->sessionlen;
179}
180
181faim_export int aim_userinfo_hascap(aim_userinfo_t *ui, fu32_t cap)
182{
183
184        if (!ui || !(ui->present & AIM_USERINFO_PRESENT_CAPABILITIES))
185                return -1;
186
187        return !!(ui->capabilities & cap);
188}
189
190
191/*
192 * Capability blocks.
193 *
194 * These are CLSIDs. They should actually be of the form:
195 *
196 * {0x0946134b, 0x4c7f, 0x11d1,
197 *  {0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}},
198 *
199 * But, eh.
200 */
201static const struct {
202        fu32_t flag;
203        fu8_t data[16];
204} aim_caps[] = {
205
206        /*
207         * Chat is oddball.
208         */
209        {AIM_CAPS_CHAT,
210         {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, 
211          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
212
213        /*
214         * These are mostly in order.
215         */
216        {AIM_CAPS_VOICE,
217         {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, 
218          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
219
220        {AIM_CAPS_SENDFILE,
221         {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, 
222          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
223
224        /*
225         * Advertised by the EveryBuddy client.
226         */
227        {AIM_CAPS_ICQ,
228         {0x09, 0x46, 0x13, 0x44, 0x4c, 0x7f, 0x11, 0xd1, 
229          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
230
231        {AIM_CAPS_IMIMAGE,
232         {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, 
233          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
234
235        {AIM_CAPS_BUDDYICON,
236         {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, 
237          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
238
239        {AIM_CAPS_SAVESTOCKS,
240         {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1,
241          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
242
243        {AIM_CAPS_GETFILE,
244         {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1,
245          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
246
247        {AIM_CAPS_ICQSERVERRELAY,
248         {0x09, 0x46, 0x13, 0x49, 0x4c, 0x7f, 0x11, 0xd1,
249          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
250
251        /*
252         * Indeed, there are two of these.  The former appears to be correct,
253         * but in some versions of winaim, the second one is set.  Either they
254         * forgot to fix endianness, or they made a typo. It really doesn't
255         * matter which.
256         */
257        {AIM_CAPS_GAMES,
258         {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
259          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
260        {AIM_CAPS_GAMES2,
261         {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
262          0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
263
264        {AIM_CAPS_SENDBUDDYLIST,
265         {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1,
266          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
267
268        /* from ICQ2002a
269        {AIM_CAPS_ICQUNKNOWN2,
270         {0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1,
271          0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, */
272
273        {AIM_CAPS_ICQRTF,
274         {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 
275          0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92}},
276
277        /* supposed to be ICQRTF?
278        {AIM_CAPS_TRILLUNKNOWN,
279         {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
280          0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}}, */
281
282        {AIM_CAPS_ICQUNKNOWN,
283         {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
284          0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}},
285
286        {AIM_CAPS_EMPTY,
287         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
289
290        {AIM_CAPS_TRILLIANCRYPT,
291         {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb,
292          0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}},
293
294        {AIM_CAPS_APINFO, 
295         {0xAA, 0x4A, 0x32, 0xB5, 0xF8, 0x84, 0x48, 0xc6,
296          0xA3, 0xD7, 0x8C, 0x50, 0x97, 0x19, 0xFD, 0x5B}},
297
298        {AIM_CAPS_LAST}
299};
300
301/*
302 * This still takes a length parameter even with a bstream because capabilities
303 * are not naturally bounded.
304 *
305 */
306faim_internal fu32_t aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len)
307{
308        fu32_t flags = 0;
309        int offset;
310
311        for (offset = 0; aim_bstream_empty(bs) && (offset < len); offset += 0x10) {
312                fu8_t *cap;
313                int i, identified;
314
315                cap = aimbs_getraw(bs, 0x10);
316
317                for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) {
318
319                        if (memcmp(&aim_caps[i].data, cap, 0x10) == 0) {
320                                flags |= aim_caps[i].flag;
321                                identified++;
322                                break; /* should only match once... */
323
324                        }
325                }
326
327                if (!identified) {
328                        faimdprintf(sess, 0, "unknown capability: {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
329                                        cap[0], cap[1], cap[2], cap[3],
330                                        cap[4], cap[5],
331                                        cap[6], cap[7],
332                                        cap[8], cap[9],
333                                        cap[10], cap[11], cap[12], cap[13],
334                                        cap[14], cap[15]);
335                }
336
337                free(cap);
338        }
339
340        return flags;
341}
342
343faim_internal int aim_putcap(aim_bstream_t *bs, fu32_t caps)
344{
345        int i;
346
347        if (!bs)
348                return -EINVAL;
349
350        for (i = 0; aim_bstream_empty(bs); i++) {
351
352                if (aim_caps[i].flag == AIM_CAPS_LAST)
353                        break;
354
355                if (caps & aim_caps[i].flag)
356                        aimbs_putraw(bs, aim_caps[i].data, 0x10);
357
358        }
359
360        return 0;
361}
362
363static void dumptlv(aim_session_t *sess, fu16_t type, aim_bstream_t *bs, fu8_t len)
364{
365        int i;
366
367        if (!sess || !bs || !len)
368                return;
369
370        faimdprintf(sess, 0, "userinfo:   type  =0x%04x\n", type);
371        faimdprintf(sess, 0, "userinfo:   length=0x%04x\n", len);
372
373        faimdprintf(sess, 0, "userinfo:   value:\n");
374
375        for (i = 0; i < len; i++) {
376                if ((i % 8) == 0)
377                        faimdprintf(sess, 0, "\nuserinfo:        ");
378
379                faimdprintf(sess, 0, "0x%2x ", aimbs_get8(bs));
380        }
381
382        faimdprintf(sess, 0, "\n");
383
384        return;
385}
386
387/*
388 * AIM is fairly regular about providing user info.  This is a generic
389 * routine to extract it in its standard form.
390 */
391faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo)
392{
393        int curtlv, tlvcnt;
394        fu8_t snlen;
395
396        if (!bs || !outinfo)
397                return -EINVAL;
398
399        /* Clear out old data first */
400        memset(outinfo, 0x00, sizeof(aim_userinfo_t));
401
402        /*
403         * Screen name.  Stored as an unterminated string prepended with a
404         * byte containing its length.
405         */
406        snlen = aimbs_get8(bs);
407        aimbs_getrawbuf(bs, outinfo->sn, snlen);
408
409        /*
410         * Warning Level.  Stored as an unsigned short.
411         */
412        outinfo->warnlevel = aimbs_get16(bs);
413
414        /*
415         * TLV Count. Unsigned short representing the number of
416         * Type-Length-Value triples that follow.
417         */
418        tlvcnt = aimbs_get16(bs);
419
420        /*
421         * Parse out the Type-Length-Value triples as they're found.
422         */
423        for (curtlv = 0; curtlv < tlvcnt; curtlv++) {
424                int endpos;
425                fu16_t type, length;
426
427                type = aimbs_get16(bs);
428                length = aimbs_get16(bs);
429
430                endpos = aim_bstream_curpos(bs) + length;
431
432                if (type == 0x0001) {
433                        /*
434                         * Type = 0x0001: User flags
435                         *
436                         * Specified as any of the following ORed together:
437                         *      0x0001  Trial (user less than 60days)
438                         *      0x0002  Unknown bit 2
439                         *      0x0004  AOL Main Service user
440                         *      0x0008  Unknown bit 4
441                         *      0x0010  Free (AIM) user
442                         *      0x0020  Away
443                         *      0x0400  ActiveBuddy
444                         *
445                         */
446                        outinfo->flags = aimbs_get16(bs);
447                        outinfo->present |= AIM_USERINFO_PRESENT_FLAGS;
448
449                } else if (type == 0x0002) {
450                        /*
451                         * Type = 0x0002: Account creation time.
452                         *
453                         * The time/date that the user originally registered for
454                         * the service, stored in time_t format.
455                         *
456                         * I'm not sure how this differs from type 5 ("member
457                         * since").
458                         *
459                         * Note: This is the field formerly known as "member
460                         * since".  All these years and I finally found out
461                         * that I got the name wrong.
462                         */
463                        outinfo->createtime = aimbs_get32(bs);
464                        outinfo->present |= AIM_USERINFO_PRESENT_CREATETIME;
465
466                } else if (type == 0x0003) {
467                        /*
468                         * Type = 0x0003: On-Since date.
469                         *
470                         * The time/date that the user started their current
471                         * session, stored in time_t format.
472                         */
473                        outinfo->onlinesince = aimbs_get32(bs);
474                        outinfo->present |= AIM_USERINFO_PRESENT_ONLINESINCE;
475
476                } else if (type == 0x0004) {
477                        /*
478                         * Type = 0x0004: Idle time.
479                         *
480                         * Number of seconds since the user actively used the
481                         * service.
482                         *
483                         * Note that the client tells the server when to start
484                         * counting idle times, so this may or may not be
485                         * related to reality.
486                         */
487                        outinfo->idletime = aimbs_get16(bs);
488                        outinfo->present |= AIM_USERINFO_PRESENT_IDLE;
489
490                } else if (type == 0x0005) {
491                        /*
492                         * Type = 0x0005: Member since date.
493                         *
494                         * The time/date that the user originally registered for
495                         * the service, stored in time_t format.
496                         *
497                         * This is sometimes sent instead of type 2 ("account
498                         * creation time"), particularly in the self-info.
499                         * And particularly for ICQ?
500                         */
501                        outinfo->membersince = aimbs_get32(bs);
502                        outinfo->present |= AIM_USERINFO_PRESENT_MEMBERSINCE;
503
504                } else if (type == 0x0006) {
505                        /*
506                         * Type = 0x0006: ICQ Online Status
507                         *
508                         * ICQ's Away/DND/etc "enriched" status. Some decoding
509                         * of values done by Scott <darkagl@pcnet.com>
510                         */
511                        aimbs_get16(bs);
512                        outinfo->icqinfo.status = aimbs_get16(bs);
513                        outinfo->present |= AIM_USERINFO_PRESENT_ICQEXTSTATUS;
514
515                } else if (type == 0x000a) {
516                        /*
517                         * Type = 0x000a
518                         *
519                         * ICQ User IP Address.
520                         * Ahh, the joy of ICQ security.
521                         */
522                        outinfo->icqinfo.ipaddr = aimbs_get32(bs);
523                        outinfo->present |= AIM_USERINFO_PRESENT_ICQIPADDR;
524
525                } else if (type == 0x000c) {
526                        /*
527                         * Type = 0x000c
528                         *
529                         * random crap containing the IP address,
530                         * apparently a port number, and some Other Stuff.
531                         *
532                         */
533                        aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
534                        outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA;
535
536                } else if (type == 0x000d) {
537                        /*
538                         * Type = 0x000d
539                         *
540                         * Capability information.
541                         *
542                         */
543                        outinfo->capabilities = aim_getcap(sess, bs, length);
544                        outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
545
546                } else if (type == 0x000e) {
547                        /*
548                         * Type = 0x000e
549                         *
550                         * Unknown.  Always of zero length, and always only
551                         * on AOL users.
552                         *
553                         * Ignore.
554                         *
555                         */
556
557                } else if ((type == 0x000f) || (type == 0x0010)) {
558                        /*
559                         * Type = 0x000f: Session Length. (AIM)
560                         * Type = 0x0010: Session Length. (AOL)
561                         *
562                         * The duration, in seconds, of the user's current
563                         * session.
564                         *
565                         * Which TLV type this comes in depends on the
566                         * service the user is using (AIM or AOL).
567                         *
568                         */
569                        outinfo->sessionlen = aimbs_get32(bs);
570                        outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN;
571
572                } else if (type == 0x001d) {
573                        /*
574                         * Type 29: Unknown.
575                         *
576                         * Currently very rare. Always 18 bytes of mostly zero.
577                         */
578
579                } else if (type == 0x001e) {
580                        /*
581                         * Type 30: Unknown.
582                         *
583                         * Always four bytes, but it doesn't look like an int.
584                         */
585                } else {
586
587                        /*
588                         * Reaching here indicates that either AOL has
589                         * added yet another TLV for us to deal with,
590                         * or the parsing has gone Terribly Wrong.
591                         *
592                         * Either way, inform the owner and attempt
593                         * recovery.
594                         *
595                         */
596                        faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV:\n");
597                        faimdprintf(sess, 0, "userinfo:   sn    =%s\n", outinfo->sn);
598                        dumptlv(sess, type, bs, length);
599                }
600
601                /* Save ourselves. */
602                aim_bstream_setpos(bs, endpos);
603        }
604
605        return 0;
606}
607
608/*
609 * Inverse of aim_extractuserinfo()
610 */
611faim_internal int aim_putuserinfo(aim_bstream_t *bs, aim_userinfo_t *info)
612{
613        aim_tlvlist_t *tlvlist = NULL;
614
615        if (!bs || !info)
616                return -EINVAL;
617
618        aimbs_put8(bs, strlen(info->sn));
619        aimbs_putraw(bs, info->sn, strlen(info->sn));
620
621        aimbs_put16(bs, info->warnlevel);
622
623
624        if (info->present & AIM_USERINFO_PRESENT_FLAGS)
625                aim_addtlvtochain16(&tlvlist, 0x0001, info->flags);
626        if (info->present & AIM_USERINFO_PRESENT_MEMBERSINCE)
627                aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince);
628        if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
629                aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince);
630        if (info->present & AIM_USERINFO_PRESENT_IDLE)
631                aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);
632
633/* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */
634#if ICQ_OSCAR_SUPPORT
635        if (atoi(info->sn) != 0) {
636                if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS)
637                        aim_addtlvtochain16(&tlvlist, 0x0006, info->icqinfo.status);
638                if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR)
639                        aim_addtlvtochain32(&tlvlist, 0x000a, info->icqinfo.ipaddr);
640        }
641#endif
642
643        if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
644                aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities);
645 
646        if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
647                aim_addtlvtochain32(&tlvlist, (fu16_t)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);
648
649        aimbs_put16(bs, aim_counttlvchain(&tlvlist));
650        aim_writetlvchain(bs, &tlvlist);
651        aim_freetlvchain(&tlvlist);
652
653        return 0;
654}
655
656/*
657 * Subtype 0x000b - Huh? What is this?
658 */
659faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn)
660{
661        aim_frame_t *fr;
662        aim_snacid_t snacid;
663
664        if (!sess || !conn || !sn)
665                return -EINVAL;
666
667        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
668                return -ENOMEM;
669
670        snacid = aim_cachesnac(sess, 0x0002, 0x000b, 0x0000, NULL, 0);
671       
672        aim_putsnac(&fr->data, 0x0002, 0x000b, 0x0000, snacid);
673        aimbs_put8(&fr->data, strlen(sn));
674        aimbs_putraw(&fr->data, sn, strlen(sn));
675
676        aim_tx_enqueue(sess, fr);
677
678        return 0;
679}
680
681/*
682 * Subtype 0x0003
683 *
684 * Normally contains:
685 *   t(0001)  - short containing max profile length (value = 1024)
686 *   t(0002)  - short - unknown (value = 16) [max MIME type length?]
687 *   t(0003)  - short - unknown (value = 10)
688 *   t(0004)  - short - unknown (value = 2048) [ICQ only?]
689 */
690static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
691{
692        aim_tlvlist_t *tlvlist;
693        aim_rxcallback_t userfunc;
694        int ret = 0;
695        fu16_t maxsiglen = 0;
696
697        tlvlist = aim_readtlvchain(bs);
698
699        if (aim_gettlv(tlvlist, 0x0001, 1))
700                maxsiglen = aim_gettlv16(tlvlist, 0x0001, 1);
701
702        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
703                ret = userfunc(sess, rx, maxsiglen);
704
705        aim_freetlvchain(&tlvlist);
706
707        return ret;
708}
709
710/* Subtype 0x0006 */
711static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
712{
713        aim_userinfo_t userinfo;
714        char *text_encoding = NULL, *text = NULL;
715        aim_rxcallback_t userfunc;
716        aim_tlvlist_t *tlvlist;
717        aim_snac_t *origsnac = NULL;
718        struct aim_priv_inforeq *inforeq;
719        int ret = 0;
720
721        origsnac = aim_remsnac(sess, snac->id);
722
723        if (!origsnac || !origsnac->data) {
724                faimdprintf(sess, 0, "parse_userinfo_middle: major problem: no snac stored!\n");
725                return 0;
726        }
727
728        inforeq = (struct aim_priv_inforeq *)origsnac->data;
729
730        if ((inforeq->infotype != AIM_GETINFO_GENERALINFO) &&
731                        (inforeq->infotype != AIM_GETINFO_AWAYMESSAGE) &&
732                        (inforeq->infotype != AIM_GETINFO_CAPABILITIES)) {
733                faimdprintf(sess, 0, "parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype);
734                return 0;
735        }
736
737        aim_extractuserinfo(sess, bs, &userinfo);
738
739        tlvlist = aim_readtlvchain(bs);
740
741        /*
742         * Depending on what informational text was requested, different
743         * TLVs will appear here.
744         *
745         * Profile will be 1 and 2, away message will be 3 and 4, caps
746         * will be 5.
747         */
748        if (inforeq->infotype == AIM_GETINFO_GENERALINFO) {
749                text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1);
750                text = aim_gettlv_str(tlvlist, 0x0002, 1);
751        } else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) {
752                text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1);
753                text = aim_gettlv_str(tlvlist, 0x0004, 1);
754        } else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) {
755                aim_tlv_t *ct;
756
757                if ((ct = aim_gettlv(tlvlist, 0x0005, 1))) {
758                        aim_bstream_t cbs;
759
760                        aim_bstream_init(&cbs, ct->value, ct->length);
761
762                        userinfo.capabilities = aim_getcap(sess, &cbs, ct->length);
763                        userinfo.present = AIM_USERINFO_PRESENT_CAPABILITIES;
764                }
765        }
766
767        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
768                ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text);
769
770        free(text_encoding);
771        free(text);
772
773        aim_freetlvchain(&tlvlist);
774
775        if (origsnac)
776                free(origsnac->data);
777        free(origsnac);
778
779        return ret;
780}
781
782/*
783 * Subtype 0x0009 - Set directory profile data.
784 *
785 * This is not the same as aim_bos_setprofile!
786 * privacy: 1 to allow searching, 0 to disallow.
787 *
788 */
789faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy) 
790{
791        aim_frame_t *fr;
792        aim_snacid_t snacid;
793        aim_tlvlist_t *tl = NULL;
794
795        aim_addtlvtochain16(&tl, 0x000a, privacy);
796
797        if (first)
798                aim_addtlvtochain_raw(&tl, 0x0001, strlen(first), first);
799        if (last)
800                aim_addtlvtochain_raw(&tl, 0x0002, strlen(last), last);
801        if (middle)
802                aim_addtlvtochain_raw(&tl, 0x0003, strlen(middle), middle);
803        if (maiden)
804                aim_addtlvtochain_raw(&tl, 0x0004, strlen(maiden), maiden);
805
806        if (state)
807                aim_addtlvtochain_raw(&tl, 0x0007, strlen(state), state);
808        if (city)
809                aim_addtlvtochain_raw(&tl, 0x0008, strlen(city), city);
810
811        if (nickname)
812                aim_addtlvtochain_raw(&tl, 0x000c, strlen(nickname), nickname);
813        if (zip)
814                aim_addtlvtochain_raw(&tl, 0x000d, strlen(zip), zip);
815
816        if (street)
817                aim_addtlvtochain_raw(&tl, 0x0021, strlen(street), street);
818
819        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))
820                return -ENOMEM;
821
822        snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0);
823
824        aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid);
825        aim_writetlvchain(&fr->data, &tl);
826        aim_freetlvchain(&tl);
827
828        aim_tx_enqueue(sess, fr);
829
830        return 0;
831}
832
833/*
834 * Subtype 0x000f
835 *
836 * XXX pass these in better
837 *
838 */
839faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy)
840{
841        aim_frame_t *fr;
842        aim_snacid_t snacid;
843        aim_tlvlist_t *tl = NULL;
844
845        /* ?? privacy ?? */
846        aim_addtlvtochain16(&tl, 0x000a, privacy);
847
848        if (interest1)
849                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest1), interest1);
850        if (interest2)
851                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest2), interest2);
852        if (interest3)
853                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest3), interest3);
854        if (interest4)
855                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest4), interest4);
856        if (interest5)
857                aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest5), interest5);
858
859        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl))))
860                return -ENOMEM;
861
862        snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0);
863
864        aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0);
865        aim_writetlvchain(&fr->data, &tl);
866        aim_freetlvchain(&tl);
867
868        aim_tx_enqueue(sess, fr);
869
870        return 0;
871}
872
873static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
874{
875
876        if (snac->subtype == 0x0003)
877                return rights(sess, mod, rx, snac, bs);
878        else if (snac->subtype == 0x0006)
879                return userinfo(sess, mod, rx, snac, bs);
880
881        return 0;
882}
883
884faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod)
885{
886
887        mod->family = 0x0002;
888        mod->version = 0x0001;
889        mod->toolid = 0x0101;
890        mod->toolversion = 0x047b;
891        mod->flags = 0;
892        strncpy(mod->name, "locate", sizeof(mod->name));
893        mod->snachandler = snachandler;
894
895        return 0;
896}
Note: See TracBrowser for help on using the repository browser.