/* chat.c */

/* Synchronet for *nix sysop chat routines */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
 *																			*
 * 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.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include <sys/types.h>
#include <utime.h>

#include "sbbs.h"
#include "chat.h"

#define PCHAT_LEN 1000		/* Size of Private chat file */

bool togglechat(scfg_t *cfg, int node_num, node_t *node, bool on)
{
    static int  org_act;

	int nodefile;
	if(getnodedat(cfg,node_num,node,&nodefile)) {
		return(FALSE);
	}
    if(on) {
        org_act=node->action;
        if(org_act==NODE_PCHT)
            org_act=NODE_MAIN;
        node->misc|=NODE_LCHAT;
    } else {
        node->action=org_act;
        node->misc&=~NODE_LCHAT;
    }
	putnodedat(cfg,node_num,node,nodefile);
    return(TRUE);
}

void wsetcolor(WINDOW *win, int fg, int bg)  {
	int   attrs=A_NORMAL;
	short	colour;
	int		lastfg=0;
	int		lastbg=0;

	if (lastfg==fg && lastbg==bg)
		return;

	lastfg=fg;
	lastbg=bg;

	if (fg & 8)  {
		attrs |= A_BOLD;
	}
	wattrset(win, attrs);
	colour = COLOR_PAIR( ((fg&7)|(bg<<3))+1 );
	#ifdef NCURSES_VERSION_MAJOR
	wcolor_set(win, colour,NULL);
	#endif
	wbkgdset(win, colour);
}

void drawchatwin(WINDOW **uwin, WINDOW **swin, box_t *boxch, const char* topname, const char* botname) {
	int maxy,maxx;

	endwin();
	getmaxyx(stdscr,maxy,maxx);
	*uwin=newwin(maxy/2-1,maxx,1,0);
	*swin=newwin(maxy-maxy/2-1,maxx,maxy/2,0);
	wsetcolor(*uwin,YELLOW,BLUE);
	wclear(*uwin);
	wborder(*uwin,  boxch->ls, boxch->rs, boxch->ts, boxch->bs, boxch->tl, boxch->tr, boxch->bl, boxch->br);
	wmove(*uwin,0,5);
	waddstr(*uwin,topname);
	wmove(*uwin,1,2);
	scrollok(*uwin,TRUE);
	wrefresh(*uwin);
	wsetcolor(*swin,YELLOW,BLUE);
	wclear(*swin);
	wborder(*swin,  boxch->ls, boxch->rs, boxch->ts, boxch->bs, boxch->tl, boxch->tr, boxch->bl, boxch->br);
	wmove(*swin,0,5);
	waddstr(*swin,botname);
	wmove(*swin,1,2);
	scrollok(*swin,TRUE);
	wrefresh(*swin);
}

int chatchar(WINDOW *win, int ch, box_t *boxch, const char* name) {
	int	maxy,maxx;
	int	cury,curx;
	getmaxyx(win,maxy,maxx);
	getyx(win,cury,curx);
	switch(ch) {
		case 8:
			curx-=1;
			if(curx<2)
				curx+=1;
			mvwaddch(win,cury,curx,' ');
			wmove(win,cury,curx);
			wrefresh(win);
			break;

		case '\r':
		case '\n':
			curx=2;
			cury+=1;
			wmove(win,cury,curx);
			if(cury>=maxy-1) {
				wscrl(win,1);
				cury-=1;
				wmove(win,cury,curx-1);
				whline(win,' ',maxx-2);
				wborder(win, boxch->ls, boxch->rs, boxch->ts, boxch->bs, boxch->tl, boxch->tr, boxch->bl, boxch->br);
				wmove(win,0,5);
				waddstr(win,name);
				wmove(win,cury,curx);
			}
			wrefresh(win);
			break;
			
		case TAB:
			curx+=8;
			curx-=((curx-2)%8)+1;
			wmove(win,cury,curx);
			ch=' ';
		default:
			waddch(win,ch);
			getyx(win,cury,curx);
			if(curx>=maxx-2) {
				curx=2;
				cury+=1;
				if(cury>=maxy-1) {
					wscrl(win,1);
					cury-=1;
					wmove(win,cury,curx-1);
					whline(win,' ',maxx-2);
					wborder(win, boxch->ls, boxch->rs, boxch->ts, boxch->bs, boxch->tl, boxch->tr, boxch->bl, boxch->br);
					wmove(win,0,5);
					waddstr(win,name);
				}
				wmove(win,cury,curx);
			}
			wrefresh(win);
	}
	return(0);
}

