1
2#import "EC.h"
3
4#import <CommonCrypto/CommonDigest.h>
5
6@implementation ECTag
7
8@synthesize tagName = m_name;
9@synthesize tagType = m_type;
10@synthesize subtags = m_subtags;
11
12+ (id)tagFromBuffer:(uint8_t **) buffer withLenght:(int) length {
13	ECTag *tag = nil; //[[ECTag alloc] init];
14
15	if ( length < 4 ) {
16		NSLog(@"[EC] buffer for tag is too short");
17		return nil;
18	}
19
20	uint16_t name16 = *(uint16_t *)(*buffer);
21	name16 = ntohs(name16);
22	bool have_subtags = (name16 & 1) != 0;
23	name16 >>= 1;
24	ECTagNames tag_name = (ECTagNames)(name16);
25	*buffer += sizeof(name16);
26
27	uint8_t type8 = *(*buffer);
28	ECTagTypes tag_type = (ECTagTypes)type8;
29	*buffer += sizeof(type8);
30
31	uint32_t size32 = *(uint32_t *)(*buffer);
32	size32 = ntohl(size32);
33	*buffer += sizeof(uint32_t);
34
35	NSMutableArray *subtags = have_subtags ? [ECTag readSubtags:buffer withLenght:(length-3)] : nil;
36
37	switch (tag_type) {
38		case EC_TAGTYPE_UINT8:
39			tag = [ECTagInt8 tagFromBuffer:buffer];
40			break;
41		case EC_TAGTYPE_UINT16:
42			tag = [ECTagInt16 tagFromBuffer:buffer];
43			break;
44		case EC_TAGTYPE_UINT32:
45			tag = [ECTagInt32 tagFromBuffer:buffer];
46			break;
47		case EC_TAGTYPE_UINT64:
48			tag = [ECTagInt64 tagFromBuffer:buffer];
49			break;
50		case EC_TAGTYPE_HASH16:
51			tag = [ECTagMD5 tagFromBuffer:buffer];
52			break;
53		case EC_TAGTYPE_STRING:
54			tag = [ECTagString tagFromBuffer:buffer];
55			break;
56		default: ;
57			break;
58	}
59	if ( tag != nil ) {
60		tag->m_name = tag_name;
61		tag->m_subtags = subtags;
62	}
63	return tag;
64}
65
66+ (NSMutableArray *)readSubtags:(uint8_t **) buffer withLenght:(int) length {
67
68	uint16_t count16 = *(uint16_t *)(*buffer);
69	count16 = ntohs(count16);
70	*buffer += sizeof(count16);
71	NSMutableArray *array = [[NSMutableArray alloc] init];
72	[array retain];
73	for(int i = 0; i < count16; i++) {
74		id tag = [ECTag tagFromBuffer:buffer withLenght:length];
75		if ( tag != nil ) {
76			[array addObject:tag];
77		}
78	}
79
80	return array;
81}
82
83- (void)writeToSocket:(NSOutputStream *) socket {
84	uint16_t name16 = (uint16_t)m_name;
85	name16 <<= 1;
86	uint8_t type8 = (uint8_t)m_type;
87	if ( [m_subtags count] ) {
88		name16 |= 1;
89	}
90	name16 = htons(name16);
91	[socket write:(uint8_t *)&name16 maxLength:sizeof(name16)];
92	[socket write:&type8 maxLength:sizeof(type8)];
93	uint32_t size32 = [self getSize];
94	size32 = htonl(size32);
95	[socket write:(uint8_t *)&size32 maxLength:sizeof(size32)];
96}
97
98- (void)writeSubtagsToSocket:(NSOutputStream *) socket {
99	uint16_t count16 = [m_subtags count];
100	count16 = htons(count16);
101	[socket write:(uint8_t *)&count16 maxLength:sizeof(count16)];
102	for (ECTag *t in m_subtags) {
103		[t writeToSocket:socket];
104	}
105}
106
107- (int)getSize {
108	int total_size = m_size;
109	for (ECTag *t in m_subtags) {
110		total_size += [t getSize];
111		// name + type + size
112		total_size += (2 + 1 + 4);
113		if ([t->m_subtags count]) {
114			total_size += 2;
115		}
116	}
117	return total_size;
118}
119
120- (id)tagByName:(ECTagNames) tagname {
121	ECTag *mytag = nil;
122	for (ECTag *t in m_subtags) {
123		if (t.tagName == tagname) {
124			mytag = t;
125			break;
126		}
127	}
128	return mytag;
129}
130
131- (void)initSubtags {
132	m_subtags = [NSMutableArray array];
133	[m_subtags retain];
134}
135
136- (void) dealloc {
137	[m_subtags release];
138	[super dealloc];
139}
140
141- (uint64_t)tagInt64ByName: (ECTagNames) tagname {
142	ECTag *st = [self tagByName: tagname];
143	if (st == nil) {
144		return 0;
145	}
146	uint64_t value = 0;
147	switch ([st getSize]) {
148		case 1: {
149			ECTagInt8 *t = (ECTagInt8 *)st;
150			value = t.uint8Value;
151			break;
152			}
153		case 2: {
154			ECTagInt16 *t = (ECTagInt16 *)st;
155			value = t.uint16Value;
156			break;
157			}
158		case 4: {
159			ECTagInt32 *t = (ECTagInt32 *)st;
160			value = t.uint32Value;
161			break;
162			}
163		case 8: {
164			ECTagInt64 *t = (ECTagInt64 *)st;
165			value = t.uint64Value;
166			break;
167			}
168	}
169	return value;
170}
171
172- (int)tagCount {
173	return [m_subtags count];
174}
175
176@end
177
178@implementation ECTagInt8
179
180@synthesize uint8Value = m_val;
181
182+ (id)tagFromInt8:(uint8_t) value withName:(ECTagNames) name {
183	ECTagInt8 *tag = [[ECTagInt8 alloc] init];
184	tag->m_val = value;
185	tag->m_size = 1;
186	tag->m_type = EC_TAGTYPE_UINT8;
187	tag->m_name = name;
188
189	return tag;
190}
191
192+ (id)tagFromBuffer:(uint8_t **) buffer {
193	ECTagInt8 *tag = [[ECTagInt8 alloc] init];
194	tag->m_val = **buffer;
195	tag->m_size = 1;
196	tag->m_type = EC_TAGTYPE_UINT8;
197
198	*buffer += 1;
199
200	return tag;
201}
202
203- (void)writeToSocket:(NSOutputStream *) socket {
204	[super writeToSocket:socket];
205
206	[socket write:&m_val maxLength:sizeof(m_val)];
207}
208
209@end
210
211@implementation ECTagInt16
212
213@synthesize uint16Value = m_val;
214
215+ (id)tagFromInt16:(uint16_t) value withName:(ECTagNames) name {
216	ECTagInt16 *tag = [[ECTagInt16 alloc] init];
217	tag->m_val = value;
218	tag->m_size = 2;
219	tag->m_type = EC_TAGTYPE_UINT16;
220	tag->m_name = name;
221
222	return tag;
223}
224
225+ (id)tagFromBuffer:(uint8_t **) buffer {
226	ECTagInt16 *tag = [[ECTagInt16 alloc] init];
227
228	tag->m_val = ntohs(*((uint16_t *)(*buffer)));
229	tag->m_size = 2;
230	tag->m_type = EC_TAGTYPE_UINT16;
231
232	*buffer += 2;
233
234	return tag;
235}
236
237
238@end
239
240@implementation ECTagInt32
241
242@synthesize uint32Value = m_val;
243
244+ (id)tagFromInt32:(uint32_t) value withName:(ECTagNames) name {
245	ECTagInt32 *tag = [[ECTagInt32 alloc] init];
246	tag->m_val = value;
247	tag->m_size = 4;
248	tag->m_type = EC_TAGTYPE_UINT32;
249	tag->m_name = name;
250
251	return tag;
252}
253
254+ (id)tagFromBuffer:(uint8_t **) buffer {
255	ECTagInt32 *tag = [[ECTagInt32 alloc] init];
256
257	tag->m_val = ntohl(*((uint32_t *)(*buffer)));
258	tag->m_size = 4;
259	tag->m_type = EC_TAGTYPE_UINT32;
260
261	*buffer += 4;
262
263	return tag;
264}
265
266
267@end
268
269@implementation ECTagInt64
270
271@synthesize uint64Value = m_val;
272
273+ (id)tagFromInt64:(uint64_t) value withName:(ECTagNames) name {
274	ECTagInt64 *tag = [[ECTagInt64 alloc] init];
275	tag->m_val = value;
276	tag->m_size = 8;
277	tag->m_type = EC_TAGTYPE_UINT64;
278	tag->m_name = name;
279
280	return tag;
281}
282
283
284+ (id)tagFromBuffer:(uint8_t **) buffer {
285	ECTagInt64 *tag = [[ECTagInt64 alloc] init];
286	uint64_t lo, hi;
287
288	uint32 val32 = *((uint32_t *)(*buffer));
289	hi = ntohl(val32);
290	*buffer += 4;
291
292	val32 = *((uint32_t *)(*buffer));
293	lo = ntohl(val32);
294	*buffer += 4;
295
296	tag->m_val = (hi << 32) | lo;
297	tag->m_size = 8;
298	tag->m_type = EC_TAGTYPE_UINT64;
299
300	return tag;
301}
302
303
304- (void)writeToSocket:(NSOutputStream *) socket {
305	[super writeToSocket:socket];
306
307	uint32_t val32 = m_val >> 32;
308	val32 = htonl(val32);
309	[socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
310
311	val32 = m_val & 0xffffffff;
312	val32 = htonl(val32);
313	[socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
314}
315
316@end
317
318
319@implementation ECTagData
320
321- (void)writeToSocket:(NSOutputStream *) socket {
322	[super writeToSocket:socket];
323
324	[socket write:(const uint8_t *)[m_data bytes] maxLength:m_size];
325}
326
327- (void) dealloc {
328	[m_data release];
329	[super dealloc];
330}
331
332+ (id)tagFromBuffer:(uint8_t **) buffer withLenght:(int) length {
333	ECTagData *tag = [[ECTagData alloc] init];
334
335	tag->m_data = [NSData dataWithBytes: *buffer length: length];
336	[tag->m_data retain];
337
338	return tag;
339}
340
341
342@end
343
344@implementation ECTagMD5
345
346+ (id)tagFromString:(NSString *) string withName:(ECTagNames) name {
347	ECTagMD5 *tag = [[ECTagMD5 alloc] init];
348
349	CC_MD5_CTX ctx;
350	unsigned char md5data[16];
351	CC_MD5_Init(&ctx);
352	CC_MD5_Update(&ctx, [string UTF8String], [string length]);
353	CC_MD5_Final(md5data, &ctx);
354
355	tag->m_data = [NSData dataWithBytes: md5data length: sizeof(md5data)];
356	[tag->m_data retain];
357	tag->m_size = 16;
358	tag->m_type = EC_TAGTYPE_HASH16;
359	tag->m_name = name;
360
361	return tag;
362}
363
364+ (id)tagFromBuffer:(uint8_t **) buffer {
365	ECTagMD5 *tag = [[ECTagMD5 alloc] init];
366
367	tag->m_data = 0;
368	tag->m_val.lo = *((uint64_t *)(*buffer));
369	(*buffer) += 8;
370	tag->m_val.hi = *((uint64_t *)(*buffer));
371	(*buffer) += 8;
372
373	return tag;
374}
375
376- (MD5Data)getMD5Data {
377	if ( m_data ) {
378		uint8_t *data_ptr = (uint8_t *)[m_data bytes];
379
380		uint64_t hi = *(uint64_t *)data_ptr;
381		data_ptr += 8;
382		uint64_t lo = *(uint64_t *)data_ptr;
383		MD5Data md5 = {hi, lo};
384		return md5;
385	} else {
386		return m_val;
387	}
388}
389- (NSString *)stringKey {
390	NSString *s = [NSString stringWithFormat:@"%qx%qx", m_val.hi, m_val.lo];
391	return s;
392}
393
394@end
395
396@implementation ECTagString
397
398@synthesize stringValue = m_val;
399
400+ tagFromString:(NSString *) string withName:(ECTagNames) name {
401	ECTagString *tag = [[ECTagString alloc] init];
402
403	const char *rawstring = [string UTF8String];
404	tag->m_size = strlen(rawstring) + 1;
405	tag->m_data = [NSData dataWithBytes: rawstring length: tag->m_size];
406	[tag->m_data retain];
407	tag->m_type = EC_TAGTYPE_STRING;
408	tag->m_name = name;
409
410	return tag;
411}
412
413+ (id)tagFromBuffer:(uint8_t **) buffer {
414	ECTagString *tag = [[ECTagString alloc] init];
415
416	tag->m_val = [NSString stringWithCString:(char *)(*buffer) encoding:NSUTF8StringEncoding];
417	*buffer += [tag->m_val length] + 1;
418
419	return tag;
420}
421
422@end
423
424@implementation ECPacket
425
426@synthesize opcode = m_opcode;
427
428+ (id)packetWithOpcode:(ec_opcode_t) opcode {
429	ECPacket *p = [[ECPacket alloc] init];
430
431	[p initWithOpcode:opcode];
432
433	return p;
434}
435
436
437- (void)initWithOpcode:(ec_opcode_t) opcode {
438	m_opcode = opcode;
439	m_flags = 0x20;
440
441	// allow notification push to my client
442	m_flags |= EC_FLAG_NOTIFY | EC_FLAG_ACCEPTS;
443
444	[self initSubtags];
445}
446
447+ (id)packetFromBuffer:(uint8_t *) buffer withLength:(int)length {
448	if ( length < 11 ) {
449		return nil;
450	}
451	ECPacket *p = [[ECPacket alloc] init];
452	uint8_t *data = buffer;
453
454	p->m_flags = ntohl(*((uint32_t *)data));
455	data += 4;
456	uint32_t packet_size = ntohl(*((uint32_t *)data));
457	data += 4;
458	if ( packet_size > 1024*1024 ) {
459		return nil;
460	}
461	p->m_opcode = (ec_opcode_t)(*data);
462	data++;
463
464	uint16_t tag_count = ntohs(*((uint16_t *)data));
465	data += 2;
466	if ( tag_count ) {
467		p->m_subtags = [[NSMutableArray alloc] init];
468		[p->m_subtags retain];
469		uint8_t *start_ptr = data;
470		for(int i = 0; i < tag_count; i++) {
471			ECTag *tag = [ECTag tagFromBuffer:&data withLenght:(length - (data - start_ptr))];
472			// some tags are not supported yet
473			if ( tag != nil ) {
474				[p->m_subtags addObject:tag];
475			}
476		}
477	}
478
479	return p;
480}
481
482- (void)writeToSocket:(NSOutputStream *) socket {
483	// 1 (command) + 2 (tag count)
484	int packet_size = [self getSize] + 1 + 2;
485
486// No need for zlib on client side
487//	if ( packet_size > MaxUncompressedPacket ) {
488//		m_flags |= (Int32)ECFlags.EC_FLAG_ZLIB;
489//	}
490	uint32_t val32 = htonl(m_flags);
491	[socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
492	if ( m_flags & EC_FLAG_ACCEPTS ) {
493		[socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
494	}
495	val32 = htonl(packet_size);
496	[socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
497	[socket write:(uint8_t *)&m_opcode maxLength:sizeof(m_opcode)];
498
499	if ( [m_subtags count] ) {
500		[self writeSubtagsToSocket:socket];
501	} else {
502		uint16_t val16 = 0;
503		[socket write:(uint8_t *)&val16 maxLength:sizeof(val16)];
504	}
505}
506
507@end
508
509@implementation ECLoginAuthPacket
510
511- (NSString *)getMD5_Str:(NSString *) str {
512	CC_MD5_CTX ctx;
513	unsigned char md5data[16];
514	CC_MD5_Init(&ctx);
515	CC_MD5_Update(&ctx, [str UTF8String], [str length]);
516	CC_MD5_Final(md5data, &ctx);
517	NSString *MD5str = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
518						 md5data[0], md5data[1],md5data[2],md5data[3],
519						 md5data[4],md5data[5],md5data[6],md5data[7],
520						 md5data[8],md5data[9],md5data[10],md5data[11],
521						 md5data[12],md5data[13],md5data[14],md5data[15]
522						 ];
523	return MD5str;
524}
525
526+ (id)loginPacket:(NSString *) password withSalt:(uint64_t) salt {
527	ECLoginAuthPacket *p = [[ECLoginAuthPacket alloc] init];
528
529	[p initWithOpcode:EC_OP_AUTH_PASSWD];
530
531	NSString *saltStr = [NSString stringWithFormat:@"%llX", salt];
532//	CC_MD5_CTX ctx;
533//	unsigned char md5data[16];
534//	CC_MD5_Init(&ctx);
535//	CC_MD5_Update(&ctx, [saltStr UTF8String], [saltStr length]);
536//	CC_MD5_Final(md5data, &ctx);
537//	NSString *saltMD5 = [NSString stringWithFormat:@"%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x",
538//						 md5data[0], md5data[1],md5data[2],md5data[3],
539//						 md5data[4],md5data[5],md5data[6],md5data[7],
540//						 md5data[8],md5data[9],md5data[10],md5data[11],
541//						 md5data[12],md5data[13],md5data[14],md5data[15]
542//						 ];
543	NSString *saltMD5 = [p getMD5_Str: saltStr];
544
545	NSString *newPass = [NSString stringWithFormat:@"%@%@", [p getMD5_Str: password], saltMD5];
546
547	NSLog(@"[EC] using salt=%@ saltHash=%@ newPass=%@\n", saltStr, saltMD5, newPass);
548
549	ECTagMD5 *passtag = [ECTagMD5 tagFromString: newPass withName:EC_TAG_PASSWD_HASH];
550	[p->m_subtags addObject:passtag];
551
552	return p;
553}
554
555
556@end
557
558@implementation ECLoginRequestPacket
559
560+ (id)loginPacket:(NSString *) version {
561	ECLoginRequestPacket *p = [[ECLoginRequestPacket alloc] init];
562
563	[p initWithOpcode:EC_OP_AUTH_REQ];
564
565	ECTagString *version_tag = [ECTagString tagFromString:version withName:EC_TAG_CLIENT_VERSION];
566	[p->m_subtags addObject:version_tag];
567
568	ECTagString *client_name_tag = [ECTagString tagFromString:@"cocoa-frontend" withName:EC_TAG_CLIENT_NAME];
569	[p->m_subtags addObject:client_name_tag];
570
571	ECTagInt64 *proto_version_tag = [ECTagInt64 tagFromInt64:EC_CURRENT_PROTOCOL_VERSION withName:EC_TAG_PROTOCOL_VERSION];
572	[p->m_subtags addObject:proto_version_tag];
573
574	return p;
575}
576
577
578@end
579
580
581@implementation ECRemoteConnection
582
583@synthesize error = m_error;
584
585+ (id)remoteConnection {
586	ECRemoteConnection *p = [[ECRemoteConnection alloc] init];
587
588	//
589	// rx buffer can be resized as needed
590	//
591	p->m_rxbuf = [NSMutableData dataWithLength:1024];
592	[p->m_rxbuf retain];
593
594	p->m_login_handler = [amuleLoginHandler initWithConnection:p];
595	[p->m_login_handler retain];
596	//
597	// client only transmit commands, which are
598	// quite small in size. "big enough" buffer will do the trick
599	//
600//	p->m_txbuf = [NSMutableData dataWithLength:1024];
601//	[p->m_txbuf retain];
602	p->m_txbuf = nil;
603
604	return p;
605}
606
607- (void) dealloc {
608	[m_rxbuf release];
609	[m_txbuf release];
610
611	[m_istream release];
612	[m_ostream release];
613
614	[super dealloc];
615}
616
617- (bool)isIpv4Address:(NSString *) address {
618	NSArray *ar = [address componentsSeparatedByString:@"."];
619	if ( [ar count] != 4 ) {
620		return false;
621	}
622	for (NSString *s in ar) {
623		const char *p = [s UTF8String];
624		while ( *p ) {
625			if ( !isdigit(*p) ) {
626				return false;
627			}
628			p++;
629		}
630	}
631	return true;
632}
633
634- (void)connectToAddress:(NSString *) hostname withPort:(int)trgport {
635	m_error = false;
636
637	NSHost *host = [NSHost hostWithName:hostname];
638	NSString *addr = nil;
639
640	//
641	// On Mac localhost has ipv6 address (linklocal), but amuled listen
642	// only on ipv4
643	//
644	for (NSString *ad in host.addresses) {
645		NSLog(@"host have address=%@ is_ipv4=%d\n", ad, [self isIpv4Address:ad]);
646		if ( [self isIpv4Address:ad] ) {
647			addr = ad;
648			break;
649		}
650	}
651	if ( addr == nil ) {
652		return;
653	}
654	host = [NSHost hostWithAddress:addr];
655
656	[NSStream getStreamsToHost:host port:trgport inputStream:&m_istream outputStream:&m_ostream];
657
658	[m_istream retain];
659	[m_ostream retain];
660
661	[m_istream setDelegate:self];
662	[m_ostream setDelegate:self];
663
664	[m_istream scheduleInRunLoop:[NSRunLoop currentRunLoop]
665            forMode:NSDefaultRunLoopMode];
666
667	[m_ostream scheduleInRunLoop:[NSRunLoop currentRunLoop]
668            forMode:NSDefaultRunLoopMode];
669
670	[m_istream open];
671	[m_ostream open];
672
673	m_remaining_size = 8;
674	m_rx_size = 0;
675}
676
677- (void)sendLogin:(NSString *) password {
678
679	[m_login_handler usePass: password];
680
681	ECLoginRequestPacket *p = [ECLoginRequestPacket loginPacket:@"0.1"];
682	[self sendPacket:p];
683}
684
685- (void)sendPacket:(ECPacket *) packet {
686	NSOutputStream *memstream = [NSOutputStream outputStreamToMemory];
687	[memstream open];
688
689	[packet writeToSocket:memstream];
690	id data = [memstream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
691
692	m_tx_size = [data length];
693	NSLog(@"[EC] sending packet %d bytes\n", m_tx_size);
694	m_tx_ptr = [m_ostream write:(const uint8_t *)[data bytes] maxLength:[data length]];
695	NSLog(@"[EC] %d bytes sent\n", m_tx_ptr);
696	if ( m_tx_ptr == m_tx_size ) {
697		m_txbuf = nil;
698	} else {
699		m_txbuf = (NSData *)data;
700		[m_txbuf retain];
701	}
702	NSStreamStatus stream_status = [m_ostream streamStatus];
703	switch ( stream_status ) {
704		case NSStreamStatusNotOpen:
705		case NSStreamStatusClosed:
706		case NSStreamStatusError:
707			NSLog(@"[EC] error in output stream\n");
708			m_error = true;
709			break;
710		default:;
711	}
712//	NSLog(@"[EC] status in output stream=%d\n", stream_status);
713
714}
715
716- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
717    switch(eventCode) {
718		case NSStreamEventOpenCompleted:
719		{
720			NSLog(@"[EC] open complete\n");
721			break;
722		}
723		case NSStreamEventErrorOccurred:
724		{
725			NSError *e = [stream streamError];
726			NSString *description = [e localizedDescription];
727			NSLog(@"[EC] socket error [%s]\n", [description UTF8String]);
728			break;
729		}
730        case NSStreamEventHasBytesAvailable:
731        {
732			uint8_t *data_ptr = (uint8_t *)[m_rxbuf mutableBytes];
733			unsigned int len = [m_rxbuf length];
734
735            len = [(NSInputStream *)stream read:data_ptr + m_rx_size maxLength:len];
736#ifdef EC_RX_DEBUG
737			NSLog(@"[EC] receiving %d bytes, %d in total, %d remaining\n", len, m_rx_size, m_remaining_size);
738#endif
739			if ( len == 0 ) {
740				//
741				// Remote side must be closed connection
742				//
743				m_error = true;
744				if ( [delegate respondsToSelector:@selector(handleError)] ) {
745					[delegate performSelector:@selector(handleError)];
746				}
747			}
748			int total_len = len;
749			int packet_offset = 0;
750			while ( total_len != 0 ) {
751				len = ( m_remaining_size > total_len ) ? total_len : m_remaining_size;
752				total_len -= len;
753
754				// are we still waiting for flags and size?
755				if ( m_rx_size < 8 ) {
756					if ( (m_rx_size + len) >= 8 ) {
757						// got flags and packet size - may proceed
758						//uint32_t flags = *(((uint32_t *)[m_rxbuf mutableBytes]) + 0);
759						uint32_t val32 = *((uint32_t *)(data_ptr + 4 + packet_offset));
760
761						int delta = 8 - m_rx_size;
762
763						m_remaining_size = ntohl(val32) - (len - delta);
764#ifdef EC_RX_DEBUG
765						NSLog(@"[EC] rx got flags+size, remaining count %d\n", m_remaining_size);
766#endif
767					} else {
768						m_remaining_size -= len;
769					}
770				} else {
771					m_remaining_size -= len;
772				}
773				m_rx_size += len;
774				if ( m_remaining_size == 0 ) {
775					//
776					// full packet received, call handler
777					//
778					uint8_t *packet_start = data_ptr + packet_offset;
779					int packet_length = [m_rxbuf length] - packet_offset;
780					ECPacket *packet = [ECPacket packetFromBuffer:packet_start withLength:packet_length];
781					packet_offset += m_rx_size;
782
783					if ( [m_login_handler loginOK] ) {
784#ifdef EC_RX_DEBUG
785						NSLog(@"[EC] calling delegate\n");
786#endif
787						if ( [delegate respondsToSelector:@selector(handlePacket:)] ) {
788							[delegate performSelector:@selector(handlePacket:) withObject:packet];
789						}
790					} else {
791						NSLog(@"[EC] login handler\n");
792						[m_login_handler handlePacket: packet];
793					}
794					m_remaining_size = 8;
795					m_rx_size = 0;
796				}
797			}
798            break;
799        }
800
801        case NSStreamEventHasSpaceAvailable:
802		{
803			if ( m_txbuf != nil ) {
804				int remaining = [m_txbuf length] - m_tx_ptr;
805				if ( remaining ) {
806					const uint8_t *txdata = ((const uint8_t *)[m_txbuf bytes]) + m_tx_ptr;
807					int txcount = [m_ostream write:txdata maxLength:remaining];
808					m_tx_ptr += txcount;
809				} else {
810					[m_txbuf release];
811					m_txbuf = nil;
812				}
813
814			}
815			break;
816		}
817	}
818}
819
820- (void)setDelegate:(id)val {
821    delegate = val;
822}
823
824- (id)delegate {
825    return delegate;
826}
827
828
829@end
830
831@implementation amuleLoginHandler
832
833+ (id)initWithConnection:(ECRemoteConnection *) connection {
834
835	amuleLoginHandler *obj = [[amuleLoginHandler alloc] init];
836	obj->m_connection = connection;
837
838	obj->m_state = LOGIN_REQUEST_SENT;
839
840	return obj;
841}
842
843- (void)usePass:(NSString *) pass {
844	m_pass = pass;
845}
846
847- (void)handlePacket:(ECPacket *) packet {
848	switch(m_state) {
849		case LOGIN_IDLE:
850			NSLog(@"[EC]: error - no packet should come until request is sent\n");
851			break;
852		case LOGIN_REQUEST_SENT:
853			if ( packet.opcode == EC_OP_AUTH_SALT ) {
854
855				uint64_t salt = [packet tagInt64ByName:EC_TAG_PASSWD_SALT];
856				ECLoginAuthPacket *auth_packet = [ECLoginAuthPacket loginPacket:m_pass withSalt:salt];
857				[m_connection sendPacket:auth_packet];
858
859				m_state = LOGIN_PASS_SENT;
860			} else {
861				NSLog(@"[EC]: error - expecting packet with EC_OP_AUTH_SALT, not [%d]\n", packet.opcode);
862				m_state = LOGIN_IDLE;
863			}
864			break;
865		case LOGIN_PASS_SENT:
866			if ( packet.opcode == EC_OP_AUTH_OK ) {
867				m_state = LOGIN_OK;
868			} else {
869				NSLog(@"[EC]: error - login failed, core replied with code=[%d]\n", packet.opcode);
870			}
871			break;
872		case LOGIN_OK:
873			NSLog(@"[EC]: error - this delegate should be replaced after login completed\n");
874			break;
875	}
876}
877- (void)reset {
878	m_state = LOGIN_IDLE;
879}
880
881- (bool)loginOK {
882	return m_state == LOGIN_OK;
883}
884
885
886@end
887