/* msg.c        -private msges and notes 
 * 
 * Author: Tano Fotang, 1997
 * 
 * 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 file COPYING for mre info.
 * 
 */

#include <forms.h>
#include <time.h>
#include <stdarg.h>
#include "aux.h"
#include "sula.h"
#include "chanwin.h"
#include "global.h"
#include "script.h"
#include "parser.h"
#include "dcc.h"
#include "setting.h"
#include "ignore.h"
#include "cmd.h"
#include "lag.h"
extern Winstruct *Win;/* parser window */
/* 
 * topic, invite, privmsg , note & notice
 * 
 */

/****************************************************************
 * 
 * T O P I C                                    
 * 
 ****************************************************************/

extern void p_topic(void)
{
	char   *channel=NULL, *sender=NULL, *newtopic=NULL,
	 *nick=NULL, *host=NULL, *login=NULL;
	size_t  ll = strlen(Msg);
	Channel *chan;

	channel = (char *) malloc(sizeof(char) * ll);
	sender = (char *) malloc(sizeof(char) * ll);
	
	newtopic = (char *) malloc(sizeof(char) * ll);

	if (sscanf(Msg, "%s TOPIC %s %[^\r\n]\r\n", sender, channel, newtopic) < 3)
		goto fini;
	/*if(X>1){
		Win= get_win_bychanname(Win->server->fd, channel);
		if(!Win) goto fini;
	}  */
	ll = strlen(sender);
	nick = (char *) malloc(sizeof(char) * ll);
	host = (char *) malloc(sizeof(char) * ll);
	login = (char *) malloc(sizeof(char) * ll);

	if (sscanf(sender, "%[^!]!", nick) < 1)
		nick = strdup("<unknown>");
	if (sscanf(sender, "%*[^!]!%[^@]@", login) < 1)
		login = strdup("<unknown>");

	chan = get_chan_byname(Win, channel);
	if (!chan)
		goto fini;		/* fatal error. should quit program. well, next time i look at this */
	newtopic = clean(++newtopic);	/*  whitespaces alone
					 * shldnt be considered a chanel topic.*/
	if (!newtopic /*|| !(*newtopic) */ ) {
		chan->topic = NULL;
		if (!ignored(sender, IG_MISC) && !check_msg(TOPIC, Msg)) {
			char    buf[256];

			if (gflags & SHOW_RAW_MSG)
				fl_addto_browser(Win->chanwin->brow2, Msg);
			else {
				if (sscanf(sender, "%*[^!]!%s", host) < 1)
					host = strdup("<unknown>");
				sprintf(buf, "%s (%s) has cleared the topic on %s", nick, host, channel);
				fl_addto_browser(Win->chanwin->brow2, buf);
			}
		}
		update_topic(Win, channel, "<" sula_NAME sula_VERSION "> says no topic has been set");
	}
	else {
	  chan->topic = strdup(newtopic);
	  if(!check_msg(TOPIC, Msg)){
		if (!ignored(sender, IG_MISC)) {
			if (gflags & SHOW_RAW_MSG)
				fl_addto_browser(Win->chanwin->brow2, Msg);
			else {
				char   *buf;
				if (sscanf(sender, "%*[^@]@%s", host) < 1)
					host = strdup("<unknown>");
				fmt_string = "%n%l%h%c%p$";
				buf = format_msg(fmt_topic, nick, login, host, channel, newtopic);
				if (buf){
					fl_addto_browser(Win->chanwin->brow2, buf);
					free(buf);
				}
			}
		}
	   }
	   update_topic(Win, channel, newtopic);
	}
fini:
	free(nick); free(host); free(channel);
	free(sender);
	free(newtopic);

}

