/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Languages/
com/planet_ink/coffee_mud/Abilities/Misc/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Common/
com/planet_ink/coffee_mud/Common/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/CompTech/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Items/interfaces/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/
com/planet_ink/coffee_mud/core/collections/
com/planet_ink/coffee_mud/core/interfaces/
com/planet_ink/coffee_mud/core/intermud/
com/planet_ink/coffee_mud/core/intermud/i3/
com/planet_ink/coffee_web/server/
com/planet_ink/siplet/applet/
lib/
resources/factions/
resources/fakedb/
resources/progs/autoplayer/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/clan.templates/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
web/pub/textedit/
package com.planet_ink.coffee_mud.core.smtp;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.collections.*;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.*;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;

import java.net.*;
import java.util.*;

import com.planet_ink.coffee_mud.core.exceptions.*;
import java.io.*;

/*
   Copyright 2011-2016 Bo Zimmerman

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

	   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
public class MassMailer implements Runnable
{
	private final LinkedList<MassMailerEntry> entries=new LinkedList<MassMailerEntry>();
	private final CMProps 		  page;
	private final String		  domain;
	private final HashSet<String> oldEmailComplaints;

	private static class MassMailerEntry
	{
		public final JournalEntry mail;
		public final String  journalName;
		public final String  overrideReplyTo;
		public final boolean usePrivateRules;
		public MassMailerEntry(JournalEntry mail, String journalName, String overrideReplyTo, boolean usePrivateRules)
		{
			this.mail=mail;
			this.journalName=journalName;
			this.overrideReplyTo=overrideReplyTo;
			this.usePrivateRules=usePrivateRules;
		}
	}

	public MassMailer(CMProps page, String domain, HashSet<String> oldEmailComplaints)
	{
		this.page=page;
		this.domain=domain;
		this.oldEmailComplaints=oldEmailComplaints;
	}

	public String domainName() { return domain;}

	public int getFailureDays()
	{
		final String s=page.getStr("FAILUREDAYS");
		if(s==null)
			return (365*20);
		final int x=CMath.s_int(s);
		if(x==0)
			return (365*20);
		return x;
	}

	public int getEmailDays()
	{
		final String s=page.getStr("EMAILDAYS");
		if(s==null)
			return (365*20);
		final int x=CMath.s_int(s);
		if(x==0)
			return (365*20);
		return x;
	}

	public boolean deleteEmailIfOld(String journalName, String key, long date, int days)
	{
		final Calendar IQE=Calendar.getInstance();
		IQE.setTimeInMillis(date);
		IQE.add(Calendar.DATE,days);
		if(IQE.getTimeInMillis()<System.currentTimeMillis())
		{
			// email is a goner
			CMLib.database().DBDeleteJournal(journalName, key);
			return true;
		}
		return false;
	}

	public void addMail(JournalEntry mail, String journalName, String overrideReplyTo, boolean usePrivateRules)
	{
		entries.add(new MassMailerEntry(mail,journalName,overrideReplyTo,usePrivateRules));
	}

	protected boolean rightTimeToSendEmail(long email)
	{
		final long curr=System.currentTimeMillis();
		final Calendar IQE=Calendar.getInstance();
		IQE.setTimeInMillis(email);
		final Calendar IQC=Calendar.getInstance();
		IQC.setTimeInMillis(curr);
		if(CMath.absDiff(email,curr)<(30*60*1000))
			return true;
		while(IQE.before(IQC))
		{
			if(CMath.absDiff(IQE.getTimeInMillis(),IQC.getTimeInMillis())<(30*60*1000))
				return true;
			IQE.add(Calendar.DATE,1);
		}
		return false;
	}


	@Override
	public void run()
	{
		for(final MassMailerEntry entry : entries)
		{
			final JournalEntry mail=entry.mail;
			final String journalName=entry.journalName;
			final String overrideReplyTo=entry.overrideReplyTo;
			final boolean usePrivateRules=entry.usePrivateRules;

			final String key=mail.key();
			final String from=mail.from();
			final String to=mail.to();
			final long date=mail.update();
			final String subj=mail.subj();
			final String msg=mail.msg().trim();

			if(to.equalsIgnoreCase("ALL")||(to.toUpperCase().trim().startsWith("MASK=")))
				continue;

			if(!rightTimeToSendEmail(date))
				continue;

			// check for valid recipient
			final String toEmail;
			final String toName;
			if(CMLib.players().playerExists(to))
			{
				final MOB toM=CMLib.players().getLoadPlayer(to);
				// check to see if the sender is ignored
				if((toM.playerStats()!=null)
				&&(toM.playerStats().getIgnored().contains(from)))
				{
					// email is ignored
					CMLib.database().DBDeleteJournal(journalName,key);
					continue;
				}
				if(toM.isAttributeSet(MOB.Attrib.AUTOFORWARD)) // forwarding OFF
					continue;
				if((toM.playerStats()==null)
				||(toM.playerStats().getEmail().length()==0)) // no email addy to forward TO
					continue;
				toName=toM.Name();
				toEmail=toM.playerStats().getEmail();
			}
			else
			if(CMLib.players().accountExists(to))
			{
				final PlayerAccount P=CMLib.players().getLoadAccount(to);
				if((P.getEmail().length()==0)) // no email addy to forward TO
					continue;
				toName=P.getAccountName();
				toEmail=P.getEmail();
			}
			else
			{
				Log.errOut("SMTPServer","Invalid to address '"+to+"' in email: "+msg);
				CMLib.database().DBDeleteJournal(journalName,key);
				continue;
			}

			// check email age
			if((usePrivateRules)
			&&(!CMath.bset(mail.attributes(), JournalEntry.ATTRIBUTE_PROTECTED))
			&&(deleteEmailIfOld(journalName, key, date, getEmailDays())))
				continue;

			SMTPLibrary.SMTPClient SC=null;
			try
			{
				if(CMProps.getVar(CMProps.Str.SMTPSERVERNAME).length()>0)
					SC=CMLib.smtp().getClient(CMProps.getVar(CMProps.Str.SMTPSERVERNAME),SMTPLibrary.DEFAULT_PORT);
				else
					SC=CMLib.smtp().getClient(toEmail);
			}
			catch(final BadEmailAddressException be)
			{
				if((!usePrivateRules)
				&&(!CMath.bset(mail.attributes(), JournalEntry.ATTRIBUTE_PROTECTED)))
				{
					// email is a goner if its a list
					CMLib.database().DBDeleteJournal(journalName,key);
					continue;
				}
				// otherwise it has its n days
				continue;
			}
			catch(final java.io.IOException ioe)
			{
				if(!oldEmailComplaints.contains(toName))
				{
					oldEmailComplaints.add(toName);
					Log.errOut("SMTPServer","Unable to send '"+toEmail+"' for '"+toName+"': "+ioe.getMessage());
				}
				if(!CMath.bset(mail.attributes(), JournalEntry.ATTRIBUTE_PROTECTED))
					deleteEmailIfOld(journalName, key, date,getFailureDays());
				continue;
			}

			final String replyTo=(overrideReplyTo!=null)?(overrideReplyTo):from;
			try
			{
				SC.sendMessage(from+"@"+domainName(),
							   replyTo+"@"+domainName(),
							   toEmail,
							   usePrivateRules?toEmail:replyTo+"@"+domainName(),
							   subj,
							   CMLib.coffeeFilter().simpleOutFilter(msg));
				//this email is HISTORY!
				CMLib.database().DBDeleteJournal(journalName, key);
			}
			catch(final java.io.IOException ioe)
			{
				// it has FAILUREDAYS days to get better.
				if(deleteEmailIfOld(journalName, key, date,getFailureDays()))
					Log.errOut("SMTPServer","Permanently unable to send to '"+toEmail+"' for user '"+toName+"': "+ioe.getMessage()+".");
				else
					Log.errOut("SMTPServer","Failure to send to '"+toEmail+"' for user '"+toName+"'.");
			}
		}
	}

}