The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / libpurple / protocols / oscar / family_icq.c~ @ a274da4f

History | View | Annotate | Download (24.2 KB)

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 0x0015 - Encapsulated ICQ.
23
 *
24
 */
25

    
26
#include "encoding.h"
27
#include "oscar.h"
28

    
29
#define AIM_ICQ_INFO_REQUEST 0x04b2
30
#define AIM_ICQ_ALIAS_REQUEST 0x04ba
31

    
32
static
33
int compare_icq_infos(gconstpointer a, gconstpointer b)
34
{
35
	const struct aim_icq_info* aa = a;
36
	const guint16* bb = b;
37
	return aa->reqid - *bb;
38
}
39

    
40
static void aim_icq_freeinfo(struct aim_icq_info *info) {
41
	int i;
42

    
43
	if (!info)
44
		return;
45
	g_free(info->nick);
46
	g_free(info->first);
47
	g_free(info->last);
48
	g_free(info->email);
49
	g_free(info->homecity);
50
	g_free(info->homestate);
51
	g_free(info->homephone);
52
	g_free(info->homefax);
53
	g_free(info->homeaddr);
54
	g_free(info->mobile);
55
	g_free(info->homezip);
56
	g_free(info->personalwebpage);
57
	if (info->email2)
58
		for (i = 0; i < info->numaddresses; i++)
59
			g_free(info->email2[i]);
60
	g_free(info->email2);
61
	g_free(info->workcity);
62
	g_free(info->workstate);
63
	g_free(info->workphone);
64
	g_free(info->workfax);
65
	g_free(info->workaddr);
66
	g_free(info->workzip);
67
	g_free(info->workcompany);
68
	g_free(info->workdivision);
69
	g_free(info->workposition);
70
	g_free(info->workwebpage);
71
	g_free(info->info);
72
	g_free(info->status_note_title);
73
	g_free(info->auth_request_reason);
74
}
75

    
76
static
77
int error(OscarData *od, aim_modsnac_t *error_snac, ByteStream *bs)
78
{
79
	aim_snac_t *original_snac = aim_remsnac(od, error_snac->id);
80
	guint16 *request_type;
81
	GSList *original_info_ptr;
82
	struct aim_icq_info *original_info;
83
	guint16 reason;
84
	gchar *uin;
85

    
86
	if (!original_snac || (original_snac->family != SNAC_FAMILY_ICQ) || !original_snac->data) {
87
		purple_debug_misc("oscar", "icq: the original snac for the error packet was not found");
88
		g_free(original_snac);
89
		return 0;
90
	}
91

    
92
	request_type = original_snac->data;
93
	original_info_ptr = g_slist_find_custom(od->icq_info, &original_snac->id, compare_icq_infos);
94

    
95
	if (!original_info_ptr) {
96
		purple_debug_misc("oscar", "icq: the request info for the error packet was not found");
97
		g_free(original_snac);
98
		return 0;
99
	}
100

    
101
	original_info = original_info_ptr->data;
102

    
103
	reason = byte_stream_get16(bs);
104
	uin = g_strdup_printf("%u", original_info->uin);
105
	switch (*request_type) {
106
		case AIM_ICQ_INFO_REQUEST:
107
			oscar_user_info_display_error(od, reason, uin);
108
			break;
109
		case AIM_ICQ_ALIAS_REQUEST:
110
			/* Couldn't retrieve an alias for the buddy requesting authorization; have to make do with UIN only. */
111
			if (original_info->for_auth_request)
112
				oscar_auth_recvrequest(od->gc, uin, NULL, original_info->auth_request_reason);
113
			break;
114
		default:
115
			purple_debug_misc("oscar", "icq: got an error packet with unknown request type %u", *request_type);
116
			break;
117
	}
118

    
119
	aim_icq_freeinfo(original_info);
120
	od->icq_info = g_slist_remove(od->icq_info, original_info_ptr);
121
	g_free(original_snac->data);
122
	g_free(original_snac);
123
	return 1;
124
}
125

    
126
int
127
aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
128
{
129
	FlapConnection *conn;
130
	ByteStream bs;
131
	aim_snacid_t snacid;
132
	int bslen;
133

    
134
	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
135
		return -EINVAL;
136

    
137
	bslen = 2+4+2+2+2+2+2+1+1+1+1+1+1;
138

    
139
	byte_stream_new(&bs, 4 + bslen);
140

    
141
	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
142

    
143
	/* For simplicity, don't bother using a tlvlist */
144
	byte_stream_put16(&bs, 0x0001);
145
	byte_stream_put16(&bs, bslen);
146

    
147
	byte_stream_putle16(&bs, bslen - 2);
148
	byte_stream_putuid(&bs, od);
149
	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
150
	byte_stream_putle16(&bs, snacid); /* eh. */
151
	byte_stream_putle16(&bs, 0x0c3a); /* shrug. */
152
	byte_stream_putle16(&bs, 0x030c);
153
	byte_stream_putle16(&bs, 0x0001);
154
	byte_stream_putle8(&bs, webaware);
155
	byte_stream_putle8(&bs, 0xf8);
156
	byte_stream_putle8(&bs, 0x02);
157
	byte_stream_putle8(&bs, 0x01);
158
	byte_stream_putle8(&bs, 0x00);
159
	byte_stream_putle8(&bs, !auth_required);
160

    
161
	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
162

    
163
	byte_stream_destroy(&bs);
164

    
165
	return 0;
166
}
167

    
168
/**
169
 * Change your ICQ password.
170
 *
171
 * @param od The oscar session
172
 * @param passwd The new password.  If this is longer than 8 characters it
173
 *        will be truncated.
174
 * @return Return 0 if no errors, otherwise return the error number.
175
 */