/****************************************************************/
/* */
/* I N V I T E                                  */
/* */
/****************************************************************/
#ifndef NOLAG
static int is_lag(const char *nick, const char *chan, Winstruct *win){
	struct timeval t;
	t.tv_usec=0;
	if(sscanf(chan,"__%u_%u", &t.tv_sec, &t.tv_usec)<1){
		/*fprintf(stderr,"%s=%s? %s\n", nick, win->server->nick,chan);*/
		return 0;
		}
	#if PARANOID
	if(
	/* make sure it's from us.
		wont work if server is too lagged and u change nick..?*/ 
	!strcasecmp(nick, win->server->nick)
	)
	#endif
	{
	struct timeval now;
	gettimeofday(&now,NULL);
	update_lag_display(win->server, now.tv_sec- t.tv_sec+
		    (float)((now.tv_usec- t.tv_usec)/ 1000000.0),
		     &t );

	}
	return 1;
}
#endif

extern void p_invite(void)
{
	char   *sender = NULL, *nick = NULL, *channel = NULL;
	char   *login = NULL, *host = NULL, *buf=NULL;
	size_t  ll;
	
	ll = strlen(Msg);
	sender = (char *) malloc(sizeof(char) * ll);
	channel = (char *) malloc(sizeof(char) * ll);
	sscanf(Msg, "%s", sender);
	ll = strlen(sender);
	nick = (char *) malloc(sizeof(char) * ll);
	if (sscanf(sender, "%[^!]!%*s", nick) < 1)
		nick = strdup("<unknown>");
	if (sscanf(Msg, "%*s INVITE %*s :%s", channel) < 1)
		goto done;
	#ifndef NOLAG
	if(is_lag(nick, channel, Win)) goto done;
	#endif
	
	host = (char *) malloc(sizeof(char) * ll);
	login = (char *) malloc(sizeof(char) * ll);
	
	if (sscanf(sender, "%*[^!]!%[^@]@", login) < 1)
		login = strdup("<unknown>");
	if (sscanf(sender, "%*[^@]@%s", host) < 1)
		host = strdup("<unknown>");
	
	if (ignored(sender, IG_INVITE)) {
		if (gflags & INFORM_IGNORED) {
			char   *s;
			fmt_string = "%n%l%h%c%p$";
			buf = format_msg(fmt_ignored, nick, login, host, channel, "INVITE");
			if (!buf)
				goto done;
			s = (char *) malloc(sizeof(char) * (strlen(buf) + strlen(nick) + 20));
			if (!s) {
				err_ret("%s %s", __FILE__, __LINE__);
				goto done;
			}
			sprintf(s, "NOTICE %s :%s\n", nick, buf);
			sendto_server(Win, s);
			free(s); free(buf);
		}
		goto done;
	}
	if(check_msg(INVITE, Msg)) goto done;
	Win->server->lastInvite = strdup(channel);
	if (sflags & S_INVITE)
		addto_sender(sender, SS_INVITE);
	if ( Win->server->flag&SET_AWAY && (gflags & BEEP_AWAY))
			fl_ringbell(0);
	if (gflags & SHOW_RAW_MSG)
		fl_addto_browser(Win->chanwin->brow2, Msg);
	else {
		fmt_string = "%n%l%h%c%p$";
		buf = format_msg(fmt_invite, nick, login, host, channel, channel);
		if (buf){
			fl_addto_browser(Win->chanwin->brow2, buf);
			free(buf);
		}
	}
	if (gflags & AUTO_INVITE) {
		buf=(char *) malloc(sizeof(char) * (strlen(channel)+40));
		if (gflags & VERBOSE_CLIENT){
			sprintf(buf, "Auto-accepting invitation to %s", channel);
			fl_addto_browser(Win->chanwin->brow2, buf);
		}
		addto_cmd_sent(Win, "JOIN", channel);
		sprintf(buf, "JOIN  %s\n", channel);
		sendto_server(Win, buf);
		free(buf);
	}
done:
	free(sender);free(nick);free(host);free(login); free(channel);

}

