/*
 *	IRC.app -- IRC client program for NEXTSTEP
 *	Copyright (C)1995 Norihiro Itoh
 *
 *	このソースはIRC.appの一部です。
 *	This file is part of IRC.app.
 *
 *	本プログラムはフリー・ソフトウェアです。あなたは、Free Software 
 *	Foundationが公表したGNU一般公有使用許諾の「バージョン２」或いは
 *	それ以降の各バージョンの中からいずれかを選択し、そのバージョンが
 *	定める条項に従って本プログラムを再頒布または変更することができま
 *	す。
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	本プログラムは有用とは思いますが、頒布にあたっては、市場性及び特
 *	定目的適合性についての暗黙の保証を含めて、いかなる保証も行ないま
 *	せん。詳細についてはGNU一般公有使用許諾書をお読みください。
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	あなたは、本プログラムと一緒にGNU一般公有使用許諾の写しを受け取っ
 *	ているはずです。そうでない場合は、Free Software Foundation, Inc.,
 *	675 Mass Ave, Cambridge, MA 02139, USAへ手紙を書いてください。
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *	作者のメールアドレス: nito@scorpio.bekkoame.or.jp
 *	Author's e-mail address: nito@scorpio.bekkoame.or.jp
 */	

#import	"ChatManager.h"

static void	receive(int fd, void *obj);

@implementation ChatManager

- connect:sender
{
    int                 priority = RECEIVE_PRIORITY;
    int			ret;
    int			fd;

    if (![self checkDefaults]) return nil;
    
    if (socket) {
    	fd = [socket getFD];
    	DPSRemoveFD(fd);
	[socket shutDownAndClose];
	[socket free];
    }
    socket = [TCPConnection new];
    ret = [socket connectTo:server by:port];
    if (ret != TCP_CONNECTED) {
    	[socket close];
	socket = [socket free];
    	return nil;
    }

    fd = [socket getFD];
    DPSAddFD(fd, receive, self, priority);

    [self sendNICK:nickname];
    [self sendUSER];

    return self;
}

- disconnect:sender
{
    [self sendQUIT];
    [socket shutDownAndClose];
    return self;
}