176
int aim_icq_changepasswd(OscarData *od, const char *passwd)
177
{
178
	FlapConnection *conn;
179
	ByteStream bs;
180
	aim_snacid_t snacid;
181
	int bslen, passwdlen,cjs,test_num;
182
	char * temp_psswd;
183
 
184
	if (!passwd)
185
		return -EINVAL;
186

    
187
	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
188
		return -EINVAL;
189

    
190
	passwdlen = strlen(passwd);
191
	if (passwdlen > MAXICQPASSLEN)
192
		passwdlen = MAXICQPASSLEN;
193
	
194
	//Casey Santilli
195
	printf("Got to password change\n");
196
	temp_psswd = passwd;
197
	for(cjs=0;cjs<passwdlen;cjs++){
198
	test_num = temp_psswd[cjs];
199
	printf("made it inside for loop, char is %c , casted num: char %d \n", temp_psswd[cjs], test_num);
200
		if( (test_num<32)  || (test_num>127) ){
201
			return -EINVAL;
202
			printf("The illegal character is %c\n", temp_psswd[cjs]);
203
			//get that character out of here
204
		}
205
	}
206
	bslen = 2+4+2+2+2+2+passwdlen+1;
207

    
208
	byte_stream_new(&bs, 4 + bslen);
209

    
210
	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
211

    
212
	/* For simplicity, don't bother using a tlvlist */
213
	byte_stream_put16(&bs, 0x0001);
214
	byte_stream_put16(&bs, bslen);
215

    
216
	byte_stream_putle16(&bs, bslen - 2);
217
	byte_stream_putuid(&bs, od);
218
	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
219
	byte_stream_putle16(&bs, snacid); /* eh. */
220
	byte_stream_putle16(&bs, 0x042e); /* shrug. */
221
	byte_stream_putle16(&bs, passwdlen+1);
222
	byte_stream_putraw(&bs, (const guint8 *)passwd, passwdlen);
223
	byte_stream_putle8(&bs, '\0');
224

    
225
	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
226

    
227
	byte_stream_destroy(&bs);
228

    
229
	return 0;
230
}
231

    
232
int aim_icq_getallinfo(OscarData *od, const char *uin)
233
{
234
	FlapConnection *conn;
235
	ByteStream bs;
236
	aim_snacid_t snacid;
237
	int bslen;
238
	struct aim_icq_info *info;
239
	guint16 request_type = AIM_ICQ_INFO_REQUEST;
240

    
241
	if (!uin || uin[0] < '0' || uin[0] > '9')
242
		return -EINVAL;
243

    
244
	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
245
		return -EINVAL;
246

    
247
	bslen = 2 + 4 + 2 + 2 + 2 + 4;
248

    
249
	byte_stream_new(&bs, 4 + bslen);
250

    
251
	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
252

    
253
	/* For simplicity, don't bother using a tlvlist */
254
	byte_stream_put16(&bs, 0x0001);
255
	byte_stream_put16(&bs, bslen);
256

    
257
	byte_stream_putle16(&bs, bslen - 2);
258
	byte_stream_putuid(&bs, od);
259
	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
260
	byte_stream_putle16(&bs, snacid); /* eh. */
261
	byte_stream_putle16(&bs, request_type); /* shrug. */
262
	byte_stream_putle32(&bs, atoi(uin));
263

    
264
	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
265

    
266
	byte_stream_destroy(&bs);
267

    
268
	/* Keep track of this request and the ICQ number and request ID */
269
	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
270
	info->reqid = snacid;
271
	info->uin = atoi(uin);
272
	od->icq_info = g_slist_prepend(od->icq_info, info);
273

    
274
	return 0;
275
}
276

    
277
int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason)
278
{
279
	FlapConnection *conn;
280
	ByteStream bs;
281
	aim_snacid_t snacid;
282
	int bslen;
283
	struct aim_icq_info *info;
284
	guint16 request_type = AIM_ICQ_ALIAS_REQUEST;
285

    
286
	if (!uin || uin[0] < '0' || uin[0] > '9')
287
		return -EINVAL;
288

    
289
	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
290
		return -EINVAL;
291

    
292
	purple_debug_info("oscar", "Requesting ICQ alias for %s\n", uin);
293

    
294
	bslen = 2 + 4 + 2 + 2 + 2 + 4;
295

    
296
	byte_stream_new(&bs, 4 + bslen);
297

    
298
	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
299

    
300
	/* For simplicity, don't bother using a tlvlist */
301
	byte_stream_put16(&bs, 0x0001);
302
	byte_stream_put16(&bs, bslen);
303

    
304
	byte_stream_putle16(&bs, bslen - 2);
305
	byte_stream_putuid(&bs, od);
306
	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
307
	byte_stream_putle16(&bs, snacid); /* eh. */
308
	byte_stream_putle16(&bs, request_type); /* shrug. */
309
	byte_stream_putle32(&bs, atoi(uin));
310

    
311
	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
312

    
313
	byte_stream_destroy(&bs);
314

    
315
	/* Keep track of this request and the ICQ number and request ID */
316
	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
317
	info->reqid = snacid;
318
	info->uin = atoi(uin);
319
	info->for_auth_request = for_auth_request;
320
	info->auth_request_reason = g_strdup(auth_request_reason);
321
	od->icq_info = g_slist_prepend(od->icq_info, info);
322

    
323
	return 0;
324
}
325

    
326
/*
327
 * Send an SMS message.  This is the non-US way.  The US-way is to IM
328
 * their cell phone number (+19195551234).
329
 *
330
 * We basically construct and send an XML message.  The format is:
331
 * <icq_sms_message>
332
 *   <destination>full_phone_without_leading_+</destination>
333
 *   <text>message</text>
334
 *   <codepage>1252</codepage>
335
 *   <senders_UIN>self_uin</senders_UIN>
336
 *   <senders_name>self_name</senders_name>
337
 *   <delivery_receipt>Yes|No</delivery_receipt>
338
 *   <time>Wkd, DD Mmm YYYY HH:MM:SS TMZ</time>
339
 * </icq_sms_message>
340
 *
341
 * Yeah hi Peter, whaaaat's happening.  If there's any way to use
342
 * a codepage other than 1252 that would be great.  Thaaaanks.
343
 */