/****************************************************************
* 
* N O T E  N O T I C E                         
* 
*  i dont know if this works at all
****************************************************************/
extern void p_note(void)
{
	char   *buf;
	int     D = strlen(Msg);

	
	buf = (char *) malloc(sizeof(char) * D);

	if (!buf) {
		err_ret("no mem");
		return;
	}
	if ((sscanf(Msg, "NOTICE %*s :%[^\n]\n", buf) < 1))
		{free(buf);return;}
	if (*buf == '#') {
		if(!check_msg(NOTE, Msg)){
		*(buf + strlen(buf) - 1) = '\0';
		berr_msg("-%s- %s", Win->server->servname, buf + 3);
		}
		free(buf);
		return;
	}
	else {
		char   *buf2, *email, *nick;

		int     D = strlen(Msg);

		email = (char *) malloc(sizeof(char) * D);
		nick = (char *) malloc(sizeof(char) * D);
		buf2 = (char *) malloc(sizeof(char) * D);

		if (!email || !nick || !buf2) {
			err_ret("no mem");
			return;
		}
		if (sscanf(Msg, "%*s %*s %*s %*s %s", buf2) < 1)
			goto done;	/*nnote: buf2 is sender */
		if (ignored(buf2, IG_NOTE)) {
			#if 0
			/* may cause a ping-pong*/
			if (gflags & INFORM_IGNORED) {
				if (sscanf(buf2, "%[^!]!%s", nick, email) < 2)
					goto done;
				fmt_string = "%n%h%p$";
				free(buf2);
				buf2 = format_msg(fmt_ignored, nick, email, "NOTE");
				if (!buf2)
					goto done;
				free(buf);
				buf = (char *) malloc(sizeof(char) * (strlen(buf2) 
				+ strlen(email) + strlen(nick) + 30));
				if (!buf) {
					err_ret("no mem");
					goto done;
				}
				sprintf(buf, "NOTE USER %s!%s :%s\n",
				 nick, email, buf2);
				sendto_server(Win, buf);
			}
			#endif
			goto done;
		}
		if(check_msg(NOTE, Msg)) {goto done;}
		if (gflags & SHOW_RAW_MSG)
			berr_msg(Msg);
		else {
			int     H, M;
			char    d[] = "0000", h[] = "00", m[] = "00";

			if (sscanf(Msg, 
		"%*s %*s %*s %*s %[^!]!%s /%[^d:]d:%[^h]h:%[^m/]m/ %*s %[^\n]\n",
				   nick, email, d, h, m, buf2) < 6) {
				berr_msg("-%s- %s", Win->server->servname, buf);
			}else{
				D = atoi(d);
				H = atoi(h);
				M = atoi(m);
			   berr_msg("-%s- Note from %s (%s) %s%s%s%s%s%s%d min%s ago:",
				 Win->server->servname,
				 nick, email, D ? d : "", D ? "day" : "", D > 1 ? "s " : D ? " " : "", 
				 (H) ? h : "", H ? "hr" : "", H > 1 ? "s " : H ? " " : "", M, M != 1 ? "s" : "");
			berr_msg("\t%s", buf2);
			}
		}
		fl_ringbell(10);
		done:
	       free(email); free(nick);
	}
}

/****************************************************************/
/* 								*/
/* P R I V M S G                                        	*/
/*								*/
/* N O T I C E                                  		*/
/* 								*/
/****************************************************************/