int chat(scfg_t *cfg, int nodenum, node_t *node, box_t *boxch, void(*timecallback)(void)) {
	WINDOW	*uwin;
	WINDOW	*swin;
	int		in,out;
	char	inpath[MAX_PATH];
	char	outpath[MAX_PATH];
	char	usrname[128];
	char	*p;
	char	ch;

	username(cfg,node->useron,usrname);

	drawchatwin(&uwin,&swin,boxch,usrname,cfg->sys_op);

	if(getnodedat(cfg,nodenum,node,NULL)) {
		return(-1);
	}

	sprintf(outpath,"%slchat.dab",cfg->node_path[nodenum-1]);
	if((out=sopen(outpath,O_RDWR|O_CREAT|O_BINARY,O_DENYNONE
		,S_IREAD|S_IWRITE))==-1) {
		return(-1);
	}

	sprintf(inpath,"%schat.dab",cfg->node_path[nodenum-1]);
	if((in=sopen(inpath,O_RDWR|O_CREAT|O_BINARY,O_DENYNONE
		,S_IREAD|S_IWRITE))==-1) {
		close(out);
		return(-1);
    }

	if((p=(char *)MALLOC(PCHAT_LEN))==NULL) {
		close(in);
		close(out);
		return(-1);
    }
	memset(p,0,PCHAT_LEN);
	write(in,p,PCHAT_LEN);
	write(out,p,PCHAT_LEN);
	FREE(p);
	lseek(in,0,SEEK_SET);
	lseek(out,0,SEEK_SET);
	halfdelay(1);

	togglechat(cfg,nodenum,node,TRUE);

	while(in != -1) {
		if(timecallback != NULL)
			timecallback();
		utime(outpath,NULL);
		utime(inpath,NULL);
		
		if(getnodedat(cfg,nodenum,node,NULL)) {
			break;
		}
		if(node->misc&NODE_LCHAT) {
			if((ch=wgetch(swin))) {
				if(ch==ESC || ch==3) {
					close(in);
					in=-1;
				}
			}
			YIELD();
			continue;
		}
		
		if(!node->status || node->status>NODE_QUIET || node->action!=NODE_PCHT) {
			close(in);
			in=-1;
		}
		switch (read(in,&ch,1)) {
			case -1:
				close(in);
				in=-1;
				break;
				
			case 0:
				lseek(in,0,SEEK_SET);	/* Wrapped */
				continue;
				
			case 1:
				lseek(in,-1L,SEEK_CUR);
				if(ch) {
					chatchar(uwin,ch,boxch,usrname);
					ch=0;
					write(in,&ch,1);
				}
		}
		if((ch=wgetch(swin))) {
			switch(ch)  {
				case 0:
				case ERR:
					ch=0;
					write(out,&ch,1);
					lseek(out,-1,SEEK_CUR);
					break;
					
				case ESC:
				case 3:
					close(in);
					in=-1;
					continue;
					
				default:
					if(lseek(out,0,SEEK_CUR)>=PCHAT_LEN)
						lseek(out,0,SEEK_SET);
					chatchar(swin,ch,boxch,cfg->sys_op);
					switch(write(out,&ch,1)) {
						case -1:
							close(in);
							in=-1;
							break;
					}
			}
		}
	}
	if(in != -1)
		close(in);
	if(out != -1)
		close(out);
	nocbreak();
	cbreak();
	togglechat(cfg,nodenum,node,FALSE);
	delwin(uwin);
	delwin(swin);
	touchwin(stdscr);
	refresh();
	return(0);
}