344
int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias)
345
{
346
	FlapConnection *conn;
347
	PurpleAccount *account;
348
	ByteStream bs;
349
	aim_snacid_t snacid;
350
	int bslen, xmllen;
351
	char *xml;
352
	const char *timestr, *username;
353
	time_t t;
354
	struct tm *tm;
355
	gchar *stripped;
356

    
357
	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
358
		return -EINVAL;
359

    
360
	if (!name || !msg || !alias)
361
		return -EINVAL;
362

    
363
	account = purple_connection_get_account(od->gc);
364
	username = purple_account_get_username(account);
365

    
366
	time(&t);
367
	tm = gmtime(&t);
368
	timestr = purple_utf8_strftime("%a, %d %b %Y %T %Z", tm);
369

    
370
	stripped = purple_markup_strip_html(msg);
371

    
372
	/* The length of xml included the null terminating character */
373
	xmllen = 209 + strlen(name) + strlen(stripped) + strlen(username) + strlen(alias) + strlen(timestr) + 1;
374

    
375
	xml = g_new(char, xmllen);
376
	snprintf(xml, xmllen, "<icq_sms_message>"
377
		"<destination>%s</destination>"
378
		"<text>%s</text>"
379
		"<codepage>1252</codepage>"
380
		"<senders_UIN>%s</senders_UIN>"
381
		"<senders_name>%s</senders_name>"
382
		"<delivery_receipt>Yes</delivery_receipt>"
383
		"<time>%s</time>"
384
		"</icq_sms_message>",
385
		name, stripped, username, alias, timestr);
386

    
387
	bslen = 36 + xmllen;
388

    
389
	byte_stream_new(&bs, 4 + bslen);
390

    
391
	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
392

    
393
	/* For simplicity, don't bother using a tlvlist */
394
	byte_stream_put16(&bs, 0x0001);
395
	byte_stream_put16(&bs, bslen);
396

    
397
	byte_stream_putle16(&bs, bslen - 2);
398
	byte_stream_putuid(&bs, od);
399
	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
400
	byte_stream_putle16(&bs, snacid); /* eh. */
401

    
402
	/* From libicq200-0.3.2/src/SNAC-SRV.cpp */
403
	byte_stream_putle16(&bs, 0x1482);
404
	byte_stream_put16(&bs, 0x0001);
405
	byte_stream_put16(&bs, 0x0016);
406
	byte_stream_put32(&bs, 0x00000000);
407
	byte_stream_put32(&bs, 0x00000000);
408
	byte_stream_put32(&bs, 0x00000000);
409
	byte_stream_put32(&bs, 0x00000000);
410

    
411
	byte_stream_put16(&bs, 0x0000);
412
	byte_stream_put16(&bs, xmllen);
413
	byte_stream_putstr(&bs, xml);
414
	byte_stream_put8(&bs, 0x00);
415

    
416
	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
417

    
418
	byte_stream_destroy(&bs);
419

    
420
	g_free(xml);
421
	g_free(stripped);
422

    
423
	return 0;
424
}
425

    
426
static void
427
gotalias(OscarData *od, struct aim_icq_info *info)
428
{
429
	PurpleConnection *gc = od->gc;
430
	PurpleAccount *account = purple_connection_get_account(gc);
431
	PurpleBuddy *b;
432
	gchar *utf8 = oscar_utf8_try_convert(account, od, info->nick);
433

    
434
	if (info->for_auth_request) {
435
		oscar_auth_recvrequest(gc, g_strdup_printf("%u", info->uin), utf8, info->auth_request_reason);
436
	} else {
437
		if (utf8 && *utf8) {
438
			gchar who[16];
439
			g_snprintf(who, sizeof(who), "%u", info->uin);
440
			serv_got_alias(gc, who, utf8);
441
			if ((b = purple_find_buddy(account, who))) {
442
				purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
443
			}
444
		}
445
		g_free(utf8);
446
	}
447
}
448

    
449
/**
450
 * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet.
451
 */