extern void p_privmsg(int flag)
{

/*------------------------------------------------------*/
/* d o  d c c                                   	*/
/*------------------------------------------------------*/
	if (flag != NOTICE && ctcp_cmd())
		return;
/*------------------------------------------------------*/
/* d o  o t h e r s                             	*/
/*------------------------------------------------------*/
	else {
		static int ctcp_reply(const char *, const char *, 
		const char *, const char *);
		char   *sender = NULL, *nick = NULL, *name = NULL, *host=NULL,
		       *email = NULL, *dest = NULL;
		char   *msg=NULL;
		char   *fmt = NULL;
		char *buf=NULL;
		size_t  ll;
		int     i;

		ll = strlen(Msg);
		sender = (char *) malloc(sizeof(char) * ll);
		dest = (char *) malloc(sizeof(char) * ll);
		msg = (char *) malloc(sizeof(char) * ll);
		if (flag == NOTICE)
			i = sscanf(Msg, "%s NOTICE %s :%[^\r\n]\r\n", sender, dest, msg);
		else
			i = sscanf(Msg, "%s PRIVMSG %s :%[^\r\n]\r\n", sender, dest, msg);
		if (i < 3) {
			if (i == 2) {
				sscanf(Msg, "%*s %*s %[^\r\n]\r\n", msg);
				berr_msg("-%s- %s", sender, msg);
			}
			goto fini;
		}
		ll = strlen(sender);
		nick = (char *) malloc(sizeof(char) * ll);
		email = (char *) malloc(sizeof(char) * ll);
		if (sscanf(sender, "%[^!]!%s", nick, email) < 2) {
			/* is not nick!user@host : probably server error */
			berr_msg("-%s- %s", sender, msg);
			goto fini;
		}
		if (ctcp_reply(nick, *email =='~'?email+1:email, dest, msg))
			goto fini;
		host = (char *) malloc(sizeof(char) * ll);
		name = (char *) malloc(sizeof(char) * ll);
		if (sscanf(email, "%[^@]@%s", name, host) < 2) {
			free(host);
			host = strdup( "<unknown>");
			name = email;
		}
		free(email);
		email = NULL;

		if (*dest == '#' || *dest == '&') {
			if (ignored(sender, flag == NOTICE ? IG_PUBNOTICE : IG_PUBMSG)) {
				char   *s = NULL;

				if (flag == NOTICE || !(gflags & INFORM_IGNORED))
					return;
				fmt_string = "%n%l%h%c%p$";
				s = format_msg(fmt_ignored, nick, name, host, dest, "CHANNEL MSG");
				if (!s) goto fini;
				buf = (char *) malloc(sizeof(char) * (strlen(s) + strlen(nick) + 15));
				if (!buf) {
					err_ret("%s %d", __FILE__, __LINE__);
					goto fini;
				}
				sprintf(buf, "NOTICE %s :%s\n", nick, s);
				sendto_server(Win, buf);
				free(s);
			        goto fini;
			}
			if(check_msg(flag == NOTICE?PUBNOTICE:PUBMSG, Msg))
				goto fini;
			if (!get_user_byuser(get_chan_byname(Win, dest), nick))
				/* sender of msg is not  on this channel */
				fmt = flag == NOTICE ? fmt_pub_notice3 : fmt_pub_msg3;
			else if (strcasecmp(dest, Win->chanCur->name))
				/* this isnt my current channel */
				fmt = flag == NOTICE ? fmt_pub_notice2 : fmt_pub_msg2;
			else
				fmt = flag == NOTICE ? fmt_pub_notice : fmt_pub_msg;
		}
		else {		/* this is a private msg/notice */
			if (ignored(sender, flag == NOTICE ? IG_PRIVNOTICE : IG_PRIVMSG)) {
				char   *s = NULL;

				if (flag == NOTICE || !(gflags & INFORM_IGNORED))
					goto fini;
				fmt_string = "%n%l%h%c%p$";
				s = format_msg(fmt_ignored, nick, name, host, dest, "PRIVATE MSG");
				if (!s)
					goto fini;
				buf = (char *) malloc(sizeof(char) * (strlen(s) + 
					strlen(nick) + 15));
				if (!buf) {
					err_ret("%s %d", __FILE__, __LINE__);
					goto fini;
				}
				sprintf(buf, "NOTICE %s :%s\n", nick, s);
				sendto_server(Win, buf);
				free(s);
				goto fini;
			}
			if(check_msg(flag == NOTICE?PRIVNOTICE:PRIVMSG, Msg))
				goto fini;
			if (flag == NOTICE) {
				if (sflags & S_NOTICE)
					addto_sender(sender, SS_NOTICE);
			}
			else if (sflags & S_MSG)
				addto_sender(sender, SS_MSG);
			fmt = flag == NOTICE ? fmt_priv_notice : fmt_priv_msg;
			if ((gflags & BEEP_MSG) || ( Win->server->flag&SET_AWAY && (gflags & BEEP_AWAY)))
				fl_ringbell(0);
		}
		/*ll = strlen(msg);*/
		if (*msg == 0x02){
			char *pmsg=msg;
			switch (*++pmsg) {
			    case 0x02:
			    	{
				char *buf2;
				pmsg++;
				unquote_str(&pmsg);
				fmt_string = "%f%n%l%h%c%p%z%Z$";
				buf2 = format_msg(
					fmt, Win->server->servname, nick, name,
					 host, dest, pmsg, strlen(Msg),
					 Win->server->read);
				if (buf2){
					fl_addto_browser(Win->chanwin->browser, buf2);
					free(buf2);
				}
				goto fini;
				}
			    default:
				    break;

			}	/*switch */
		}
		if (gflags & SHOW_RAW_MSG) {
			fl_addto_browser(Win->chanwin->browser, Msg);
		}
		else {
			char   *ptr = NULL;

			fmt_string = "%f%n%l%h%c%p%z%Z$";
			ptr = format_msg(
						fmt,
						Win->server->servname,
						nick, name, host, dest, msg,
					      strlen(Msg), Win->server->read
			   );
			if (ptr){
				fl_addto_browser(Win->chanwin->browser, ptr);
				free(ptr);
			}
			
		}

	fini:
	free(sender);free(nick);free(dest);
	free(msg); free(buf);free(name); free(host);
	}
}