- receiveFromServer
{
    int			ret, i;
    char		*from;
    char		*cmd;
    int			cmdid;
    int			size;
    int			fromflag;
    static char		rbuff[BUFSIZ+1];
    static char		buff[BUFSIZ+1];
    static char		frombuff[BUFSIZ+1];
    static char		argbuff[BUFSIZ+1];
    static char		tobuff[BUFSIZ+1];
    static char		msgbuff[BUFSIZ+1];
    unsigned char	c;

    bzero(buff, (BUFSIZ+1));
    fromflag = 0;

    ret = [socket receiveLine:rbuff];
    size = jis2euc((char *)rbuff, buff, strlen(rbuff));
    if (ret <= 0) {
    	return nil;
    }

    if (buff[0] == ':') {
    	fromflag = 1;
	from = strtok(buff, " \r\n");
	for (i = 0; (c = *(from + i + 1)) != '\0'; i++) {
	    if (c == '!') {
	    	frombuff[i] = '\0';
		break;
	    }
	    frombuff[i] = c;
	}
    	cmd = strtok(NULL, " \r\n");
    } else {
    	cmd = strtok(buff, " \r\n");
    }
    cmdid = atoi(cmd);
    strcpy(argbuff, strtok(NULL, "\r\n"));

    if (cmdid == 0) {
    	if (strcmp(cmd, MSG_PASS) == 0) {
    	} else if (strcmp(cmd, MSG_NICK) == 0) {
    	} else if (strcmp(cmd, MSG_USER) == 0) {
    	} else if (strcmp(cmd, MSG_SERVER) == 0) {
    	} else if (strcmp(cmd, MSG_OPER) == 0) {
    	} else if (strcmp(cmd, MSG_QUIT) == 0) {
    	} else if (strcmp(cmd, MSG_SQUIT) == 0) {
    	} else if (strcmp(cmd, MSG_JOIN) == 0) {
	    strcpy(tobuff, strtok(argbuff, " \r\n"));
	    [[NXApp managerOf:tobuff] join:frombuff];
    	} else if (strcmp(cmd, MSG_PART) == 0) {
	    strcpy(tobuff, strtok(argbuff, " \r\n"));
	    [[NXApp managerOf:tobuff] part:frombuff];
    	} else if (strcmp(cmd, MSG_MODE) == 0) {
    	} else if (strcmp(cmd, MSG_TOPIC) == 0) {
	    strcpy(tobuff, strtok(argbuff, " \r\n"));
	    strcpy(msgbuff,(strtok(NULL, "\r\n") + 1));
	    [[NXApp managerOf:tobuff] setTopic:msgbuff];	    
    	} else if (strcmp(cmd, MSG_NAMES) == 0) {
    	} else if (strcmp(cmd, MSG_LIST) == 0) {
    	} else if (strcmp(cmd, MSG_INVITE) == 0) {
    	} else if (strcmp(cmd, MSG_KICK) == 0) {
    	} else if (strcmp(cmd, MSG_VERSION) == 0) {
    	} else if (strcmp(cmd, MSG_STATS) == 0) {
    	} else if (strcmp(cmd, MSG_LINKS) == 0) {
    	} else if (strcmp(cmd, MSG_TIME) == 0) {
    	} else if (strcmp(cmd, MSG_CONNECT) == 0) {
    	} else if (strcmp(cmd, MSG_TRACE) == 0) {
    	} else if (strcmp(cmd, MSG_ADMIN) == 0) {
    	} else if (strcmp(cmd, MSG_INFO) == 0) {
    	} else if (strcmp(cmd, MSG_PRIVMSG) == 0) {
	    strcpy(tobuff, strtok(argbuff, " \r\n"));
	    strcpy(msgbuff,(strtok(NULL, "\r\n") + 1));
	    if (strcmp(msgbuff, "\001VERSION\001") == 0) {
	    	[self replyVERSION:frombuff];
	    } else if (strcmp(msgbuff, "\001CLIENTINFO\001") == 0) {
	    	[self replyCLIENTINFO:frombuff];
	    } else {
		[[NXApp managerOf:tobuff] writeMessage:msgbuff from:frombuff];
	    }    
    	} else if (strcmp(cmd, MSG_NOTICE) == 0) {
    	} else if (strcmp(cmd, MSG_WHO) == 0) {
    	} else if (strcmp(cmd, MSG_WHOIS) == 0) {
    	} else if (strcmp(cmd, MSG_WHOWAS) == 0) {
    	} else if (strcmp(cmd, MSG_KILL) == 0) {
    	} else if (strcmp(cmd, MSG_PING) == 0) {
	    [self sendPONG];
    	} else if (strcmp(cmd, MSG_PONG) == 0) {
    	} else if (strcmp(cmd, MSG_ERROR) == 0) {
    	} else if (strcmp(cmd, MSG_AWAY) == 0) {
    	} else if (strcmp(cmd, MSG_REHASH) == 0) {
    	} else if (strcmp(cmd, MSG_RESTART) == 0) {
    	} else if (strcmp(cmd, MSG_SUMMON) == 0) {
    	} else if (strcmp(cmd, MSG_USERS) == 0) {
    	} else if (strcmp(cmd, MSG_WALLOPS) == 0) {
    	} else if (strcmp(cmd, MSG_USERHOST) == 0) {
    	} else if (strcmp(cmd, MSG_ISON) == 0) {
	} else {
	}
    } else {
    	switch (cmdid) {
    	case ERR_NOSUCHNICK:
	    break;
    	case ERR_NOSUCHSERVER:
	    break;
    	case ERR_NOSUCHCHANNEL:
	    break;
    	case ERR_CANNOTSENDTOCHAN:
	    break;
    	case ERR_TOOMANYCHANNELS:
	    break;
    	case ERR_WASNOSUCHNICK:
	    break;
    	case ERR_TOOMANYTARGETS:
	    break;
    	case ERR_NOSUCHSERVICE:
	    break;
    	case ERR_NOORIGIN:
	    break;
    	case ERR_NORECIPIENT:
	    break;
    	case ERR_NOTEXTTOSEND:
	    break;
    	case ERR_NOTOPLEVEL:
	    break;
    	case ERR_WILDTOPLEVEL:
	    break;
    	case ERR_UNKNOWNCOMMAND:
	    break;
    	case ERR_NOMOTD:
	    break;
    	case ERR_NOADMININFO:
	    break;
    	case ERR_FILEERROR:
	    break;
    	case ERR_NONICKNAMEGIVEN:
	    break;
    	case ERR_ERRONEUSNICKNAME:
	    break;
    	case ERR_NICKNAMEINUSE:
	    break;
    	case ERR_NICKCOLLISION:
	    break;
    	case ERR_USERNOTINCHANNEL:
	    break;
    	case ERR_NOTONCHANNEL:
	    break;
    	case ERR_USERONCHANNEL:
	    break;
    	case ERR_NOLOGIN:
	    break;
    	case ERR_SUMMONDISABLED:
	    break;
    	case ERR_USERSDISABLED:
	    break;
    	case ERR_NOTREGISTERED:
	    break;
    	case ERR_NEEDMOREPARAMS:
	    break;
    	case ERR_ALREADYREGISTRED:
	    break;
    	case ERR_NOPERMFORHOST:
	    break;
    	case ERR_PASSWDMISMATCH:
	    break;
    	case ERR_YOUREBANNEDCREEP:
	    break;
    	case ERR_YOUWILLBEBANNED:
	    break;
    	case ERR_KEYSET:
	    break;
    	case ERR_CHANNELISFULL:
	    break;
    	case ERR_UNKNOWNMODE:
	    break;
    	case ERR_INVITEONLYCHAN:
	    break;
    	case ERR_BANNEDFROMCHAN:
	    break;
    	case ERR_BADCHANNELKEY:
	    break;
    	case ERR_NOPRIVILEGES:
	    break;
    	case ERR_CHANOPRIVSNEEDED:
	    break;
    	case ERR_CANTKILLSERVER:
	    break;
    	case ERR_NOOPERHOST:
	    break;
    	case ERR_UMODEUNKNOWNFLAG:
	    break;
    	case ERR_USERSDONTMATCH:
	    break;
    	case RPL_NONE:
	    break;
    	case RPL_USERHOST:
	    break;
    	case RPL_ISON:
	    break;
    	case RPL_TEXT:
	    break;
    	case RPL_AWAY:
	    break;
    	case RPL_UNAWAY:
	    break;
    	case RPL_NOWAWAY:
	    break;
    	case RPL_WHOISUSER:
	    break;
    	case RPL_WHOISSERVER:
	    break;
    	case RPL_WHOISOPERATOR:
	    break;
    	case RPL_WHOISIDLE:
	    break;
    	case RPL_ENDOFWHOIS:
	    break;
    	case RPL_WHOISCHANNELS:
	    break;
    	case RPL_WHOWASUSER:
	    break;
    	case RPL_ENDOFWHOWAS:
	    break;
    	case RPL_LISTSTART:
	    [NXApp startList];
	    break;
    	case RPL_LIST:
	    [NXApp setList:argbuff];
	    break;
    	case RPL_LISTEND:
	    [NXApp endList];
	    break;
    	case RPL_CHANNELMODEIS:
	    break;
    	case RPL_NOTOPIC:
	    break;
    	case RPL_TOPIC:
	    strtok(argbuff, " \r\n");
	    strcpy(tobuff, strtok(NULL, " \r\n"));
	    strcpy(msgbuff,(strtok(NULL, "\r\n") + 1));
	    [[NXApp managerOf:tobuff] setTopic:msgbuff];	    
	    break;
    	case RPL_INVITING:
	    break;
    	case RPL_SUMMONING:
	    break;
    	case RPL_VERSION:
	    break;
    	case RPL_WHOREPLY:
	    break;
    	case RPL_ENDOFWHO:
	    break;
    	case RPL_NAMREPLY:
	    strtok(argbuff, " \r\n");
	    strtok(NULL, " \r\n");
	    strcpy(tobuff, strtok(NULL, " \r\n"));
	    strcpy(msgbuff,(strtok(NULL, "\r\n") + 1));
	    [[NXApp managerOf:tobuff] setNames:msgbuff];	    
	    break;
    	case RPL_ENDOFNAMES:
	    [[NXApp managerOf:tobuff] endNames];	    
	    break;
    	case RPL_LINKS:
	    break;
    	case RPL_ENDOFLINKS:
	    break;
    	case RPL_BANLIST:
	    break;
    	case RPL_ENDOFBANLIST:
	    break;
    	case RPL_INFO:
	    break;
    	case RPL_ENDOFINFO:
	    break;
    	case RPL_MOTDSTART:
	    break;
    	case RPL_MOTD:
	    break;
    	case RPL_ENDOFMOTD:
	    break;
    	case RPL_YOUREOPER:
	    break;
    	case RPL_REHASHING:
	    break;
    	case RPL_TIME:
	    break;
    	case RPL_USERSSTART:
	    break;
    	case RPL_USERS:
	    break;
    	case RPL_ENDOFUSERS:
	    break;
    	case RPL_NOUSERS:
	    break;
    	case RPL_TRACELINK:
	    break;
    	case RPL_TRACECONNECTING:
	    break;
    	case RPL_TRACEHANDSHAKE:
	    break;
    	case RPL_TRACEUNKNOWN:
	    break;
    	case RPL_TRACEOPERATOR:
	    break;
    	case RPL_TRACEUSER:
	    break;
    	case RPL_TRACESERVER:
	    break;
    	case RPL_TRACENEWTYPE:
	    break;
    	case RPL_TRACELOG:
	    break;
    	case RPL_STATSLINKINFO:
	    break;
    	case RPL_STATSCOMMANDS:
	    break;
    	case RPL_STATSCLINE:
	    break;
    	case RPL_STATSNLINE:
	    break;
    	case RPL_STATSILINE:
	    break;
    	case RPL_STATSKLINE:
	    break;
    	case RPL_STATSYLINE:
	    break;
    	case RPL_ENDOFSTATS:
	    break;
    	case RPL_STATSLLINE:
	    break;
    	case RPL_STATSUPTIME:
	    break;
    	case RPL_STATSOLINE:
	    break;
    	case RPL_STATSHLINE:
	    break;
    	case RPL_UMODEIS:
	    break;
    	case RPL_LUSERCLIENT:
	    break;
    	case RPL_LUSEROP:
	    break;
    	case RPL_LUSERUNKNOWN:
	    break;
    	case RPL_LUSERCHANNELS:
	    break;
    	case RPL_LUSERME:
	    break;
    	case RPL_ADMINME:
	    break;
    	case RPL_ADMINLOC1:
	    break;
    	case RPL_ADMINLOC2:
	    break;
    	case RPL_ADMINEMAIL:
	    break;
	default:
	    break;
	}
    }
    return self;
}

