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+"'."); } } } }