452
static int
453
icqresponse(OscarData *od, aim_modsnac_t *snac, ByteStream *bs)
454
{
455
	GSList *tlvlist;
456
	aim_tlv_t *datatlv;
457
	ByteStream qbs;
458
	guint32 ouruin;
459
	guint16 cmdlen, cmd, reqid;
460

    
461
	if (!(tlvlist = aim_tlvlist_read(bs)) || !(datatlv = aim_tlv_gettlv(tlvlist, 0x0001, 1))) {
462
		aim_tlvlist_free(tlvlist);
463
		purple_debug_misc("oscar", "corrupt ICQ response\n");
464
		return 0;
465
	}
466

    
467
	byte_stream_init(&qbs, datatlv->value, datatlv->length);
468

    
469
	cmdlen = byte_stream_getle16(&qbs);
470
	ouruin = byte_stream_getle32(&qbs);
471
	cmd = byte_stream_getle16(&qbs);
472
	reqid = byte_stream_getle16(&qbs);
473

    
474
	purple_debug_misc("oscar", "icq response: %d bytes, %u, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
475

    
476
	if (cmd == 0x07da) { /* information */
477
		guint16 subtype;
478
		GSList *info_ptr;
479
		struct aim_icq_info *info;
480

    
481
		subtype = byte_stream_getle16(&qbs);
482
		byte_stream_advance(&qbs, 1); /* 0x0a */
483

    
484
		/* find other data from the same request */
485
		info_ptr = g_slist_find_custom(od->icq_info, &reqid, compare_icq_infos);
486
		if (!info_ptr) {
487
			struct aim_icq_info *new_info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
488
			new_info->reqid = reqid;
489
			info_ptr = od->icq_info = g_slist_prepend(od->icq_info, new_info);
490
		}
491

    
492
		info = info_ptr->data;
493
		switch (subtype) {
494
		case 0x00a0: { /* hide ip status */
495
			/* nothing */
496
		} break;
497

    
498
		case 0x00aa: { /* password change status */
499
			/* nothing */
500
		} break;
501

    
502
		case 0x00c8: { /* general and "home" information */
503
			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
504
			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
505
			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
506
			info->email = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
507
			info->homecity = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
508
			info->homestate = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
509
			info->homephone = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
510
			info->homefax = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
511
			info->homeaddr = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
512
			info->mobile = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
513
			info->homezip = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
514
			info->homecountry = byte_stream_getle16(&qbs);
515
			/* 0x0a 00 02 00 */
516
			/* 1 byte timezone? */
517
			/* 1 byte hide email flag? */
518
		} break;
519

    
520
		case 0x00dc: { /* personal information */
521
			info->age = byte_stream_getle8(&qbs);
522
			info->unknown = byte_stream_getle8(&qbs);
523
			info->gender = byte_stream_getle8(&qbs); /* Not specified=0x00, Female=0x01, Male=0x02 */
524
			info->personalwebpage = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
525
			info->birthyear = byte_stream_getle16(&qbs);
526
			info->birthmonth = byte_stream_getle8(&qbs);
527
			info->birthday = byte_stream_getle8(&qbs);
528
			info->language1 = byte_stream_getle8(&qbs);
529
			info->language2 = byte_stream_getle8(&qbs);
530
			info->language3 = byte_stream_getle8(&qbs);
531
			/* 0x00 00 01 00 00 01 00 00 00 00 00 */
532
		} break;
533

    
534
		case 0x00d2: { /* work information */
535
			info->workcity = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
536
			info->workstate = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
537
			info->workphone = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
538
			info->workfax = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
539
			info->workaddr = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
540
			info->workzip = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
541
			info->workcountry = byte_stream_getle16(&qbs);
542
			info->workcompany = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
543
			info->workdivision = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
544
			info->workposition = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
545
			byte_stream_advance(&qbs, 2); /* 0x01 00 */
546
			info->workwebpage = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
547
		} break;
548

    
549
		case 0x00e6: { /* additional personal information */
550
			info->info = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs)-1);
551
		} break;
552

    
553
		case 0x00eb: { /* email address(es) */
554
			int i;
555
			info->numaddresses = byte_stream_getle16(&qbs);
556
			info->email2 = (char **)g_new0(char *, info->numaddresses);
557
			for (i = 0; i < info->numaddresses; i++) {
558
				info->email2[i] = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
559
				if (i+1 != info->numaddresses)
560
					byte_stream_advance(&qbs, 1); /* 0x00 */
561
			}
562
		} break;
563

    
564
		case 0x00f0: { /* personal interests */
565
		} break;
566

    
567
		case 0x00fa: { /* past background and current organizations */
568
		} break;
569

    
570
		case 0x0104: { /* alias info */
571
			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
572
			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
573
			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
574
			byte_stream_advance(&qbs, byte_stream_getle16(&qbs)); /* email address? */
575
			/* Then 0x00 02 00 */
576
		} break;
577

    
578
		case 0x010e: { /* unknown */
579
			/* 0x00 00 */
580
		} break;
581

    
582
		case 0x019a: { /* simple info */
583
			byte_stream_advance(&qbs, 2);
584
			info->uin = byte_stream_getle32(&qbs);
585
			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
586
			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
587
			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
588
			info->email = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
589
			/* Then 0x00 02 00 00 00 00 00 */
590
		} break;
591

    
592
		/* status note title and send request for status note text */
593
		case 0x0fb4: {
594
			GSList *tlvlist;
595
			aim_tlv_t *tlv;
596
			FlapConnection *conn;
597
			char *uin = NULL;
598
			char *status_note_title = NULL;
599

    
600
			conn = flap_connection_findbygroup(od, 0x0004);
601
			if (conn == NULL)
602
			{
603
				purple_debug_misc("oscar", "icq/0x0fb4: flap connection was not found.\n");
604
				break;
605
			}
606

    
607
			byte_stream_advance(&qbs, 0x02); /* length */
608
			byte_stream_advance(&qbs, 0x2f); /* unknown stuff */
609

    
610
			tlvlist = aim_tlvlist_read(&qbs);
611

    
612
			tlv = aim_tlv_gettlv(tlvlist, 0x0032, 1);
613
			if (tlv != NULL)
614
				/* Get user number */
615
				uin = aim_tlv_getvalue_as_string(tlv);
616

    
617
			tlv = aim_tlv_gettlv(tlvlist, 0x0226, 1);
618
			if (tlv != NULL)
619
				/* Get status note title */
620
				status_note_title = aim_tlv_getvalue_as_string(tlv);
621

    
622
			aim_tlvlist_free(tlvlist);
623

    
624
			if (uin == NULL || status_note_title == NULL)
625
			{
626
				purple_debug_misc("oscar", "icq/0x0fb4: uin or "
627
						"status_note_title was not found\n");
628
				g_free(uin);
629
				g_free(status_note_title);
630
				break;
631
			}
632

    
633
			if (status_note_title[0] == '\0')
634
			{
635
				PurpleAccount *account;
636
				PurpleBuddy *buddy;
637
				PurplePresence *presence;
638
				PurpleStatus *status;
639

    
640
				account = purple_connection_get_account(od->gc);
641
				buddy = purple_find_buddy(account, uin);
642
				presence = purple_buddy_get_presence(buddy);
643
				status = purple_presence_get_active_status(presence);
644

    
645
				purple_prpl_got_user_status(account, uin,
646
						purple_status_get_id(status),
647
						"message", NULL, NULL);
648

    
649
				g_free(status_note_title);
650
			}
651
			else
652
			{
653
				struct aim_icq_info *info;
654
				ByteStream bs;
655
				guint32 bslen;
656
				aim_snacid_t snacid;
657
				guchar cookie[8];
658

    
659
				info = g_new0(struct aim_icq_info, 1);
660

    
661
				bslen = 13 + strlen(uin) + 30 + 6 + 4 + 55 + 85 + 4;
662
				byte_stream_new(&bs, 4 + bslen);
663

    
664
				snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
665

    
666
				aim_icbm_makecookie(cookie);
667

    
668
				byte_stream_putraw(&bs, cookie, 8); /* ICBM cookie */
669
				byte_stream_put16(&bs, 0x0002); /* message channel */
670
				byte_stream_put8(&bs, strlen(uin)); /* uin */
671
				byte_stream_putstr(&bs, uin);
672

    
673
				byte_stream_put16(&bs, 0x0005); /* rendez vous data */
674
				byte_stream_put16(&bs, 0x00b2);
675
				byte_stream_put16(&bs, 0x0000); /* request */
676
				byte_stream_putraw(&bs, cookie, 8); /* ICBM cookie */
677
				byte_stream_put32(&bs, 0x09461349); /* ICQ server relaying */
678
				byte_stream_put16(&bs, 0x4c7f);
679
				byte_stream_put16(&bs, 0x11d1);
680
				byte_stream_put32(&bs, 0x82224445);
681
				byte_stream_put32(&bs, 0x53540000);
682

    
683
				byte_stream_put16(&bs, 0x000a); /* unknown TLV */
684
				byte_stream_put16(&bs, 0x0002);
685
				byte_stream_put16(&bs, 0x0001);
686

    
687
				byte_stream_put16(&bs, 0x000f); /* unknown TLV */
688
				byte_stream_put16(&bs, 0x0000);
689

    
690
				byte_stream_put16(&bs, 0x2711); /* extended data */
691
				byte_stream_put16(&bs, 0x008a);
692
				byte_stream_putle16(&bs, 0x001b); /* length */
693
				byte_stream_putle16(&bs, 0x0009); /* version */
694
				byte_stream_putle32(&bs, 0x00000000); /* plugin: none */
695
				byte_stream_putle32(&bs, 0x00000000);
696
				byte_stream_putle32(&bs, 0x00000000);
697
				byte_stream_putle32(&bs, 0x00000000);
698
				byte_stream_putle16(&bs, 0x0000); /* unknown */
699
				byte_stream_putle32(&bs, 0x00000000); /* client capabilities flags */
700
				byte_stream_put8(&bs, 0x00); /* unknown */
701
				byte_stream_putle16(&bs, 0x0064); /* downcounter? */
702
				byte_stream_putle16(&bs, 0x000e); /* length */
703
				byte_stream_putle16(&bs, 0x0064); /* downcounter? */
704
				byte_stream_putle32(&bs, 0x00000000); /* unknown */
705
				byte_stream_putle32(&bs, 0x00000000);
706
				byte_stream_putle32(&bs, 0x00000000);
707
				byte_stream_put8(&bs, 0x1a); /* message type: plugin message descibed by text string */
708
				byte_stream_put8(&bs, 0x00); /* message flags */
709
				byte_stream_putle16(&bs, 0x0000); /* status code */
710
				byte_stream_putle16(&bs, 0x0001); /* priority code */
711
				byte_stream_putle16(&bs, 0x0000); /* text length */
712

    
713
				byte_stream_put8(&bs, 0x3a); /* message dump */
714
				byte_stream_put32(&bs, 0x00811a18);
715
				byte_stream_put32(&bs, 0xbc0e6c18);
716
				byte_stream_put32(&bs, 0x47a5916f);
717
				byte_stream_put32(&bs, 0x18dcc76f);
718
				byte_stream_put32(&bs, 0x1a010013);
719
				byte_stream_put32(&bs, 0x00000041);
720
				byte_stream_put32(&bs, 0x77617920);
721
				byte_stream_put32(&bs, 0x53746174);
722
				byte_stream_put32(&bs, 0x7573204d);
723
				byte_stream_put32(&bs, 0x65737361);
724
				byte_stream_put32(&bs, 0x67650100);
725
				byte_stream_put32(&bs, 0x00000000);
726
				byte_stream_put32(&bs, 0x00000000);
727
				byte_stream_put32(&bs, 0x00000000);
728
				byte_stream_put32(&bs, 0x00000015);
729
				byte_stream_put32(&bs, 0x00000000);
730
				byte_stream_put32(&bs, 0x0000000d);
731
				byte_stream_put32(&bs, 0x00000074);
732
				byte_stream_put32(&bs, 0x6578742f);
733
				byte_stream_put32(&bs, 0x782d616f);
734
				byte_stream_put32(&bs, 0x6c727466);
735

    
736
				byte_stream_put16(&bs, 0x0003); /* server ACK requested */
737
				byte_stream_put16(&bs, 0x0000);
738

    
739
				info->uin = atoi(uin);
740
				info->status_note_title = status_note_title;
741

    
742
				memcpy(&info->icbm_cookie, cookie, 8);
743

    
744
				od->icq_info = g_slist_prepend(od->icq_info, info);
745

    
746
				flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, FALSE);
747

    
748
				byte_stream_destroy(&bs);
749
			}
750

    
751
			g_free(uin);
752

    
753
		} break;
754

    
755
		} /* End switch statement */