- sendToServer:(const char *)message
{
    int			ret;
    int			size;
    static char		buff[BUFSIZ+1];

    bzero(buff, (BUFSIZ+1));
    size = euc2jis((char *)message, buff, strlen(message));
    ret = [socket sendData:(char *)buff sizeOf:size];

    if (ret != 1) {
    	return nil;
    }
    return self;
}

- checkDefaults
{
    const char		*dvalue;

    dvalue = NXReadDefault([NXApp appName], "ServerName");
    if (dvalue) {
    	if (strlen((char *)dvalue) == 0) return nil;
	strcpy(server, (char *)dvalue);
    } else return nil;

    dvalue = NXReadDefault([NXApp appName], "ServerPort");
    if (dvalue) {
    	if (strlen((char *)dvalue) == 0) return nil;
	port = (u_short)atoi(dvalue);
    } else return nil;

    dvalue = NXReadDefault([NXApp appName], "NickName");
    if (dvalue) {
    	if (strlen((char *)dvalue) == 0) return nil;
	strcpy(nickname, (char *)dvalue);
    } else return nil;

    dvalue = NXReadDefault([NXApp appName], "RealName");
    if (dvalue) {
    	if (strlen((char *)dvalue) == 0) return nil;
	strcpy(realname, (char *)dvalue);
    } else return nil;

    return self;
}

