comparison libpurple/protocols/oscar/family_locate.c @ 29418:365b90fa23cf

This patch comes from the combined work of contributors minstrel, NightFox, bob007, salieff, and nops (these are their trac usernames). I have made some minor tweaks to the patch, but these shouldn't be a problem. This patch needs some TLC before we can merge it anywhere else; it adds API so it must hit im.pidgin.pidgin.next.minor before hitting im.pidgin.pidgin. Refs #4508.
author John Bailey <rekkanoryo@rekkanoryo.org>
date Thu, 13 Nov 2008 17:04:53 +0000
parents 46cc31494ff4
children 2c95b7c57ebb
comparison
equal deleted inserted replaced
24404:f18f37a62971 29418:365b90fa23cf
163 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, 163 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
164 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 164 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
165 {OSCAR_CAPABILITY_GAMES2, 165 {OSCAR_CAPABILITY_GAMES2,
166 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, 166 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
167 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 167 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
168
169 /* New format of caps (xtraz icons) */
170 {OSCAR_CAPABILITY_NEWCAPS,
171 {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
172 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
173
174 /* Support xtraz statuses */
175 {OSCAR_CAPABILITY_XTRAZ,
176 {0x1a, 0x09, 0x3c, 0x6c, 0xd7, 0xFD, 0x4e, 0xc5,
177 0x9d, 0x51, 0xa6, 0x47, 0x4e, 0x34, 0xf5, 0xa0}},
168 178
169 {OSCAR_CAPABILITY_SENDBUDDYLIST, 179 {OSCAR_CAPABILITY_SENDBUDDYLIST,
170 {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, 180 {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1,
171 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, 181 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
172 182
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
239 249
240 {OSCAR_CAPABILITY_LAST, 250 {OSCAR_CAPABILITY_LAST,
241 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 251 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
253 };
254
255 #define AIM_CUSTOM_ICONS_COUNT 35
256
257 static const struct {
258 char *filename;
259 char *descriptivename;
260 guint8 data[16];
261 } aim_custom_icons[AIM_CUSTOM_ICONS_COUNT] = {
262 /* empty X-Status for the case when customicon == 0 */
263 {NULL, NULL,
264 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
266
267 {"xstatus_thinking", "Thinking",
268 {0x3f, 0xb0, 0xbd, 0x36, 0xaf, 0x3b, 0x4a, 0x60,
269 0x9e, 0xef, 0xcf, 0x19, 0x0f, 0x6a, 0x5a, 0x7f}},
270
271 {"xstatus_busy", "Busy",
272 {0x48, 0x8e, 0x14, 0x89, 0x8a, 0xca, 0x4a, 0x08,
273 0x82, 0xaa, 0x77, 0xce, 0x7a, 0x16, 0x52, 0x08}},
274
275 {"xstatus_shopping", "Shopping",
276 {0x63, 0x62, 0x73, 0x37, 0xa0, 0x3f, 0x49, 0xff,
277 0x80, 0xe5, 0xf7, 0x09, 0xcd, 0xe0, 0xa4, 0xee}},
278
279 {"xstatus_typing", "Typing",
280 {0x63, 0x4f, 0x6b, 0xd8 ,0xad, 0xd2, 0x4a, 0xa1,
281 0xaa, 0xb9, 0x11, 0x5b, 0xc2, 0x6d, 0x05, 0xa1}},
282
283 {"xstatus_question", "Question Mark",
284 {0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0,
285 0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64}},
286
287 {"xstatus_angry", "Angry",
288 {0x01, 0xd8, 0xd7, 0xee, 0xac, 0x3b, 0x49, 0x2a,
289 0xa5, 0x8d, 0xd3, 0xd8, 0x77, 0xe6, 0x6b, 0x92}},
290
291 {"xstatus_eating", "Eating",
292 {0xf8, 0xe8, 0xd7, 0xb2, 0x82, 0xc4, 0x41, 0x42,
293 0x90, 0xf8, 0x10, 0xc6, 0xce, 0x0a, 0x89, 0xa6}},
294
295 {"xstatus_cinema", "Cinema",
296 {0x10, 0x7a, 0x9a, 0x18, 0x12, 0x32, 0x4d, 0xa4,
297 0xb6, 0xcd, 0x08, 0x79, 0xdb, 0x78, 0x0f, 0x09}},
298
299 {"xstatus_sick", "Sick",
300 {0x1f, 0x7a, 0x40, 0x71, 0xbf, 0x3b, 0x4e, 0x60,
301 0xbc, 0x32, 0x4c, 0x57, 0x87, 0xb0, 0x4c, 0xf1}},
302
303 {"xstatus_crap", "Unknown 1",
304 {0x2c, 0xe0, 0xe4, 0xe5, 0x7c, 0x64, 0x43, 0x70,
305 0x9c, 0x3a, 0x7a, 0x1c, 0xe8, 0x78, 0xa7, 0xdc}},
306
307 {"xstatus_iron", "Unknown 2",
308 {0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27,
309 0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97}},
310
311 {"xstatus_bathing", "Bathing",
312 {0x5a, 0x58, 0x1e, 0xa1, 0xe5, 0x80, 0x43, 0x0c,
313 0xa0, 0x6f, 0x61, 0x22, 0x98, 0xb7, 0xe4, 0xc7}},
314
315 {"xstatus_tv", "Watching TV",
316 {0x80, 0x53, 0x7d, 0xe2, 0xa4, 0x67, 0x4a, 0x76,
317 0xb3, 0x54, 0x6d, 0xfd, 0x07, 0x5f, 0x5e, 0xc6}},
318
319 {"xstatus_fun", "Having fun",
320 {0x6f, 0x49, 0x30, 0x98, 0x4f, 0x7c, 0x4a, 0xff,
321 0xa2, 0x76, 0x34, 0xa0, 0x3b, 0xce, 0xae, 0xa7}},
322
323 {"xstatus_sleeping", "Sleeping",
324 {0x78, 0x5e, 0x8c, 0x48, 0x40, 0xd3, 0x4c, 0x65,
325 0x88, 0x6f, 0x04, 0xcf, 0x3f, 0x3f, 0x43, 0xdf}},
326
327 {"xstatus_pda", "PDA device",
328 {0x10, 0x11, 0x17, 0xc9, 0xa3, 0xb0, 0x40, 0xf9,
329 0x81, 0xac, 0x49, 0xe1, 0x59, 0xfb, 0xd5, 0xd4}},
330
331 {"xstatus_heart", "In love",
332 {0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48,
333 0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80}},
334
335 {"xstatus_tired", "Tired",
336 {0x83, 0xc9, 0xb7, 0x8e, 0x77, 0xe7, 0x43, 0x78,
337 0xb2, 0xc5, 0xfb, 0x6c, 0xfc, 0xc3, 0x5b, 0xec}},
338
339 {"xstatus_friends", "Friends",
340 {0xf1, 0x8a, 0xb5, 0x2e, 0xdc, 0x57, 0x49, 0x1d,
341 0x99, 0xdc, 0x64, 0x44, 0x50, 0x24, 0x57, 0xaf}},
342
343 {"xstatus_phone", "On the phone",
344 {0x12, 0x92, 0xe5, 0x50, 0x1b, 0x64, 0x4f, 0x66,
345 0xb2, 0x06, 0xb2, 0x9a, 0xf3, 0x78, 0xe4, 0x8d}},
346
347 {"xstatus_surfing", "Surfing",
348 {0xa6, 0xed, 0x55, 0x7e, 0x6b, 0xf7, 0x44, 0xd4,
349 0xa5, 0xd4, 0xd2, 0xe7, 0xd9, 0x5c, 0xe8, 0x1f}},
350
351 {"xstatus_mobile", "Cell phone",
352 {0x16, 0x0c, 0x60, 0xbb, 0xdd, 0x44, 0x43, 0xf3,
353 0x91, 0x40, 0x05, 0x0f, 0x00, 0xe6, 0xc0, 0x09}},
354
355 {"xstatus_google", "Googling",
356 {0xd4, 0xe2, 0xb0, 0xba, 0x33, 0x4e, 0x4f, 0xa5,
357 0x98, 0xd0, 0x11, 0x7d, 0xbf, 0x4d, 0x3c, 0xc8}},
358
359 {"xstatus_party", "Party",
360 {0xe6, 0x01, 0xe4, 0x1c, 0x33, 0x73, 0x4b, 0xd1,
361 0xbc, 0x06, 0x81, 0x1d, 0x6c, 0x32, 0x3d, 0x81}},
362
363 {"xstatus_coffee", "Coffee",
364 {0x1b, 0x78, 0xae, 0x31, 0xfa, 0x0b, 0x4d, 0x38,
365 0x93, 0xd1, 0x99, 0x7e, 0xee, 0xaf, 0xb2, 0x18}},
366
367 {"xstatus_gaming", "Playing",
368 {0xd4, 0xa6, 0x11, 0xd0, 0x8f, 0x01, 0x4e, 0xc0,
369 0x92, 0x23, 0xc5, 0xb6, 0xbe, 0xc6, 0xcc, 0xf0}},
370
371 {"xstatus_internet", "Internet",
372 {0x12, 0xd0, 0x7e, 0x3e, 0xf8, 0x85, 0x48, 0x9e,
373 0x8e, 0x97, 0xa7, 0x2a, 0x65, 0x51, 0xe5, 0x8d}},
374
375 {"xstatus_zzz", "Snoozing",
376 {0x64, 0x43, 0xc6, 0xaf, 0x22, 0x60, 0x45, 0x17,
377 0xb5, 0x8c, 0xd7, 0xdf, 0x8e, 0x29, 0x03, 0x52}},
378
379 {"xstatus_writing", "Writing",
380 {0x00, 0x72, 0xd9, 0x08, 0x4a, 0xd1, 0x43, 0xdd,
381 0x91, 0x99, 0x6f, 0x02, 0x69, 0x66, 0x02, 0x6f}},
382
383 {"xstatus_beer", "Drinking",
384 {0x8c, 0x50, 0xdb, 0xae, 0x81, 0xed, 0x47, 0x86,
385 0xac, 0xca, 0x16, 0xcc, 0x32, 0x13, 0xc7, 0xb7}},
386
387 {"xstatus_music", "Music",
388 {0x61, 0xbe, 0xe0, 0xdd, 0x8b, 0xdd, 0x47, 0x5d,
389 0x8d, 0xee, 0x5f, 0x4b, 0xaa, 0xcf, 0x19, 0xa7}},
390
391 {"xstatus_studying", "Studying",
392 {0x60, 0x9d, 0x52, 0xf8, 0xa2, 0x9a, 0x49, 0xa6,
393 0xb2, 0xa0, 0x25, 0x24, 0xc5, 0xe9, 0xd2, 0x60}},
394
395 {"xstatus_engineering", "Engineering",
396 {0xba, 0x74, 0xdb, 0x3e, 0x9e, 0x24, 0x43, 0x4b,
397 0x87, 0xb6, 0x2f, 0x6b, 0x8d, 0xfe, 0xe5, 0x0f}},
398
399 {"xstatus_crapping", "In the restroom",
400 {0x16, 0xf5, 0xb7, 0x6f, 0xa9, 0xd2, 0x40, 0x35,
401 0x8c, 0xc5, 0xc0, 0x84, 0x70, 0x3c, 0x98, 0xfa}}
243 }; 402 };
244 403
245 /* 404 /*
246 * Add the userinfo to our linked list. If we already have userinfo 405 * Add the userinfo to our linked list. If we already have userinfo
247 * for this buddy, then just overwrite parts of the old data. 406 * for this buddy, then just overwrite parts of the old data.
276 cur->onlinesince = userinfo->onlinesince; 435 cur->onlinesince = userinfo->onlinesince;
277 if (userinfo->sessionlen != 0) 436 if (userinfo->sessionlen != 0)
278 cur->sessionlen = userinfo->sessionlen; 437 cur->sessionlen = userinfo->sessionlen;
279 if (userinfo->capabilities != 0) 438 if (userinfo->capabilities != 0)
280 cur->capabilities = userinfo->capabilities; 439 cur->capabilities = userinfo->capabilities;
440 if (userinfo->customicon != 0)
441 cur->customicon = userinfo->customicon;
442
281 cur->present |= userinfo->present; 443 cur->present |= userinfo->present;
282 444
283 if (userinfo->iconcsumlen > 0) { 445 if (userinfo->iconcsumlen > 0) {
284 g_free(cur->iconcsum); 446 g_free(cur->iconcsum);
285 cur->iconcsum = (guint8 *)g_malloc(userinfo->iconcsumlen); 447 cur->iconcsum = (guint8 *)g_malloc(userinfo->iconcsumlen);
467 cap[4], cap[5], 629 cap[4], cap[5],
468 cap[6], cap[7], 630 cap[6], cap[7],
469 cap[8], cap[9], 631 cap[8], cap[9],
470 cap[10], cap[11], cap[12], cap[13], 632 cap[10], cap[11], cap[12], cap[13],
471 cap[14], cap[15]); 633 cap[14], cap[15]);
472
473 g_free(cap); 634 g_free(cap);
474 } 635 }
475 636
476 return flags; 637 return flags;
638 }
639
640 gint32
641 aim_get_custom_icon(OscarData *od, ByteStream *bs, int len)
642 {
643 int offset;
644 gint32 result = -1;
645
646 for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) {
647 /* check wheather this capability is a custom user icon */
648 guint8 *cap;
649 int i;
650
651 cap = byte_stream_getraw(bs, 0x10);
652
653 for (i = 1; i < AIM_CUSTOM_ICONS_COUNT; i++) {
654 if (memcmp(&aim_custom_icons[i].data, cap, 0x10) == 0) {
655 purple_debug_misc("oscar", "Custom user icon: %s\n", aim_custom_icons[i].descriptivename);
656 result = i;
657 break; /* should only match once... */
658 }
659 }
660 g_free(cap);
661 }
662
663 return result;
477 } 664 }
478 665
479 guint32 666 guint32
480 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len) 667 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len)
481 { 668 {
564 g_free(info->itmsurl_encoding); 751 g_free(info->itmsurl_encoding);
565 g_free(info->away); 752 g_free(info->away);
566 g_free(info->away_encoding); 753 g_free(info->away_encoding);
567 } 754 }
568 755
756 #define ICQMOODS_COUNT 23
757
758 static const struct {
759 char *mood;
760 gint32 icon_num;
761 } icqmoods[ICQMOODS_COUNT] = {
762 {"icqmood1", 12},
763 {"icqmood2", 18},
764 {"icqmood3", 24},
765 {"icqmood4", 30},
766 {"icqmood5", 1},
767 {"icqmood6", 7},
768 {"icqmood7", 13},
769 {"icqmood8", 19},
770 {"icqmood9", 25},
771 {"icqmood10", 31},
772 {"icqmood11", 11},
773 {"icqmood12", 8},
774 {"icqmood13", 14},
775 {"icqmood14", 20},
776 {"icqmood15", 26},
777 {"icqmood16", 32},
778 {"icqmood17", 9},
779 {"icqmood18", 15},
780 {"icqmood19", 21},
781 {"icqmood20", 27},
782 {"icqmood21", 33},
783 {"icqmood22", 10},
784 {"icqmood23", 6},
785 };
786
569 /* 787 /*
570 * AIM is fairly regular about providing user info. This is a generic 788 * AIM is fairly regular about providing user info. This is a generic
571 * routine to extract it in its standard form. 789 * routine to extract it in its standard form.
572 */ 790 */
573 int 791 int
604 * Parse out the Type-Length-Value triples as they're found. 822 * Parse out the Type-Length-Value triples as they're found.
605 */ 823 */
606 for (curtlv = 0; curtlv < tlvcnt; curtlv++) { 824 for (curtlv = 0; curtlv < tlvcnt; curtlv++) {
607 guint16 type, length; 825 guint16 type, length;
608 int endpos; 826 int endpos;
827 int curpos;
609 828
610 type = byte_stream_get16(bs); 829 type = byte_stream_get16(bs);
611 length = byte_stream_get16(bs); 830 length = byte_stream_get16(bs);
612 831 curpos = byte_stream_curpos(bs);
613 endpos = byte_stream_curpos(bs) + MIN(length, byte_stream_empty(bs)); 832 endpos = curpos + MIN(length, byte_stream_empty(bs));
614 833
615 if (type == 0x0001) { 834 if (type == 0x0001) {
616 /* 835 /*
617 * User flags 836 * User flags
618 * 837 *
723 /* 942 /*
724 * OSCAR Capability information 943 * OSCAR Capability information
725 */ 944 */
726 outinfo->capabilities |= aim_locate_getcaps(od, bs, length); 945 outinfo->capabilities |= aim_locate_getcaps(od, bs, length);
727 outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES; 946 outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
947 byte_stream_setpos(bs, curpos);
948 outinfo->customicon = aim_get_custom_icon(od, bs, length);
728 949
729 } else if (type == 0x000e) { 950 } else if (type == 0x000e) {
730 /* 951 /*
731 * AOL capability information 952 * AOL capability information
732 */ 953 */
851 outinfo->itmsurl_len = 0; 1072 outinfo->itmsurl_len = 0;
852 outinfo->itmsurl = g_strdup(""); 1073 outinfo->itmsurl = g_strdup("");
853 outinfo->itmsurl_encoding = NULL; 1074 outinfo->itmsurl_encoding = NULL;
854 } 1075 }
855 } break; 1076 } break;
1077
1078 case 0x000e: { /* ICQ mood */
1079 char *mood;
1080 gint32 i;
1081 gint32 icon_num = -1;
1082
1083 mood = byte_stream_getstr(bs, length2);
1084
1085 for (i = 0; i < ICQMOODS_COUNT; i++)
1086 if (!strcmp(mood, icqmoods[i].mood)) {
1087 icon_num = icqmoods[i].icon_num;
1088 break; /* should only match once... */
1089 }
1090
1091 if (icon_num >= 0)
1092 outinfo->customicon = icon_num;
1093 else
1094 purple_debug_warning("oscar", "Unknown icqmood: %s", mood);
1095
1096 g_free(mood);
1097 } break;
856 } 1098 }
857 1099
858 /* Save ourselves. */ 1100 /* Save ourselves. */
859 byte_stream_setpos(bs, endpos2); 1101 byte_stream_setpos(bs, endpos2);
860 } 1102 }
931 aim_tlvlist_add_32(&tlvlist, 0x000a, info->icqinfo.ipaddr); 1173 aim_tlvlist_add_32(&tlvlist, 0x000a, info->icqinfo.ipaddr);
932 } 1174 }
933 #endif 1175 #endif
934 1176
935 if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) 1177 if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
936 aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities); 1178 aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities, info->customicon);
937 1179
938 if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) 1180 if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
939 aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); 1181 aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);
940 1182
941 byte_stream_put16(bs, aim_tlvlist_count(tlvlist)); 1183 byte_stream_put16(bs, aim_tlvlist_count(tlvlist));
1138 GSList *tlvlist = NULL; 1380 GSList *tlvlist = NULL;
1139 1381
1140 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) 1382 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
1141 return -EINVAL; 1383 return -EINVAL;
1142 1384
1143 aim_tlvlist_add_caps(&tlvlist, 0x0005, caps); 1385 aim_tlvlist_add_caps(&tlvlist, 0x0005, caps, purple_account_get_int(purple_connection_get_account(od->gc), "customicon", -1));
1144 1386
1145 byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); 1387 byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
1146 1388
1147 snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0); 1389 snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0);
1148 1390
1224 /* Caps will be 5 */ 1466 /* Caps will be 5 */
1225 if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) { 1467 if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) {
1226 ByteStream cbs; 1468 ByteStream cbs;
1227 byte_stream_init(&cbs, tlv->value, tlv->length); 1469 byte_stream_init(&cbs, tlv->value, tlv->length);
1228 userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length); 1470 userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
1471 byte_stream_rewind(&cbs);
1472 userinfo->customicon = aim_get_custom_icon(od, &cbs, tlv->length);
1229 userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES; 1473 userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;
1230 } 1474 }
1231 aim_tlvlist_free(tlvlist); 1475 aim_tlvlist_free(tlvlist);
1232 1476
1233 aim_locate_adduserinfo(od, userinfo); 1477 aim_locate_adduserinfo(od, userinfo);
1451 mod->snachandler = snachandler; 1695 mod->snachandler = snachandler;
1452 mod->shutdown = locate_shutdown; 1696 mod->shutdown = locate_shutdown;
1453 1697
1454 return 0; 1698 return 0;
1455 } 1699 }
1700
1701 guint32
1702 aim_get_custom_icons_count()
1703 {
1704 return AIM_CUSTOM_ICONS_COUNT;
1705 }
1706
1707 char*
1708 aim_get_custom_icon_filename(gint32 no)
1709 {
1710 if (no >= AIM_CUSTOM_ICONS_COUNT || no < 1)
1711 return NULL;
1712 return aim_custom_icons[no].filename;
1713 }
1714
1715 char*
1716 aim_get_custom_icon_descriptivename(gint32 no)
1717 {
1718 if (no >= AIM_CUSTOM_ICONS_COUNT || no < 1)
1719 return NULL;
1720 return aim_custom_icons[no].descriptivename;
1721 }
1722
1723 guint8*
1724 aim_get_custom_icon_data(gint32 no)
1725 {
1726 if (no >= AIM_CUSTOM_ICONS_COUNT || no < 1)
1727 return NULL;
1728 return (guint8 *)aim_custom_icons[no].data;
1729 }