# infobot :: Kevin Lenzo 1997

# process the incoming message

$SIG{'ALRM'} = 'TimerAlarm';

sub process {
    ($who, $msgType, $message) = @_;
    $origMessage = $message;
    $message =~ s/[\cA-\c_]//ig; # strip control characters

    $addressed = 0;

    return if $instance =~ /antihelp/;

    my ($n, $uh) = ($nuh =~ /^([^!]+)!(.*)/);

    if ($msgType =~ /private/ and $message =~ /^hey, what is/) {
	$infobots{$nuh} = $who;
	&msg($who, "inter-infobot communication now requires version 0.43 or higher.");
	return 'NOREPLY';
    }

    return 'NOREPLY' if $message =~ /^...but/;
    return 'NOREPLY' if $message =~ /^.* already had it that way/;
    return 'NOREPLY' if $message =~ /^told /; # reply from friendly infobot
    return 'NOREPLY' if $message =~ /^told /; # reply from friendly infobot
    return 'NOREPLY' if ($message =~ /^[!\*]/);
    return 'NOREPLY' if ($message =~ /^gotcha/i);

    return 'NOREPLY' if ($ignoreList{$uh});
    return 'NOREPLY' if ($ignoreList{$who});

    return 'NOREPLY' if (lc($who) eq lc($param{'nick'}));

    if ($msgType =~ /private/ and $message =~ s/^:INFOBOT://) {
	&status("infobot <$nuh> identified") unless $infobots{$nuh};
	$infobots{$nuh} = $who;
    }

    if ($infobots{$nuh}) {
	if ($msgType =~ /private/) {
	    if ($message =~ /^QUERY (<.*?>) (.*)/) {
		my $r;
		my $target = $1;
		my $item = $2;
		$item =~ s/[.\?]$//;
		
		&status(":INFOBOT:QUERY $who: $message");

		if ($r = &get("is", $item)) {
		    &msg($who, ":INFOBOT:REPLY $target $item =is=> $r");
		} 
		if ($r = &get("are", $item)) {
		    &msg($who, ":INFOBOT:REPLY $target $item =are=> $r");
		}
		return 'NOREPLY';
	    } elsif ($message =~ /^REPLY <(.*?)> (.*)/) {
		my $r;
		my $target = $1;
		my $item = $2;


		&status(":INFOBOT:REPLY $who: $message");

		my ($X, $V, $Y) = $item =~ /^(.*?) =(.*?)=> (.*)/;
		if ($param{'acceptURL'} ne "REQUIRE" or $Y =~ /(http|ftp|mailto|telnet|file):/) {
		    &set($V, $X, $Y);
		    &msg($target, "$who knew: $X $V $Y");
		}

		return 'NOREPLY';
	    }

	} else {
	    return 'NOREPLY';
	}
    }

    $VerifWho = &verifyUser($nuh);
    my $now = time();
    $seen{$who} = $now;

    if ($VerifWho) {
	$uFlags = $user{$VerifWho."flags"};
	$uPasswd = $user{$VerifWho."pass"};
	$uTitle = $user{$VerifWho."title"};

	if (not exists $seenVerif{$VerifWho} or time()-$seenVerif{$VerifWho} > 360) {
	    status("mask verified for $VerifWho");
	}

	$seenVerif{$VerifWho} = $now;
	# inside hostmask list

	if ($msgType =~ /private/) {
	    # it's a private message
	    my ($potentialPass) = $message =~ /^\s*(\S+)/;

	    if (exists($verified{$VerifWho})) {
		# aging. you need to keep talking to it re-verify
		if (time() - $verified{$VerifWho} < 60*60) { # 1 hour decay
		    $verified{$VerifWho} = $now;
		} else {
		    &status("verification for $VerifWho expired");
		    delete $verified{$VerifWho};
		}
	    }

	    if ($uPasswd eq "NONE_NEEDED") {
		&status("no password needed for $VerifWho");
		$verified{$verifWho} = $now;
	    }

	    if (&ckpasswd($potentialPass, $uPasswd)) {
		$message =~ s/^\s*\S+\s*//;
		$origMessage =~ s/^\s*\S+\s*/<PASSWORD> /;
		&status("password verified for $VerifWho");
		$verified{$VerifWho} = $now;
		if ($message =~ /^\s*$/) {
		    &msg($who, "i recognize you there");
		    return 'NOREPLY';
		}
	    }
	}
    }

    # see User.pl for the "special" user commands
    return 'NOREPLY' if &userProcessing() eq 'NOREPLY';

    if ($msgType !~ /public/) { $addressed = 1; }

    if ($message =~ /^\s*$param{'nick'}\s*\?*$/i) {
	&status("feedback addressing from $who");
	$addressed = 1;
	$blocked = 0;	   
	if ($msgType =~ /public/) {
	    if (rand() > 0.5) {
		&performSay("yes, $who?");
	    } else {
		&performSay("$who?");
	    }
	} else {
	    &msg($who, "yes?");
	}

	$lastaddressedby = $who;
	$lastaddressedtime = time();
	return '';
    }

    if (($message =~ /^\s*$param{'nick'}\s*([\,\:\> ]+) */i) 
	or ($message =~ /^\s*$param{'nick'}\s*-+ *\??/i)) {
	# i have been addressed!
	my($it) = $&;

	if ($' !~ /^\s*is/i) {
	    $message = $';
	    $addressed = 1;
	    $blocked = 0;   
	}
    }

    if ($message =~ /, ?$param{nick}(\W+)?$/i) { # i have been addressed!
	my($it) = $&; 
	if ($` !~ /^\s*i?s\s*$/i) {
	    $xxx = quotemeta($it);
	    $message =~ s/$xxx//;
	    $addressed = 1;
	    $blocked = 0;   
	}
    }

    my $channel = &channel();

    if ($addressed) {
	&status("$who is addressing me");
	$lastaddressedby = $who;
	$lastaddressedtime = time();
    } else {
	my ($now, $diff);
	$now = time();
	$diff = $now - $lastaddressedtime;
	if ($who eq $lastaddressedby and $diff < 10) {
	    # assume we're talking to the same person even if we're
	    # not addressed, if we've been addressed in 10 seconds 
	    $addressed = 1;
	    &status("assuming continuity of address by $who ($diff seconds elapsed)");
	}
    }

    if ($message =~ s/^forget\s+((a|an|the)\s+)?//i) {
	# cut off final punctuation
	$message =~ s/[.!?]+$//;
	#return 'no authorization to lobotomize';
	#}
	$k = &normquery($message);
	$k = lc($k);

	$found = 0;

	foreach $d ("is", "are") {
	    if ($r = get($d, $k)) { 
		if (IsFlag("r") ne "r") {
		    performReply("you have no access to remove factoids");
		    return '';
		}
		$found = 1 ;
		&status("forget: <$who> $k");
		clear($d, $k); 
		$factoidCount--;
	    }
	}
	if ($found == 1) {
	    if ($msgType =~ /private/) {
		&msg($who, "I forgot $k");
	    } else {
		&say("$who: I forgot $k");
	    }
	    $l = $who; $l =~ s/^=//;
	    $updateCount++;
	    return '';
	} else {
	    if ($msgType !~ /public/) {
		&msg($who, "I didn't have anything matching $k");
		return '';
	    } else {
		if ($addressed > 0) {
		    &say("$who, I didn't have anything matching $k");
		    return '';
		}
	    }
	}
    }

    $target = $who;

    $skipReply = 0;
    $message_input_length = length($message);

    foreach $x (@confused) {
	$y = quotemeta($x);
	return "" if $message =~ /^\s*$y\s*/;
    }

    return if ($who eq $param{'nick'});

    $message =~ s/^\s+//;	# strip any dodgey spaces off

    if (($message =~ s/^\S+\s*:\s+//) or ($message =~ s/^\S+\s+--+\s+//)) {
	# stripped the addressee ("^Pudge: it's there")
	$reallyTalkingTo = $1;
    } else {
	$reallyTalkingTo = '';
	if ($addressed) {
	    $reallyTalkingTo = $param{'nick'};
	}
    }

    # might want to take this out.

    if ($addressed and $message =~ /^seen (\S+)\?*/) {
	my $person = $1;
	if (exists $seen{$person}) {
	    my $when = localtime($seen{$person});
	    if ($msgType =~ /public/) {
		&performSay("$person was last seen saying something on IRC $when");
	    } else {
		&msg($who, "$person was last seen saying something on IRC $when");
	    }
	}
    }
    if ($message =~ /^timer\s+(\d+)$/i) {
	status("$who set a timer for $1 seconds");
	alarm $1;
	return '';
    }

    # here's where the external routines get called.
    # if they return anything but null, that's the "answer".
    my $mr =  &myRoutines;
    if ($mr) {
	return $mr;
    }

    if ($message =~ /^\s*heya?,? /) {
	return unless $addressed;
	# greetings
    }

    if ($message =~ /^\s*h(h|e|a|\s+)+\s*$/) { # laughter
	return "";
    }

    if ($message =~ /(good( fucking)? bo(t|y))|(bot( |\-)?snack)/i) {
	&status("random praise");
	if ($msgType =~ /public/) {
	    if ((time() - $prevTime <= 15) || ($addressed)) {
		if (rand()  < .5)  {
		    &performSay("thanks $who :)");
		} else {
		    &performSay(":)");
		}
	    }
	} else {
	    &msg($who, ":)");
	}
	return "";
    }

    if ($addressed) {
	if ($message =~ /you (rock|rocks|rewl|rule|are so+ co+l)/) {
	    if (rand()  < .5)  {
		&performSay("thanks $who :)");
	    } else {
		&performSay(":)");
	    }
	    return "";
	}
	if ($message =~ /thank(s| you)/i) {
	    if ($msgType =~ /public/) {
		if (rand()  < .5)  {
		    &performSay($welcomes[int(rand(@welcomes))]." ".$who);
		} else {
		    &performSay($who.": ".$welcomes[int(rand(@welcomes))]);
		}
	    } else {
		if (rand()  < .5)  {
		    &msg($who, $welcomes[int(rand(@welcomes))].", ".$who);
		} else {
		    &msg($who, $welcomes[int(rand(@welcomes))]);
		}
	    }
	    return "";
	}
    }

    if ($message =~ /^\s*(h(ello|i( there)?|owdy|ey|ola)|salut|bonjour|niihau|que\s*tal)( $param{nick})?\s*$/i) {
	if (!$addressed and rand() > 0.35) {
	    # 35% chance of replying to a random greeting when not addressed
	    return "";
	}

	my($r) = $hello[int(rand(@hello))];
	if ($msgType =~ /public/) {
	    &performSay($r.", $who");
	} else {
	    &msg($who, $r);
	}
	return "";
    }

    if (($message =~ /^nslookup (\S+)$/i) and $param{allowDNS}) {
	&status("DNS Lookup: $1");
	&DNS($1);
	return '';
    }

    if (($message =~ /^traceroute (\S+)$/i) and $param{allowTraceroute}) {
	&status("traceroute to $1");
	&troute($1);
	return '';
    }

    if (($message =~ /^internic (\S+)$/i) and $param{allowInternic}) {
	&status("internic whois query: $1");
	&domain_summary($1);				
	return '';
    }

    $message =~ s/^\s*hey,?\s+where/where/i;
    $message =~ s/whois/who is/ig;
    $message =~ s/where can i find/where is/i;
    $message =~ s/how about/where is/i;
    $message =~ s/^(gee|boy|golly|gosh),? //i;
    $message =~ s/^(well|and|but|or|yes),? //i;
    $message =~ s/^(does )?(any|ne)(1|one|body) know //i;
    $message =~ s/ da / the /ig;
    $message =~ s/^heya?,?( folks)?,*\.* *//i; # clear initial filled pauses & stuff
    $message =~ s/^[uh]+m*[,\.]* +//i;
    $message =~ s/^o+[hk]+(a+y+)?,*\.* +//i; 
    $message =~ s/^g(eez|osh|olly)+,*\.* +(.+)/$2/i;
    $message =~ s/^w(ow|hee|o+ho+)+,*\.* +(.+)/$2/i;
    $message =~ s/^still,* +//i; 
    $message =~ s/^well,* +//i;
    $message =~ s/^\s*(stupid )?q(uestion)?:\s+//i;

    # may not want to cut off all: all i know is ... 
    # but for now seem mostly content-free

    if ($param{'allowLeave'} =~ /$msgType/) {
	if ($message =~ /(leave|part) ((\#|\&)\S+)/i) {
	    if ($addressed) {
		if (IsFlag("c") ne "c") {
		    &performReply("you don't have the channel flag");
		    return '';
		}
		&channel($2);
		&performSay("goodbye, $who.");
		&status("PART $2 <$who>");
		&part($2);
		return '';
	    }
	}
    }

    if ($msgType !~ /public/) {
	# accept only msgs leaves/joins
	my($ok_to_join);
	if ($message =~ /join ((\&|\#)\S+)/i) {
	    my($which) = $1;
	    foreach $chan (split(/\s+/, $param{'allowed_channels'})) {
		if (lc($which) eq lc($chan)) {
		    $ok_to_join = $which;
		    last;
		}
	    }
	    if ($ok_to_join) {
		if (IsFlag("c") ne "c") {
		    &msg($who, "You don't have the channel flag");
		    return '';
		}
		joinChan($ok_to_join);
		&status("JOIN $ok_to_join <$who>");
		&msg($who, "joining $ok_to_join") 
		    unless ($channel eq &channel());
		sleep(1);
				# my $temp = &channel();
				# &performSay("hello, $who.");
				# &channel($temp);
		return '';
	    } else {
		&msg($who, "I am not allowed to join that channel.");
		return '';
	    }
	}
    }

    if (($message =~ s/^(no,?\s+$param{'nick'},?\s*)//i)
	or ($addressed and $message =~ s/^(no,?\s+)//i)) { 
        # clear initial negative
	# an initial negative may signify a correction
	$correction_plausible = 1;
	&status("correction is plausible, initial negative and nick deleted ($1)") if ($param{VERBOSITY} > 2);
    } else {
	$correction_plausible = 0;
    }

    my($result) = "";

    my $holdMessage = $message;

    $result = &doQuestion($msgType, $message) 
	unless ($who eq 'NOREPLY');
    
    if (($result eq 'NOREPLY') or ($who eq 'NOREPLY')) {
	return '';
    }

    if ($result) {
	if ($param{'addressing'} eq "REQUIRED" and !$addressed) {
	    return 'NOREPLY';
	}
	if (!$finalQMark and !$addressed and 
	    ($input_message_length < $param{'minVolunteerLength'})) {
	    $in = '';
	    return 'NOREPLY';
	}
    }
    
    if ($result !~ /^\s*$/) {
	&status("question: <$who> $message");

	$questionCount++;

	if ($msgType =~ /public/) {
	    if (!$target or !$answer or ($who eq $target)) {
		if ($result) {
		    &performSay($result) unless $blocked;
		} else {
		    &performSay("i didn't have anything matching $tell_obj, $who");
		}
	    } else {
		my $r = "$who wants you to know: $result";
		&msg($target, $r);
		if ($who ne $target) {
		    &msg($who, "told $target about $tell_obj ($r)");
		}
		return 'NOREPLY';
	    }
	} else {		# not public
	    $l = $who;
	    $l =~ s/=//g;
	    if ($answer ne "" ) { # a real answer
		if ($who eq $target) {
		    &msg($who, $result);
		} else {	# to someone else
		    my $r;

		    if ($who eq $target) {
			&msg($target, $result);
		    } else {
			$r = "$who wants you to know: $result";
			&msg($target, $r);
			&msg($who, "told $target about $tell_obj ($r)");
		    }
		}
	    } else {		# didn't know
		&msg($who,$result);
	    }
	}
    } else {			# no reply from doQ
	return "No authorization to teach" unless (IsFlag("t") eq "t");
	if (!$param{'allowUpdate'}) {
	    return '';
	}

	$result = &doStatement($msgType, $holdMessage);

	if (($who eq 'NOREPLY')||($result eq 'NOREPLY')) { return ''; };

	return 'NOREPLY' if grep $_ eq $who, split /\s+/, $param{friendlyBots};

	if ($result !~ /^\s*$/) {
	    if ($msgType !~ /public/) { 
		&msg($who, "gotcha.")
		}
	} else {
	    if ($msgType !~ /public/) { 
		&msg($who, $confused[int(rand(@confused))]);
	    }
	    if (($msgType !~ /public/) || ($addressed)) {
		&status("unparseable: $message");
	    }
	}
    }
}

1;
