package com.planet_ink.coffee_mud.Libraries;
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.Libraries.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.ColorLibrary.Color;
import com.planet_ink.coffee_mud.Libraries.interfaces.ColorLibrary.ColorState;
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.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;
import java.util.*;
/*
Copyright 2004-2019 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 CoffeeFilter extends StdLibrary implements TelnetFilter
{
@Override
public String ID()
{
return "CoffeeFilter";
}
private static final String[][] finalFilter = new String[][]{{"<S-","[S-"},{"<T-","[T-"},{"@x","0x"}};
private Hashtable<String, Pronoun> tagTable = null;
private ColorState normalColor = null;
@Override
public void initializeClass()
{
normalColor = CMLib.color().getNormalColor();
}
@Override
public Map<String, Pronoun> getTagTable()
{
if(tagTable==null)
{
tagTable=new Hashtable<String,Pronoun>();
for(final Pronoun P : Pronoun.values())
tagTable.put(P.suffix, P);
}
return tagTable;
}
@Override
public String simpleOutFilter(final String msg)
{
if(msg==null)
return null;
final StringBuffer buf=new StringBuffer(msg);
for(int i=0;i<buf.length();i++)
{
switch(buf.charAt(i))
{
case '`':
buf.setCharAt(i,'\'');
break;
case '\\':
if(i<buf.length()-1)
{
switch(buf.charAt(i+1))
{
case '%':
buf.deleteCharAt(i);
break;
case 'n':
case 'r':
buf.setCharAt(i,(char)13);
if((i>=buf.length()-2)||((i<buf.length()-2)&&((buf.charAt(i+2))!=10)))
buf.setCharAt(i+1,(char)10);
else
if(i<buf.length()-2)
buf.deleteCharAt(i+1);
break;
case '\'':
case '`':
buf.setCharAt(i,'\'');
buf.deleteCharAt(i+1);
break;
}
}
break;
}
}
if(CMSecurity.isDebugging(CMSecurity.DbgFlag.OUTPUT))
Log.debugOut("CoffeeFilter","OUTPUT: ?: "+buf.toString());
return buf.toString();
}
@Override
public String[] wrapOnlyFilter(final String msg, final int wrap)
{
int loop=0;
final StringBuilder buf=new StringBuilder(msg);
int len=(wrap>0)?wrap:(Integer.MAX_VALUE/3);
int lastSpace=0;
int firstAlpha=-1;
int amperStop = -1;
while(buf.length()>loop)
{
int lastSp=-1;
while((loop<len)&&(buf.length()>loop))
{
switch(buf.charAt(loop))
{
case ' ':
{
if(lastSp>lastSpace)
lastSpace=lastSp;
lastSp=loop;
}
break;
case (char)13:
{
if(((loop<buf.length()-1)&&((buf.charAt(loop+1))!=10))
&&((loop>0)&&((buf.charAt(loop-1))!=10)))
buf.insert(loop+1,(char)10);
if(wrap>0)
len=loop+wrap;
lastSpace=loop;
}
break;
case (char)10:
{
if(wrap>0)
len=loop+wrap;
lastSpace=loop;
}
break;
case '`':
break;
case '!':
if((loop<buf.length()-10)
&&(buf.charAt(loop+1)=='!')
&&((buf.substring(loop+2,loop+7).equalsIgnoreCase("sound"))
||(buf.substring(loop+2,loop+7).equalsIgnoreCase("music"))))
{
final int x=buf.indexOf("(",loop+7);
final int y=buf.indexOf(")",loop+7);
if((x>=0)&&(y>=x))
{
buf.delete(loop,y+1);
loop--;
}
}
break;
case '>':
break;
case '"':
break;
case '&':
if(loop < amperStop)
break;
else
if(loop<buf.length()-3)
{
if(buf.substring(loop,loop+3).equalsIgnoreCase("lt;"))
buf.replace(loop,loop+3,"<");
else
if(buf.substring(loop,loop+3).equalsIgnoreCase("gt;"))
buf.replace(loop,loop+3,">");
}
break;
case '%':
if(loop<buf.length()-2)
{
final int dig1=hexStr.indexOf(buf.charAt(loop+1));
final int dig2=hexStr.indexOf(buf.charAt(loop+2));
if((dig1>=0)&&(dig2>=0))
{
final int val=((dig1*16)+dig2);
buf.setCharAt(loop,(char)val);
buf.deleteCharAt(loop+1);
if((buf.charAt(loop))==13)
buf.setCharAt(loop+1,(char)10);
else
buf.deleteCharAt(loop+1);
loop--; // force a retry of this char
}
}
break;
case '(':
break;
case '\\':
if(loop<buf.length()-1)
{
switch(buf.charAt(loop+1))
{
case '%':
buf.deleteCharAt(loop);
break;
case 'n':
case 'r':
buf.setCharAt(loop,(char)13);
if((loop>=buf.length()-2)||((loop<buf.length()-2)&&((buf.charAt(loop+2))!=10)))
buf.setCharAt(loop+1,(char)10);
else
if(loop<buf.length()-2)
buf.deleteCharAt(loop+1);
break;
case '\'':
case '`':
buf.setCharAt(loop,'\'');
buf.deleteCharAt(loop+1);
break;
}
}
break;
case '<':
break;
case '\033': // skip escapes
if((loop < buf.length()-1) && (buf.charAt(loop+1)=='['))
{
char loopc=buf.charAt(loop);
while( (loop < buf.length()-1) && (loopc!='m') && (loopc!='z') )
{
len++;
loop++;
loopc=buf.charAt(loop);
}
len++; // and one more for the 'm'.
}
break;
case '^':
{
len++;
loop++;
if(loop<buf.length())
{
final char c=buf.charAt(loop);
switch(c)
{
case ColorLibrary.COLORCODE_BACKGROUND:
if(loop+1<buf.length())
{
len++;
loop++;
}
break;
case ColorLibrary.COLORCODE_FANSI256:
case ColorLibrary.COLORCODE_BANSI256:
if(loop+3<buf.length())
{
len+=3;
loop+=3;
}
break;
case '<':
case '&':
{
len++;
loop++;
while(loop<(buf.length()-1))
{
if(((c=='<')&&((buf.charAt(loop)!='^')||(buf.charAt(loop+1)!='>')))
||((c=='&')&&(buf.charAt(loop)!=';')))
{
len++;
loop++;
}
}
len++;
break;
}
default:
len--;
loop--;
break;
}
}
break;
}
default:
if((firstAlpha < 0)&&(Character.isLetter(buf.charAt(loop))))
firstAlpha = loop;
break;
}
loop++;
}
if((len<buf.length())
&&(loop!=lastSp)
&&(lastSp>=0)
&&(loop>=0)
&&(loop<buf.length())
&&(buf.charAt(loop)!=13)
&&(buf.charAt(loop)!=10))
{
amperStop=loop;
if(buf.charAt(lastSp)==' ')
{
if(buf.charAt(lastSp+1)==' ')
{
buf.setCharAt(lastSp,(char)13);
buf.setCharAt(lastSp+1,(char)10);
}
else
{
buf.setCharAt(lastSp,(char)13);
buf.insert(lastSp,(char)10);
}
}
else
{
buf.insert(lastSp,(char)13);
buf.insert(lastSp,(char)10);
}
loop=lastSp+2;
}
if(wrap>0)
len=loop+wrap;
}
if(firstAlpha<0)
firstAlpha=0;
if(firstAlpha<buf.length())
buf.setCharAt(firstAlpha,Character.toUpperCase(buf.charAt(firstAlpha)));
return buf.toString().split("\n\r");
}
@Override
public String secondaryUserInputFilter(final String s)
{
return CMStrings.replaceAlls(s,finalFilter);
}
protected int convertEscape(final Session S, final StringBuffer str, final int index)
{
int enDex = index + 1;
final char c = str.charAt(enDex);
switch (c)
{
case '?':
{
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_ANSI)))
{
ColorState lastColor=S.getLastColor();
final ColorState currColor=S.getCurrentColor();
if((lastColor.foregroundCode()==currColor.foregroundCode())
&&(lastColor.backgroundCode()==currColor.backgroundCode()))
lastColor=normalColor;
final String[] clookup = S.getColorCodes();
String escapeSequence;
if(lastColor.foregroundCode() < 256)
escapeSequence=clookup[lastColor.foregroundCode()];
else
escapeSequence="\033[38;5;"+(lastColor.foregroundCode() & 0xff)+"m";
if(lastColor.backgroundCode()=='.')
escapeSequence=ColorLibrary.Color.NONE.getANSICode()+escapeSequence;
else
{
String bgEscapeSequence;
if(lastColor.backgroundCode() < 256)
{
bgEscapeSequence=clookup[lastColor.backgroundCode()];
if(bgEscapeSequence==null)
bgEscapeSequence=ColorLibrary.Color.BGBLACK.getANSICode();
else
if(ColorLibrary.MAP_ANSICOLOR_TO_ANSIBGCOLOR.containsKey(bgEscapeSequence))
bgEscapeSequence=ColorLibrary.MAP_ANSICOLOR_TO_ANSIBGCOLOR.get(bgEscapeSequence);
}
else
bgEscapeSequence="\033[48;5;"+(lastColor.backgroundCode() & 0xff)+"m";
escapeSequence+=bgEscapeSequence;
}
S.setLastColor(S.getCurrentColor());
S.setCurrentColor(lastColor);
str.insert(index+2, escapeSequence);
str.delete(index, index+2);
return index+escapeSequence.length()-1;
}
str.delete(index, index+2);
return index-1;
}
case ColorLibrary.COLORCODE_FANSI256:
case ColorLibrary.COLORCODE_BANSI256:
{
if(((S!=null)&&(!S.getClientTelnetMode(Session.TELNET_ANSI)))
||(enDex>str.length()-5))
{
str.delete(index, index+5);
return index-1;
}
enDex++;
int finalNum=-1;
int num=str.charAt(enDex)-'0';
if((num>=0)&&(num<=5))
{
int buildNum=(num*36);
num=str.charAt(enDex+1)-'0';
if((num>=0)&&(num<=5))
{
buildNum+=(num*6);
num=str.charAt(enDex+2)-'0';
if((num>=0)&&(num<=5))
{
finalNum=(buildNum + num) + 16;
}
}
}
if((finalNum < 0) && (str.charAt(enDex)==str.charAt(enDex-1)))
{
enDex++;
num=CMath.hexDigit(str.charAt(enDex));
final int num2=CMath.hexDigit(str.charAt(enDex+1));
if((num>=0)&&(num2>=0))
finalNum=(num*16)+num2;
}
if(finalNum >=0)
{
final boolean isFg=(c==ColorLibrary.COLORCODE_FANSI256);
final Color color16;
if((S!=null)&&(S.getClientTelnetMode(Session.TELNET_ANSI16)))
color16 = CMLib.color().getANSI16Equivalent((short)finalNum);
else
color16 = null;
if(color16 == null)
{
String escapeSequence;
if(isFg)
{
escapeSequence="\033[38;5;"+finalNum+"m";
if((S!=null)
&&(S.getCurrentColor().backgroundCode()!='.'))
escapeSequence=ColorLibrary.Color.NONE.getANSICode()+escapeSequence;
}
else
escapeSequence="\033[48;5;"+finalNum+"m";
if(S!=null)
{
if(isFg)
{
S.setLastColor(S.getCurrentColor());
S.setCurrentColor(CMLib.color().valueOf((char)(256 | finalNum), '.'));
}
else
{
S.setCurrentColor(CMLib.color().valueOf(S.getCurrentColor().foregroundCode(), (char)(256 | finalNum)));
}
}
str.insert(index+5, escapeSequence);
str.delete(index, index+5);
return index+escapeSequence.length()-1;
}
else
{
String escapeSequence = color16.getANSICode();
if(isFg)
{
if(S!=null)
{
if((S!=null)
&&(S.getCurrentColor().backgroundCode()!='.'))
escapeSequence=ColorLibrary.Color.NONE.getANSICode()+escapeSequence;
S.setLastColor(S.getCurrentColor());
S.setCurrentColor(CMLib.color().valueOf(color16.getCodeChar(),'.'));
}
}
else
{
escapeSequence=ColorLibrary.MAP_ANSICOLOR_TO_ANSIBGCOLOR.get(escapeSequence);
if(S!=null)
{
final ColorState curColor=S.getCurrentColor();
S.setCurrentColor(CMLib.color().valueOf(curColor.foregroundCode(), color16.getCodeChar()));
}
}
str.insert(index+5, escapeSequence);
str.delete(index, index+5);
return index+escapeSequence.length()-1;
}
}
str.delete(index, index+5);
return index-1;
}
case ColorLibrary.COLORCODE_BACKGROUND:
{
enDex++;
if((S!=null)&&(!S.getClientTelnetMode(Session.TELNET_ANSI)))
{
str.delete(index, index+2);
return index-1;
}
final char bc=str.charAt(enDex);
final String[] clookup = (S==null)?CMLib.color().standardColorLookups():S.getColorCodes();
final String bgEscapeSequence;
final String escapeSequence=clookup[bc];
if(escapeSequence == null)
bgEscapeSequence = null;
else
bgEscapeSequence=ColorLibrary.MAP_ANSICOLOR_TO_ANSIBGCOLOR.get(escapeSequence);
if(bgEscapeSequence != null)
{
str.insert(index+3, bgEscapeSequence);
str.delete(index, index+3);
if(S!=null)
{
final ColorState curColor=S.getCurrentColor();
S.setCurrentColor(CMLib.color().valueOf(curColor.foregroundCode(), bc));
}
return index+bgEscapeSequence.length()-1;
}
else
if(escapeSequence != null)
{
str.insert(index+3, escapeSequence);
str.delete(index, index+3);
return index+escapeSequence.length()-1;
}
else
{
str.delete(index, index+3);
return index-1;
}
}
case '>':
/* why was this here?
if (currentColor > 0)
{
if (clookup()[c] == null)
escapeCodes = clookup()[currentColor];
else
if (clookup()[currentColor] == null)
escapeCodes = clookup[c];
else
escapeCodes = clookup()[c] + clookup()[currentColor];
}
else
*/
str.delete(index, index+1);
return index;
case '<':
{
while(enDex<(str.length()-1))
{
if((str.charAt(enDex)!='^')||(str.charAt(enDex+1)!='>'))
enDex++;
else
if((S==null)
||(!S.getClientTelnetMode(Session.TELNET_MXP))
||(!S.isAllowedMxp(str.substring(index,enDex+2))))
{
str.delete(index,enDex+2);
enDex=index-1;
return enDex;
}
else
{
str.delete(enDex, enDex+1);
str.delete(index, index+1);
return enDex-1;
}
}
str.delete(index, index+1);
return index;
}
case '&':
{
while(enDex<(str.length()-1))
{
if(str.charAt(enDex)!=';')
enDex++;
else
if((S==null)
||(!S.getClientTelnetMode(Session.TELNET_MXP))
||(!S.isAllowedMxp(str.substring(index,enDex+1))))
{
str.delete(index,enDex+1);
enDex=index-1;
return enDex;
}
else
{
str.delete(index, index+1);
return enDex;
}
}
str.delete(index, index+1);
return index;
}
case '"':
str.delete(index, index+1);
return index;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if((S==null)||(S.getClientTelnetMode(Session.TELNET_MSP)))
{
final int escOrd=CMProps.Str.ESC0.ordinal() + (c - ('0'));
final CMProps.Str escEnum=CMProps.Str.values()[escOrd];
final String escapeSequence=CMProps.getVar(escEnum);
str.insert(index+2, escapeSequence);
str.delete(index, index+2);
return index+escapeSequence.length()-1;
}
else
{
str.delete(index, index+2);
return index-1;
}
case '.':
if((S==null)||(S.getClientTelnetMode(Session.TELNET_ANSI)))
{
final String[] clookup = (S==null)?CMLib.color().standardColorLookups():S.getColorCodes();
String escapeSequence=clookup[c];
if(escapeSequence==null)
escapeSequence="";
str.insert(index+2, escapeSequence);
str.delete(index, index+2);
return index+escapeSequence.length()-1;
}
else
{
str.delete(index, index+2);
return index-1;
}
case '^':
str.delete(index, index+1);
return index;
default:
if((c>=0)
&&(c<256)
&&((S==null)||(S.getClientTelnetMode(Session.TELNET_ANSI))))
{
final String[] clookup = (S==null)?CMLib.color().standardColorLookups():S.getColorCodes();
String escapeSequence=clookup[c];
if(escapeSequence==null)
return index;
if(escapeSequence.length()>0)
{
if((S!=null)
&&(escapeSequence.charAt(0)=='\033'))
{
final ColorState state=S.getCurrentColor();
if(state.backgroundCode()!='.')
escapeSequence=ColorLibrary.Color.NONE.getANSICode()+escapeSequence;
S.setLastColor(state);
S.setCurrentColor(CMLib.color().valueOf(c,'.'));
}
else
if(escapeSequence.charAt(0)=='^')
{
str.insert(index+2, escapeSequence);
str.delete(index, index+2);
return index-1;
}
}
str.insert(index+2, escapeSequence);
str.delete(index, index+2);
return index+escapeSequence.length()-1;
}
else
{
str.delete(index, index+2);
return index-1;
}
}
}
// no word-wrapping, text filtering or ('\','n') -> '\n' translations
@Override
public String colorOnlyFilter(final String msg, final Session S)
{
if(msg==null)
return null;
if(msg.length()==0)
return msg;
final StringBuffer buf=new StringBuffer(msg);
final Session CS=S;
//if(CS==null) CS=(Session)CMClass.getCommon("DefaultSession");
int loop=0;
while(buf.length()>loop)
{
switch(buf.charAt(loop))
{
case '>':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,">".toCharArray());
loop+=3;
}
break;
case '"':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,""".toCharArray());
loop+=5;
}
break;
case '&':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
if((!buf.substring(loop+1,loop+4).equalsIgnoreCase("lt;"))
&&(buf.substring(loop+1,loop+4).equalsIgnoreCase("gt;")))
{
buf.delete(loop,loop+1);
buf.insert(loop,"&".toCharArray());
loop+=4;
}
}
else
if(loop<=buf.length()-4)
{
if(buf.substring(loop+1,loop+4).equalsIgnoreCase("lt;"))
buf.replace(loop,loop+4,"<");
else
if(buf.substring(loop+1,loop+4).equalsIgnoreCase("gt;"))
buf.replace(loop,loop+4,">");
else
if((loop<=buf.length()-6) && (buf.substring(loop+1,loop+6).equalsIgnoreCase("quot;")))
buf.replace(loop,loop+6,"\"");
}
break;
case '<':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,"<".toCharArray());
loop+=3;
}
break;
case '^':
if(loop<buf.length()-1)
{
loop=convertEscape(CS, buf, loop);
}
break;
default:
break;
}
loop++;
}
if ((S!=null)
&&(normalColor!=null)
&&(!normalColor.equals(S.getCurrentColor()))
&&(S.getClientTelnetMode(Session.TELNET_ANSI)))
{
buf.append(S.getColorCodes()['N']);
S.setLastColor(S.getCurrentColor());
S.setCurrentColor(normalColor);
}
if(CMSecurity.isDebugging(CMSecurity.DbgFlag.OUTPUT))
Log.debugOut("CoffeeFilter","OUTPUT: "+(((S!=null)&&(S.mob()!=null))?S.mob().Name():"")+": "+buf.toString());
return buf.toString();
}
// no word-wrapping, text filtering or ('\','n') -> '\n' translations
@Override
public String mxpSafetyFilter(final String msg, final Session S)
{
if(msg==null)
return null;
if(msg.length()==0)
return msg;
final StringBuffer buf=new StringBuffer(msg);
int loop=0;
while(buf.length()>loop)
{
switch(buf.charAt(loop))
{
case '>':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,">".toCharArray());
loop+=3;
}
break;
case '"':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,""".toCharArray());
loop+=5;
}
break;
case '&':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
if((!buf.substring(loop,loop+3).equalsIgnoreCase("lt;"))
&&(buf.substring(loop,loop+3).equalsIgnoreCase("gt;")))
{
buf.delete(loop,loop+1);
buf.insert(loop,"&".toCharArray());
loop+=4;
}
}
else
if(loop<buf.length()-3)
{
if(buf.substring(loop,loop+3).equalsIgnoreCase("lt;"))
buf.replace(loop,loop+3,"<");
else
if(buf.substring(loop,loop+3).equalsIgnoreCase("gt;"))
buf.replace(loop,loop+3,">");
}
break;
case '<':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,"<".toCharArray());
loop+=3;
}
break;
default:
break;
}
loop++;
}
if(CMSecurity.isDebugging(CMSecurity.DbgFlag.OUTPUT))
Log.debugOut("CoffeeFilter","OUTPUT: "+(((S!=null)&&(S.mob()!=null))?S.mob().Name():"")+": "+buf.toString());
return buf.toString();
}
@Override
public String getLastWord(final StringBuffer buf, final int lastSp, final int lastSpace)
{
String lastWord="";
if(lastSp>lastSpace)
{
lastWord=CMStrings.removeColors(buf.substring(lastSpace,lastSp)).trim().toUpperCase();
while((lastWord.length()>0)&&(!Character.isLetterOrDigit(lastWord.charAt(0))))
lastWord=lastWord.substring(1);
while((lastWord.length()>0)&&(!Character.isLetterOrDigit(lastWord.charAt(lastWord.length()-1))))
lastWord=lastWord.substring(0,lastWord.length()-1);
for(int i=lastWord.length()-1;i>=0;i--)
{
if(!Character.isLetterOrDigit(lastWord.charAt(i)))
{
lastWord=lastWord.substring(i+1);
break;
}
}
}
else
{
for(int i=(lastSpace-1);((i>=0)&&(!Character.isLetterOrDigit(buf.charAt(i))));i--)
lastWord=buf.charAt(i)+lastWord;
lastWord=CMStrings.removeColors(lastWord).trim().toUpperCase();
}
return lastWord;
}
@Override
public String fullOutFilter(final Session S,
final MOB mob,
final Physical source,
final Environmental target,
final Environmental tool,
final String msg,
final boolean wrapOnly)
{
if(msg==null)
return null;
if(msg.length()==0)
return msg;
boolean doSagain=false;
boolean firstSdone=false;
boolean capitalize = true;
final StringBuffer buf=new StringBuffer(msg);
final int wrap=(S!=null)?S.getWrap():78;
int len=(wrap>0)?wrap:(Integer.MAX_VALUE/3);
int loop=0;
int lastSpace=0;
int firstAlpha=-1;
int amperStop = -1;
int loopDebugCtr=0;
int lastLoop=-1;
while(buf.length()>loop)
{
if(loop==lastLoop)
{
//BZ: delete when this is fixed.
//BZ: 11/2015 - this might be fixed now!
if(++loopDebugCtr>5)
{
Log.debugOut("CoffeeFilter","LOOP: "+loop+"/"+wrap+"/!"+(buf.charAt(loop)=='\033')+"!/"+lastSpace+"/"+firstAlpha+"/"+amperStop+"/"+doSagain+"/"+firstSdone+"/"+buf.length()+"/"+loopDebugCtr);
Log.debugOut("CoffeeFilter",buf.toString());
break;
}
}
else
{
lastLoop=loop;
loopDebugCtr=0;
}
int lastSp=-1;
while((loop<len)&&(buf.length()>loop))
{
switch(buf.charAt(loop))
{
case ' ':
{
if(lastSp>lastSpace)
lastSpace=lastSp;
lastSp=loop;
}
break;
case (char)13:
{
if(((loop<buf.length()-1)&&((buf.charAt(loop+1))!=10))
&&((loop>0)&&((buf.charAt(loop-1))!=10)))
buf.insert(loop+1,(char)10);
if(wrap>0)
len=loop+wrap;
lastSpace=loop;
}
break;
case (char)10:
{
if(wrap>0)
len=loop+wrap;
lastSpace=loop;
}
break;
case '`':
buf.setCharAt(loop,'\'');
break;
case '!':
if((loop<buf.length()-10)
&&(buf.charAt(loop+1)=='!')
&&((buf.substring(loop+2,loop+7).equalsIgnoreCase("sound"))
||(buf.substring(loop+2,loop+7).equalsIgnoreCase("music"))))
{
final int x=buf.indexOf("(",loop+7);
final int y=buf.indexOf(")",loop+7);
if((x>=0)&&(y>=x))
{
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MSP)||S.getClientTelnetMode(Session.TELNET_MXP))
&&((source==null)
||(source==mob)
||(CMLib.flags().canBeHeardSpeakingBy(source,mob))))
{
if(S.getClientTelnetMode(Session.TELNET_MXP))
{
buf.setCharAt(loop+1, '<');
buf.setCharAt(x, ' ');
buf.setCharAt(y, '>');
buf.deleteCharAt(loop);
if(wrap>0)
len=len+(y-loop);
loop=y-1;
}
else
if(S.getClientTelnetMode(Session.TELNET_MSP))
{
if(wrap>0)
len=len+(y-loop)+1;
loop=y;
}
}
else
{
buf.delete(loop,y+1);
loop--;
}
}
}
break;
case '>':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,">".toCharArray());
loop+=3;
}
break;
case '"':
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,""".toCharArray());
loop+=5;
}
break;
case '&':
if(loop < amperStop)
break;
else
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
if((!buf.substring(loop,loop+3).equalsIgnoreCase("lt;"))
&&(!buf.substring(loop,loop+3).equalsIgnoreCase("gt;")))
{
buf.delete(loop,loop+1);
buf.insert(loop,"&".toCharArray());
loop+=4;
}
else
loop+=3;
}
else
if(loop<buf.length()-3)
{
if(buf.substring(loop,loop+3).equalsIgnoreCase("lt;"))
buf.replace(loop,loop+3,"<");
else
if(buf.substring(loop,loop+3).equalsIgnoreCase("gt;"))
buf.replace(loop,loop+3,">");
}
break;
case '%':
if(loop<buf.length()-2)
{
final int dig1=hexStr.indexOf(buf.charAt(loop+1));
final int dig2=hexStr.indexOf(buf.charAt(loop+2));
if((dig1>=0)&&(dig2>=0))
{
final int val=((dig1*16)+dig2);
buf.setCharAt(loop,(char)val);
buf.deleteCharAt(loop+1);
if((buf.charAt(loop))==13)
buf.setCharAt(loop+1,(char)10);
else
buf.deleteCharAt(loop+1);
if(buf.charAt(loop)=='\033')
loop--; // force a retry of this char
}
}
break;
case '(':
if((!wrapOnly)&&(loop<(buf.length()-1)))
{
final char c2=Character.toUpperCase(buf.charAt(loop+1));
if(((loop<buf.length()-2)&&(buf.charAt(loop+2)==')')&&(c2=='S'))
||((loop<buf.length()-3)&&(buf.charAt(loop+3)==')')&&(Character.toUpperCase(buf.charAt(loop+2))=='S')&&((c2=='Y')||(c2=='E'))))
{
final String lastWord=getLastWord(buf,lastSp,lastSpace);
final int lastParen=(c2=='S')?loop+2:loop+3;
if(lastWord.equals("A")
||lastWord.equals("YOU")
||lastWord.equals("1")
||doSagain)
{
if(c2=='Y')
buf.replace(loop,lastParen+1,CMStrings.sameCase("y",buf.charAt(loop+1)));
else
buf.delete(loop,lastParen+1);
doSagain=true;
loop--;
}
else
{
if(c2=='Y')
buf.replace(loop,lastParen+1,CMStrings.sameCase("ies",buf.charAt(loop+1)));
else
{
buf.deleteCharAt(lastParen);
buf.deleteCharAt(loop);
}
}
firstSdone=true;
}
}
break;
case '\\':
if(loop<buf.length()-1)
{
switch(buf.charAt(loop+1))
{
case '%':
buf.deleteCharAt(loop);
break;
case 'n':
case 'r':
{
buf.setCharAt(loop,(char)13);
if((loop>=buf.length()-2)||((loop<buf.length()-2)&&((buf.charAt(loop+2))!=10)))
buf.setCharAt(loop+1,(char)10);
else
if(loop<buf.length()-2)
buf.deleteCharAt(loop+1);
}
break;
case '\'':
case '`':
{
buf.setCharAt(loop,'\'');
buf.deleteCharAt(loop+1);
}
break;
}
}
break;
case '<':
if((!wrapOnly)&&((loop+1)<buf.length()))
{
// supported here <?-HIS-HER>, <?-HIM-HER>, <?-NAME>,
// <?-NAMESELF>, <?-HE-SHE>, <?-IS-ARE>, <?-HAS-HAVE>
//int endDex=loop;
StringBuffer cmd=new StringBuffer("");
int ldex=loop+1;
char lc=' ';
for(;(ldex<buf.length())&&(cmd!=null);ldex++)
{
lc=buf.charAt(ldex);
if(lc=='>')
break;
switch(lc)
{
case '<':
case '\n':
case '\r':
cmd=null;
break;
default:
cmd.append(Character.toUpperCase(lc));
break;
}
}
if((cmd!=null)&&(ldex<buf.length())&&(buf.charAt(ldex)=='>')&&(cmd.length()>1)&&(cmd.length()<14))
{
Environmental regarding=null;
switch(cmd.charAt(0))
{
case 'S':
regarding = source;
break;
case 'T':
regarding = target;
break;
case 'O':
regarding = tool;
break;
}
String replacement=null;
final Pronoun P=getTagTable().get(cmd.substring(1));
if(P==null)
{
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP))
&&(S.isAllowedMxp(buf.substring(loop,loop+1))))
{
buf.delete(loop,loop+1);
buf.insert(loop,"<".toCharArray());
}
}
else
switch(P)
{
case NAME:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
{
replacement="you";
if(!firstSdone)
doSagain=true;
}
else
if((mob!=null)
&&((!CMLib.flags().canSee(mob))||(!CMLib.flags().canBeSeenBy(regarding,mob)))
&&(regarding.Name().trim().length()>0))
replacement=((regarding instanceof MOB)?"someone":"something");
else
if(regarding instanceof PhysicalAgent)
replacement=((PhysicalAgent)regarding).name(mob);
else
replacement=regarding.name();
}
break;
case ACCOUNTNAME:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
{
replacement="you";
if(!firstSdone)
doSagain=true;
}
else
if((mob!=null)
&&((!CMLib.flags().canSee(mob))||(!CMLib.flags().canBeSeenBy(regarding,mob)))
&&(regarding.Name().trim().length()>0))
replacement=((regarding instanceof MOB)?"someone":"something");
else
if(regarding instanceof MOB)
{
if((((MOB)regarding).playerStats()!=null)
&&(((MOB)regarding).playerStats().getAccount()!=null))
replacement=((MOB)regarding).playerStats().getAccount().getAccountName();
else
replacement=((MOB)regarding).name(mob);
}
else
if(regarding instanceof PhysicalAgent)
replacement=((PhysicalAgent)regarding).name(mob);
else
replacement=regarding.name();
}
break;
case NAMENOART:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
{
replacement="you";
if(!firstSdone)
doSagain=true;
}
else
if((mob!=null)
&&((!CMLib.flags().canSee(mob))||(!CMLib.flags().canBeSeenBy(regarding,mob)))
&&(regarding.Name().trim().length()>0))
replacement=((regarding instanceof MOB)?"someone":"something");
else
if(regarding instanceof PhysicalAgent)
replacement=CMLib.english().removeArticleLead(((PhysicalAgent)regarding).name(mob));
else
replacement=CMLib.english().removeArticleLead(regarding.name());
}
break;
case NAMESELF:
{
if(regarding==null)
replacement="";
else
if(((source==target)||(target==null))&&(mob==regarding))
replacement="yourself";
else
if(mob==regarding)
{
replacement="you";
if(!firstSdone)
doSagain=true;
}
else
if((mob!=null)
&&((!CMLib.flags().canSee(mob))||(!CMLib.flags().canBeSeenBy(regarding,mob)))
&&(regarding.Name().trim().length()>0))
replacement=((regarding instanceof MOB)?"someone":"something");
else
if(source==target)
replacement=((regarding instanceof MOB)?(((MOB)regarding).charStats().himher()+"self"):"itself");
else
if(regarding instanceof PhysicalAgent)
replacement=((PhysicalAgent)regarding).name(mob);
else
replacement=regarding.name();
}
break;
case YOUPOSS:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
replacement="your";
else
if((mob!=null)
&&((!CMLib.flags().canSee(mob))||(!CMLib.flags().canBeSeenBy(regarding,mob)))
&&(regarding.Name().trim().length()>0))
replacement=((regarding instanceof MOB)?"someone's":"something's");
else
if(regarding instanceof PhysicalAgent)
replacement=((PhysicalAgent)regarding).name(mob)+"'s";
else
replacement=regarding.name()+"'s";
}
break;
case WITHNAME:
{
if(regarding==null)
replacement="";
else
replacement=L(" with @x1",((PhysicalAgent)regarding).name(mob));
}
break;
case HISHER:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
replacement="your";
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().hisher();
else
replacement="its";
}
break;
case HIMHER:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
{
replacement="you";
if(!firstSdone)
doSagain=true;
}
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().himher();
else
replacement="it";
}
break;
case HIMHERSELF:
{
if(regarding==null)
replacement="themself";
else
if(mob==regarding)
replacement="yourself";
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().himher()+"self";
else
replacement="itself";
}
break;
case HISHERSELF:
{
if(regarding==null)
replacement="themself";
else
if(mob==regarding)
replacement="yourself";
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().hisher()+"self";
else
replacement="itself";
}
break;
case HESHE:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
{
replacement="you";
if(!firstSdone)
doSagain=true;
}
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().heshe();
else
replacement="its";
}
break;
case SIRMADAM:
{
if(regarding==null)
replacement="";
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().sirmadam();
else
replacement="sir";
}
break;
case MRMS:
{
if(regarding==null)
replacement="";
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().MrMs();
else
replacement="Mr.";
}
break;
case MISTERMADAM:
{
if(regarding==null)
replacement="";
else
if(regarding instanceof MOB)
replacement=((MOB)regarding).charStats().MisterMadam();
else
replacement="Mister";
}
break;
case ISARE:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
replacement="are";
else
replacement="is";
}
break;
case ISARE2:
{
final String lastWord=getLastWord(buf,lastSp,lastSpace);
if((lastWord.equals("A")||lastWord.equals("YOU")||lastWord.equals("1")||doSagain))
replacement="is";
else
replacement="are";
}
break;
case HASHAVE:
{
if(regarding==null)
replacement="";
else
if(mob==regarding)
replacement="have";
else
if(regarding instanceof MOB)
replacement="has";
}
break;
}
if(replacement!=null)
{
final String newReplacement=CMLib.lang().filterTranslation(replacement);
if(newReplacement!=null)
replacement=newReplacement;
if(capitalize)
replacement=CMStrings.capitalizeFirstLetter(replacement);
buf.delete(loop,ldex+1);
if(replacement != null)
buf.insert(loop,replacement.toCharArray());
loop--;
}
capitalize=false;
}
else
if((S!=null)
&&(S.getClientTelnetMode(Session.TELNET_MXP)))
{
buf.delete(loop,loop+1);
buf.insert(loop,"<".toCharArray());
loop+=3;
}
}
break;
case '\033': // skip escapes
{
if((S!=null)&&(!S.getClientTelnetMode(Session.TELNET_ANSI)))
{
final int oldLoop=loop;
if((loop < buf.length()-1) && (buf.charAt(loop+1)=='['))
{
loop++; // added 2013, see comment below
char loopc=buf.charAt(loop);
while( (loop < buf.length()-1) && (loopc!='m') && (loopc!='z') )
{
loop++;
loopc=buf.charAt(loop);
}
buf.delete(oldLoop,loop+1);
loop=oldLoop-1;
}
}
else
{
if((loop < buf.length()-1) && (buf.charAt(loop+1)=='['))
{
loop++; // added 2013, see comment below
char loopc=buf.charAt(loop);
while( (loop < buf.length()-1) && (loopc!='m') && (loopc!='z') )
{
len++;
loop++;
loopc=buf.charAt(loop);
}
//if(buf.charAt(loop)=='\033')
// loop--; // force a retry of this char. 2013: why do this? only possible if you didn't move, and this promises less moving!
}
}
break;
}
case '^':
{
if(loop<buf.length()-1)
{
final int oldLoop=loop;
loop=convertEscape(S, buf, loop);
if(wrap>0)
{
len=(loop-oldLoop)+len+1;
}
lastSp=loop+1;
}
break;
}
case '.':
capitalize=(loop < buf.length()-3)
&& (buf.charAt(loop+1)==' ')
&& ((buf.charAt(loop+2)==' ')||(buf.charAt(loop+2)=='<'));
break;
default:
{
if((firstAlpha < 0)&&(Character.isLetter(buf.charAt(loop))))
firstAlpha = loop;
capitalize=false;
break;
}
}
loop++;
}
if((len<buf.length())
&&(loop!=lastSp)
&&(lastSp>=0)
&&(loop>=0)
&&(loop<buf.length())
&&(buf.charAt(loop)!=13)
&&(buf.charAt(loop)!=10))
{
amperStop=loop;
if(buf.charAt(lastSp)==' ')
{
if(buf.charAt(lastSp+1)==' ')
{
buf.setCharAt(lastSp,(char)13);
buf.setCharAt(lastSp+1,(char)10);
}
else
{
buf.setCharAt(lastSp,(char)13);
buf.insert(lastSp,(char)10);
}
}
else
{
buf.insert(lastSp,(char)13);
buf.insert(lastSp,(char)10);
}
loop=lastSp+2;
}
if(wrap>0)
len=loop+wrap;
}
if(firstAlpha<0)
firstAlpha=0;
if(firstAlpha<buf.length())
buf.setCharAt(firstAlpha,Character.toUpperCase(buf.charAt(firstAlpha)));
if((S!=null)
&&(!normalColor.equals(S.getCurrentColor()))
&&(S.getClientTelnetMode(Session.TELNET_ANSI)))
{
buf.append(S.getColorCodes()['N']);
S.setLastColor(S.getCurrentColor());
S.setCurrentColor(normalColor);
}
/* fabulous debug code
for(int i=0;i<buf.length();i+=25)
{
for(int x=0;x<25;x++)
{
if((i+x)<buf.length())
{
char c=buf.charAt(i+x);
if((c!='\r')&&(c!='\n'))
System.out.print(c);
else
System.out.print("?");
}
}
System.out.print(" ");
for(int x=0;x<25;x++)
{
if((i+x)<buf.length())
{
int c=(int)buf.charAt(i+x);
int a=c/16;
int b=c%16;
System.out.print(("0123456789ABCDEF").charAt(a));
System.out.print(("0123456789ABCDEF").charAt(b));
}
}
System.out.print(" \n");
}
//*/
if(CMSecurity.isDebugging(CMSecurity.DbgFlag.OUTPUT))
Log.debugOut("CoffeeFilter","OUTPUT: "+(((S!=null)&&(S.mob()!=null))?S.mob().Name():"")+": "+buf.toString());
return buf.toString();
}
@Override
public String simpleInFilter(final StringBuilder input)
{
return simpleInFilter(input, false);
}
@Override
public String simpleInFilter(StringBuilder input, final boolean permitMXPTags)
{
if(input==null)
return null;
int x=0;
while(x<input.length())
{
final char c=input.charAt(x);
switch(c)
{
case '\'':
input.setCharAt(x,'`');
break;
case '%':
if(x<input.length()-2)
{
final int dig1=hexStr.indexOf(input.charAt(x+1));
final int dig2=hexStr.indexOf(input.charAt(x+2));
if((dig1>=0)&&(dig2>=0))
{
final int val=((dig1*16)+dig2);
if((val==0xff)||(val==0)||(val==0x1b))
{
input.insert(x,'\\');
x++;
}
}
}
break;
case '^':
if((x<(input.length()-1))&&(!permitMXPTags))
{
switch(input.charAt(x+1))
{
case '<':
case '>':
case '&':
input.deleteCharAt(x);
break;
}
}
break;
case 8:
{
final String newStr=input.toString();
if(x==0)
input=new StringBuilder(newStr.substring(x+1));
else
{
input=new StringBuilder(newStr.substring(0,x-1)+newStr.substring(x+1));
x--;
}
x--;
break;
}
}
x++;
}
return input.toString();
}
@Override
public String fullInFilter(final String input)
{
if(input==null)
return null;
final StringBuilder buf=new StringBuilder(input);
for(int i=0;i<buf.length();i++)
{
switch(buf.charAt(i))
{
case (char)10:
buf.setCharAt(i,'r');
buf.insert(i,'\\');
break;
case (char)13:
buf.setCharAt(i,'n');
buf.insert(i,'\\');
break;
}
}
return simpleInFilter(buf,false).toString();
}
@Override
public String safetyFilter(final String s)
{
final StringBuffer s1=new StringBuffer(s);
int x=-1;
while((++x)<s1.length())
{
if(s1.charAt(x)=='\r')
{
s1.deleteCharAt(x);
x--;
}
else
if(s1.charAt(x)=='\n')
{
s1.setCharAt(x,'\\');
s1.insert(x+1,'n');
x++;
}
else
if(s1.charAt(x)=='\'')
s1.setCharAt(x,'`');
}
return s1.toString();
}
}