/*
 * Copyright (c) 2002 Sergey Lyubka
 * IRC bot, for FreeBSD x86
 * Compilation: 
 * cpp -P -C  ircbot.s | m4 | gcc -s -x assembler -nostdlib -o ircbot -
 * Note: can be easily ported to x86 Linux, by changing PUSHPARAMS and
 * SYSCALL macros.

define(`PUSHPARAMS',
	`ifelse($#, 0, ,$#, 1,
	`pushl	$1',
	`pushl	$1
	PUSHPARAMS(shift($@))')')

define(`REVERSE', `ifelse($#, 0, ,$#, 1, $1, `REVERSE(shift($@)), $1')')

define(`SYSCALL',
	`PUSHPARAMS(REVERSE(shift($@)))
	movl	`$'$1, %eax
	pushl	%eax
	int	`$'0x80
	addl	`$'eval(4 * ($#)),%esp')

 * $Id: ircbot.s,v 1.1 2003/10/08 08:03:36 devnull Exp $
 */

#include <sys/syscall.h>

.globl _start

.data
sock:		.long	0
logfd:		.long	0
usagestr:	.asciz	"usage:\nasmbot [server_ip [port]]\n"
fatalstr:	.asciz	"fatal error occured\n"
logfile:	.asciz	"asmbot.log"
tcp_nodelay:	.long	1

/* the next few var is the sockaddr */
sin_len:	.byte	16		/* sizeof(sockaddr_in) */
sin_family:	.byte	2		/* AF_INET */
sin_port:	.short	0x0b1a		/* htons(6667) */
sin_addr:	.long	0xe62228d4	/* htonl(212.40.34.2) */	

/* irc commands */
cmd_user:	.asciz	"user asmbot asmbot asmbot asmbot\r\n"
cmd_nick:	.asciz	"nick asmbot\r\n"
cmd_join:	.asciz	"join #cbot\r\n"
cmd_pong:	.asciz	"PONG irc.lucky.net\r\n"

.comm	ibuf,	2048
.comm	obuf,	2048

.code32

strlen:			/* return string len. string ptr is pushed to stack */
	pushl	%edi
	movl	8(%esp), %edi
	xorl	%eax, %eax
1:
	cmpb	$0, (%edi, %eax)
	jz	2f
	incl	%eax
	jmp	1b
2:
	popl	%edi
	ret	$4
	
	
fatal:
	pushl	%edx
	movl	8(%esp), %edx
	pushl	%edx	
	call	strlen
	SYSCALL(SYS_write, $1, %edx, %eax)
	SYSCALL(SYS_exit, $1)	
	popl	%edx
	ret
	

/*
 * create socket, and connect it to a server. socket stored in the
 * global variable sock
 */
mksocket:
	SYSCALL(SYS_socket, $2, $1, $0)	/* socket(PF_INET, SOCK_STREAM, 0) */
	movl	%eax, sock
	SYSCALL(SYS_connect, sock, $sin_len, $16)	/* connect */
	ret

/*
 * Open a log file and store a file descriptor in a global variable
 */
initlog:
	/* open(logfile, O_WRONLY | O_APPEND | O_CREAT, 0644) */
	SYSCALL(SYS_open, $logfile, $(0x1 | 0x8 | 0x200), $0644)
	movl	%eax, logfd
	ret

/*
 * Connect to the IRC server, join the channel
 */
login:
	pushl	$cmd_user
	call	strlen
	SYSCALL(SYS_write, sock, $cmd_user, %eax);
	pushl	$cmd_nick
	call	strlen
	SYSCALL(SYS_write, sock, $cmd_nick, %eax);
	SYSCALL(SYS_read, sock, $ibuf, $2048)
	pushl	$cmd_join
	call	strlen
	SYSCALL(SYS_write, sock, $cmd_join, %eax);
	ret

/*
 * Infinite main loop
 */
loop:
2:
	SYSCALL(SYS_read, sock, $ibuf, $2048)	/* read(sock, ibuf, 2048) */
	cmpl	$0, %eax
	jg	1f
	pushl	$fatalstr
	call	fatal
	jmp	2b
1:
	/* is it a server PING ? */
	cmpl	$0x474e4950, ibuf
	jne	3f
	/* yes, send a response */
	pushl	$cmd_pong
	call	strlen
	SYSCALL(SYS_write, sock, $cmd_pong, %eax);
	jmp	2b
3:
	SYSCALL(SYS_write, logfd, $ibuf, %eax)	/* write to logfile */
	jmp	2b

/*
 * The entry point
 */
_start:
	popl	%eax
	popl	%eax
	decl	%eax		/* argc == 1 ? */
	jz	1f
	
	/* TODO: handle command-line arguments here */
	
1:
	call	initlog
	call	mksocket
	call	login
	call	loop