- (char *)takeNickName
{
    return nickname;
}

- sendNICK:(char *)nick
{
    sprintf(sendbuff, "%s %s\n", MSG_NICK, nickname);
    [self sendToServer:sendbuff];
    return self;
}

- sendUSER
{
    sprintf(sendbuff, "%s %s %s %s :%s\n", MSG_USER, NXUserName(),
    		 NXSystemDomainName, server, realname);
    [self sendToServer:sendbuff];
    return self;
}

- sendLIST
{
    sprintf(sendbuff, "%s\n", MSG_LIST);
    [self sendToServer:sendbuff];
    return self;
}

- sendLIST:(char *)channel
{
    sprintf(sendbuff, "%s %s\n", MSG_LIST, channel);
    [self sendToServer:sendbuff];
    return self;
}

- sendNAMES:(char *)channel
{
    sprintf(sendbuff, "%s %s\n", MSG_NAMES, channel);
    [self sendToServer:sendbuff];
    return self;
}

- sendTOPIC:(char *)channel
{
    sprintf(sendbuff, "%s %s\n", MSG_TOPIC, channel);
    [self sendToServer:sendbuff];
    return self;
}

- sendTOPIC:(char *)channel altTopic:(char *)topic
{
    sprintf(sendbuff, "%s %s ;%s\n", MSG_TOPIC, channel, topic);
    [self sendToServer:sendbuff];
    return self;
}