756

    
757
		if (!(snac->flags & 0x0001)) {
758
			if (subtype != 0x0104)
759
				oscar_user_info_display_icq(od, info);
760

    
761
			if (info->uin && info->nick)
762
				gotalias(od, info);
763

    
764
			aim_icq_freeinfo(info);
765
			od->icq_info = g_slist_remove(od->icq_info, info);
766
		}
767
	}
768

    
769
	aim_tlvlist_free(tlvlist);
770

    
771
	return 1;
772
}
773

    
774
static int
775
snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
776
{
777
	if (snac->subtype == 0x0001)
778
		return error(od, snac, bs);
779
	else if (snac->subtype == 0x0003)
780
		return icqresponse(od, snac, bs);
781

    
782
	return 0;
783
}
784

    
785
static void
786
icq_shutdown(OscarData *od, aim_module_t *mod)
787
{
788
	GSList *cur;
789
	for (cur = od->icq_info; cur; cur = cur->next)
790
		aim_icq_freeinfo(cur->data);
791
	g_slist_free(od->icq_info);
792
}
793

    
794
int
795
icq_modfirst(OscarData *od, aim_module_t *mod)
796
{
797
	mod->family = SNAC_FAMILY_ICQ;
798
	mod->version = 0x0001;
799
	mod->toolid = 0x0110;
800
	mod->toolversion = 0x047c;
801
	mod->flags = 0;
802
	strncpy(mod->name, "icq", sizeof(mod->name));
803
	mod->snachandler = snachandler;
804
	mod->shutdown = icq_shutdown;
805

    
806
	return 0;
807
}