static int ctcp_reply(const char *nick, const char *email, const char *dest,
		      const char *msg)
{

	/* handle a cTCP reply */
	char   *str;
	char   *buf, *ptr, *s=NULL;
	size_t  ll = strlen(msg);
     /*todo: free buf */
	buf = (char *) malloc(sizeof(char) * ll);
	str = (char *)(msg);
	ptr = buf;
	if (str && *str != 0x01)
		return 0;
	while (*++str && *str != 0x01)
		*ptr++ = *str;
	if (*str != 0x01)
		return 0;
	*ptr = '\0';		/* ignore all else after 0x01 */
	if(check_msg(CTCP_REPLY, Msg)) return 1;
	if (gflags & SHOW_RAW_MSG) {
		fl_addto_browser(Win->chanwin->brow2, Msg);
		return 1;
	}
	str = nextstr(buf, 1);
	if (!strcasecmp(str, "PING")) {
		struct timeval t, t2;
		int i=sscanf(buf, "%*s %u %u", &t.tv_sec, &t.tv_usec);
		if(i<1) return 1;
		if(i<2) t.tv_usec=0;
		gettimeofday(&t2, NULL);
		s = (char *) malloc(sizeof(char) * (ll + 64));
		sprintf(s, "CTCP PING reply from %s: %f seconds", nick,
		 (float)(t2.tv_sec-t.tv_sec+
		    (float)((t2.tv_usec- t.tv_usec)/ 1000000.0)
		 )
		 );
		fl_addto_browser(Win->chanwin->brow2, s);

	}
	else{
		if(*buf==0x02 && *(buf+1)==0x02){
			buf+=2;
			unquote_str(&buf); /* newline, tab*/
		}
		rmstr(&buf, 1);/*rm ctcp cmdname*/
		s = (char *) malloc(sizeof(char) * (ll + 64));
		sprintf(s, "CTCP %s reply from %s: %s", str, nick, buf);
		fl_addto_browser(Win->chanwin->brow2, s);
	}
	free(s);
	return 1;
}