- sendJOIN:(char *)channel
{
    sprintf(sendbuff, "%s %s\n", MSG_JOIN, channel);
    [self sendToServer:sendbuff];
    return self;
}

- sendPART:(char *)channel
{
    sprintf(sendbuff, "%s %s\n", MSG_PART, channel);
    [self sendToServer:sendbuff];
    return self;
}

- sendPRIVMSG:(char *)message to:(char *)receiver
{
    sprintf(sendbuff, "%s %s :%s\n", MSG_PRIVMSG, receiver, message);
    [self sendToServer:sendbuff];
    return self;
}

- sendNOTICE:(char *)message to:(char *)receiver
{
    sprintf(sendbuff, "%s %s :%s\n", MSG_NOTICE, receiver, message);
    [self sendToServer:sendbuff];
    return self;
}

- sendPONG
{
    sprintf(sendbuff, "%s %s\n", MSG_PONG, nickname);
    [self sendToServer:sendbuff];
    return self;
}

- sendAWAY
{
    sprintf(sendbuff, "%s\n", MSG_AWAY);
    [self sendToServer:sendbuff];
    return self;
}

- sendAWAY:(char *)message
{
    sprintf(sendbuff, "%s :%s\n", MSG_AWAY, message);
    [self sendToServer:sendbuff];
    return self;
}

- sendQUIT
{
    sprintf(sendbuff, "%s\n", MSG_QUIT);
    [self sendToServer:sendbuff];
    return self;
}

- sendQUIT:(char *)message
{
    sprintf(sendbuff, "%s :%s\n", MSG_QUIT, message);
    [self sendToServer:sendbuff];
    return self;
}

- replyVERSION:(char *)name
{
    sprintf(sendbuff, "%s %s :\001VERSION IRC.app 0.5 NEXTSTEP 3.2J :VERSION IRC.app 0.5 for NEXTSTEP 3.2J\001\n",
    		MSG_NOTICE, name);
    [self sendToServer:sendbuff];
    return self;
}

- replyCLIENTINFO:(char *)name
{
    sprintf(sendbuff, "%s %s :\001CLIENTINFO :VERSION CLIENTINFO\001\n",
    		MSG_NOTICE, name);
    [self sendToServer:sendbuff];
    return self;
}

@end

void 
receive(int fd, void *obj)
{
    [(id)obj receiveFromServer];
}
