package com.planet_ink.coffee_mud.core.intermud.imc2; import com.planet_ink.coffee_mud.Commands.interfaces.Command; import com.planet_ink.coffee_mud.Common.interfaces.*; import com.planet_ink.coffee_mud.Locales.interfaces.Room; import com.planet_ink.coffee_mud.MOBS.interfaces.MOB; import com.planet_ink.coffee_mud.core.*; import java.io.*; import java.net.Socket; import java.util.*; /** * IMC2 version 0.10 - an inter-mud communications protocol * Copyright (C) 1996 & 1997 Oliver Jowett <oliver@randomly.org> * * IMC2 Gold versions 1.00 though 2.00 are developed by MudWorld. * Copyright (C) 1999 - 2002 Haslage Net Electronics (Anthony R. Haslage) * * IMC2 MUD-Net version 3.10 is developed by Alsherok and Crimson Oracles * Copyright (C) 2002 Roger Libiez ( Samson ) * Additional code Copyright (C) 2002 Orion Elder * Registered with the United States Copyright Office * TX 5-555-584 * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING); if not, write to the * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Ported to Java by Istvan David (u_davis@users.sourceforge.net) * */ @SuppressWarnings("unchecked") public final class IMC2Driver extends Thread { Socket sa; /* a player on IMC */ final class imc_char_data { String name = ""; /* name of character */ int invis; /* invisible to IMC? */ int level; /* trust level */ int wizi; /* wizi level */ } static final int PERM_NONE = 0; static final int PERM_PLAYER = 1; static final int PERM_IMMORTAL = 2; static final int PERM_ADMIN = 3; boolean shutdown=false; boolean isShutdown=false; Date imc_boot = new Date(); long imc_now,imc_sequencenumber,imc_prev_sequencenumber; public hubinfo this_imcmud = new hubinfo(); public siteinfo imc_siteinfo = new siteinfo(); imc_statistics imc_stats = new imc_statistics(); public int imc_active; /* Connection state */ long HeartBeat = 0; // elapsed heartbeats call_out c_thread=null; call_in c_thread2=null; Hashtable muds = new Hashtable(); Hashtable channels = new Hashtable(); public Hashtable chanhist = new Hashtable(); Hashtable replies = new Hashtable(); public Hashtable chan_conf = new Hashtable(); public Hashtable chan_mask = new Hashtable(); BufferedReader in; DataOutputStream out; public String imc_name = ""; public short imc_log_on; /* refresh timeout */ final static int IMC_TIMEOUT = 650; public final static int CHAN_OPEN = 1; public final static int CHAN_CLOSED = 2; public final static int CHAN_PRIVATE = 3; public final static int CHAN_COPEN = 4; public final static int CHAN_CPRIVATE = 5; /* max length of any mud name */ final static int IMC_MNAME_LENGTH = 20; /* max length of any player name */ final static int IMC_PNAME_LENGTH = 40; /* max length of any player@mud name */ final static int IMC_NAME_LENGTH = (IMC_MNAME_LENGTH + IMC_PNAME_LENGTH + 1); /* activation states */ public final static int IA_NONE = 0; public final static int IA_CONFIG1 = 1; public final static int IA_CONFIG2 = 2; public final static int IA_UP = 3; /* connection states */ final static int IMC_CLOSED = 0; /* No active connection */ final static int IMC_CONNECTING = 1; /* Contacting hub */ final static int IMC_WAIT1 = 2; /* Waiting for hub verification */ final static int IMC_CONNECTED = 3; /* Fully connected */ final static int IMC_VERSION = 2; final static String IMC_VERSIONID = "IMC2 4.00 for CoffeeMud"; final void tracef(int level, String s) { if((level<1)||(CMSecurity.isDebugging("IMC2"))) Log.debugOut("IMC2",level+"/"+s); } final void send_to_player(String name, String text) { if(name.equalsIgnoreCase("all")) { for(int s=0;s<CMLib.sessions().size();s++) CMLib.sessions().elementAt(s).println(text); } else { MOB M=CMLib.players().getPlayer(name); if(M!=null) M.tell(text); } } public void ev_request_keepalive(Object param) { imc_request_keepalive(); //imc_register_call_out(25, "ev_keepalive", null); } final public String[][] buildChannelMap(String s) { Vector V=CMParms.parseCommas(s,true); Vector finalV=new Vector(); for(int v=0;v<V.size();v++) { String s2=(String)V.elementAt(v); Vector V2=CMParms.parse(s2); String[] bit=new String[3]; bit[0]=""; bit[1]=""; bit[2]=""; if(V2.size()<1) continue; bit[0]=(String)V2.elementAt(0); if(V2.size()==1) bit[2]=(String)V2.elementAt(0); else { bit[2]=(String)V2.lastElement(); if(V2.size()>2) bit[1]=CMParms.combine(V2,1,V.size()-1); } finalV.addElement(bit); } String[][] finalS=new String[finalV.size()][3]; for(int i=0;i<finalV.size();i++) finalS[i]=(String[])finalV.elementAt(i); return finalS; } final public String[][] buildChannelMap() { String[][] map=new String[chan_conf.size()][3]; int dex=0; for(Enumeration e=chan_conf.keys();e.hasMoreElements();) { map[dex][0]=(String)e.nextElement(); map[dex][1]=(String)chan_mask.get(map[dex][0]); map[dex][2]=(String)chan_conf.get(map[dex][0]); } return map; } final public static String[] explodeNicely(String s) { return explodeNicely(s, " "); } public void shutdown() { shutdown=true; try{ if(c_thread!=null) c_thread.shutdown(); }catch(Exception e){} try{ if(c_thread2!=null) c_thread2.shutdown(); }catch(Exception e){} CMLib.killThread(this,500,1); int i=0; while (((++i)<60)&&((!c_thread.isShutdown)||(!c_thread2.isShutdown)||(!isShutdown))) try { sleep(1000); } catch (Exception ex) {} } final public static String[] explodeNicely(String s, String separator) { StringTokenizer st = new StringTokenizer(s, separator); int n = st.countTokens(); if(n==0) { String array[] = new String[1]; array[0] = s; return array; } String array[] = new String[n]; int i = 0; while(st.hasMoreTokens()) { array[i] = st.nextToken(); i++; } return array; } /* put a line onto descriptors output buffer */ final void do_imcsend( String line ) { if(line.endsWith("\n\r")) this_imcmud.outbuf = line; else this_imcmud.outbuf = line+"\n\r"; } /* connect to hub */ final boolean imc_connect_to() { String buf; if (imc_active == IA_NONE) { tracef(0, "IMC is not active"); return false; } tracef(8, "Connecting to " + this_imcmud.hubname); try { sa = new Socket(this_imcmud.host, this_imcmud.port); } catch (Exception e) { tracef(0, "Error connecting to " + this_imcmud.host + ":" + this_imcmud.port); return false; } if (sa == null) { tracef(0, "Error connecting to " + this_imcmud.host + ":" + this_imcmud.port); return false; } try { sa.setSoTimeout(60000); in = new BufferedReader(new InputStreamReader(sa.getInputStream())); out = new DataOutputStream(sa.getOutputStream()); } catch(Exception e) { } this_imcmud.state = IMC_CONNECTING; this_imcmud.insize = 1024; this_imcmud.outsize = 1024; buf = "PW " + imc_name.trim() + " " + this_imcmud.clientpw + " version=" + IMC_VERSION+" autosetup "+this_imcmud.serverpw; do_imcsend(buf); imc_write_to_socket(out); imc_read_from_socket(in); return true; } /* start up IMC */ final boolean imc_startup_network() { if (imc_active != IA_CONFIG2) { tracef(0, "imc_startup_network: called with imc_active == "+ imc_active); return false; } tracef(8, "IMC2 Network Initializing"); imc_active = IA_UP; imc_stats.start = imc_now; imc_stats.rx_pkts = 0; imc_stats.tx_pkts = 0; imc_stats.rx_bytes = 0; imc_stats.tx_bytes = 0; imc_stats.sequence_drops = 0; /* Connect to Hub */ if (!imc_connect_to()) return false; imc_register_call_out(5, "ev_keepalive", null); imc_register_call_out(6, "ev_request_keepalive", null); return true; } final public void ev_imc_firstrefresh() { PACKET out = new PACKET(); if (this_imcmud == null || imc_active < IA_UP) return; out.from = "*"; out.to = "IMC@*"; out.type = "ice-refresh"; imc_initdata(out); imc_addkey(out, "channel", "*"); imc_send(out); } final public boolean imc_startup( boolean force, String loginName, String host, String email, String web, String hub, int port, String passclient, String passsrvr, String[][] channelMap) { if( imc_active != IA_NONE ) { tracef(0, "imc_startup: called with imc_active = "+imc_active ); return false; } imc_now = new Date().getTime()/1000; /* start our clock */ imc_boot = new Date(); imc_sequencenumber = imc_now; for(int i=0;i<channelMap.length;i++) if((channelMap[i][0]!=null)&&(channelMap[i][1]!=null)&&(channelMap[i][2]!=null)) { chan_mask.put(channelMap[i][0],channelMap[i][1]); chan_conf.put(channelMap[i][0],channelMap[i][2]); } imc_name=loginName; imc_log_on=1; // logging? this_imcmud.autoconnect=true; imc_siteinfo.name=CMProps.getVar(CMProps.SYSTEM_MUDNAME); imc_siteinfo.host=host; imc_siteinfo.port=CMath.s_int((String)CMParms.parse(CMProps.getVar(CMProps.SYSTEM_MUDPORTS)).elementAt(0)); imc_siteinfo.email=email; imc_siteinfo.base="CoffeeMud v"+CMProps.getVar(CMProps.SYSTEM_MUDVER); imc_siteinfo.details="Custom Java-based Mud"; imc_siteinfo.www=web; this_imcmud.hubname=hub; this_imcmud.host=hub; this_imcmud.port=port; this_imcmud.clientpw=passclient; this_imcmud.serverpw=passsrvr; if( !this_imcmud.autoconnect && !force ) { tracef(8, "IMC2 data loaded. Autoconnect not set. "+ "IMC will need to be connected manually." ); return false; } imc_active = !imc_name.equals("") ? IA_CONFIG2 : IA_CONFIG1; if( imc_active == IA_CONFIG2 && ( this_imcmud.autoconnect || force ) ) { if( imc_startup_network() ) { ev_imc_firstrefresh(); return true; } imc_active = IA_NONE; } return false; } final String normal2(String data) { data = CMStrings.replaceAll(data, "\\\"", "\""); StringBuffer str=new StringBuffer(data); for(int i=0;i<str.length()-1;i++) { if(str.charAt(i)=='~') switch(str.charAt(i+1)) { case 'R': case 'r': case 'y': case 'Y': case 'g': case 'G': case 'b': case 'B': case 'w': case 'W': case 'c': case 'C': str.setCharAt(i,'^'); break; case 'm': str.setCharAt(i,'^'); str.setCharAt(i+1,'p'); break; case 'M': str.setCharAt(i,'^'); str.setCharAt(i+1,'P'); break; case 'p': str.setCharAt(i,'^'); str.setCharAt(i+1,'p'); break; case 'P': str.setCharAt(i,'^'); str.setCharAt(i+1,'P'); break; case 'z': str.setCharAt(i,'^'); str.setCharAt(i+1,'R'); break; case 'x': case 'u': case 'v': case 'i': case '$': case 's': case 'Z': case 'X': case 'D': str.setCharAt(i,'^'); str.setCharAt(i+1,'W'); break; case 'd': str.setCharAt(i,'^'); str.setCharAt(i+1,'w'); break; case '!': str.setCharAt(i,'^'); str.setCharAt(i+1,'.'); break; case 'L': str.setCharAt(i,'^'); str.setCharAt(i+1,'!'); break; } else if(str.charAt(i)=='^') switch(str.charAt(i+1)) { case 'O': str.setCharAt(i+1,'y'); break; } else if(str.charAt(i)=='&') switch(str.charAt(i+1)) { case 'D': str.setCharAt(i,'^'); str.setCharAt(i+1,'!'); break; } } return str.toString(); } /* printkeys: print key-value pairs, escaping values */ final String printkeys(PACKET data) { String buf; int i; buf = ""; for (i = 0; i < PACKET.IMC_MAX_KEYS; i++) { if (!data.key[i].equals("") ) { buf = buf + data.key[i] + "="; if (data.value[i].equals("")) buf = buf + "\"" + data.value[i] + "\""; else buf = buf + data.value[i]; buf = buf + " "; } } return buf; } final public String do_imcstats() { return "IMC Statistics:\\n\\r\\n"+ "Received packets: "+imc_stats.rx_pkts+"\\n\\r"+ "Received bytes: "+imc_stats.rx_bytes+"\\n\\r"+ "Transmitted packets: "+imc_stats.tx_pkts+"\\n\\r"+ "Transmitted bytes: "+imc_stats.tx_bytes+"\\n\\r"+ "Packets dropped: "+imc_stats.sequence_drops+"\\n\\n\\r"+ "Last IMC Boot: "+imc_boot.toString()+"\\n\\r"; } final public String do_imcinfo() { String host=CMProps.getVar(CMProps.SYSTEM_MUDDOMAIN).toLowerCase(); return "IMC Statistics:\\n\\r\\n"+ "Site Name :"+imc_siteinfo.name+"\\n\\r"+ "Site Host :"+((host.length()>0)?host:sa.getLocalAddress().getHostName())+"\\n\\r"+ "Site Port :"+imc_siteinfo.port+"\\n\\r"+ ((imc_siteinfo.www.length()>0)?"Web Address :"+imc_siteinfo.www+"\\n\\r":"")+ ((imc_siteinfo.www.length()>0)?"Email :"+imc_siteinfo.email+"\\n\\r":"")+ "Codebase :"+imc_siteinfo.base+"\\n\\r"+ "IMC Version :"+IMC_VERSIONID+"\\n\\r"; } final PACKET interpret2(String argument ) { String seq; PACKET out = new PACKET(); imc_initdata(out); StringTokenizer st = new StringTokenizer(argument, " "); if(st.countTokens() < 5) { if(st.countTokens() == 4) { String tmp = st.nextToken(); if(tmp.equalsIgnoreCase("autosetup")) { // who cares what the server says. /* String serverName = st.nextToken(); if(st.nextToken().equalsIgnoreCase("accept")) { String networkName = st.nextToken(); } */ } } else { tracef(0, "interpret: bad packet received, discarding"); tracef(0, "interpret: argument was '"+argument+"'"); imc_stats.sequence_drops++; } return null; } if(imc_stats.max_pkt < argument.length()) imc_stats.max_pkt = argument.length(); imc_stats.rx_bytes += argument.length(); imc_stats.rx_pkts++; int pos = 0; String tmp = st.nextToken(); out.i.from = tmp; pos+=tmp.length(); tmp = st.nextToken(); seq = tmp; pos+=tmp.length(); tmp = st.nextToken(); out.i.path = tmp; pos+=tmp.length(); tmp = st.nextToken(); out.type = tmp; pos+=tmp.length(); tmp = st.nextToken(); out.i.to = tmp; pos+=tmp.length(); String keys = argument.substring(pos+5, argument.length()); try { while((keys.length() > 0) && !keys.equals(" ")) { String key = ""; String val = ""; int kpos = keys.indexOf("="); if(kpos > -1) { key = keys.substring(0, kpos); keys = keys.substring(kpos+1, keys.length()); if(keys.startsWith("\"")) { int p = 0; boolean found = false; while(!found) { p = keys.indexOf("\"", p+1); if(p > -1) { String tmp2 = keys.substring(p-1, p+1); if(!tmp2.equals("\\\"")) found = true; } else { p=keys.length(); found = true; } } val = keys.substring(1, p); if(p>=keys.length()) keys=""; else if(p+2>=keys.length()) keys = keys.substring(p+1, keys.length()); else keys = keys.substring(p+2, keys.length()); } else { if(!keys.equals(" ")) { int npos = keys.indexOf(" "); if (npos > -1) { val = keys.substring(0, npos); if(npos+2 > keys.length()) keys = ""; else keys = keys.substring(npos + 1, keys.length()); } else { val = keys; keys = ""; } } else keys = ""; } } val = normal2(val); imc_addkey(out, key, val); } } catch (StringIndexOutOfBoundsException x) { Log.errOut("IMC2Driver", "Stringerror: "+keys); Log.errOut("IMC2Driver", x); } catch (Exception e) { Log.errOut("IMC2Driver", e); } out.i.sequence = Long.valueOf(seq).longValue(); return out; } final String generate2( PACKET p ) { String temp; String newpath; if(p.i.path.equals("")) newpath = imc_name; else newpath = imc_name+"!"+p.i.path; temp = p.i.from+" "+p.i.sequence+" "+newpath+" "+p.type+" "+p.i.to+" "+printkeys( p ); imc_stats.tx_bytes += temp.length(); imc_stats.tx_pkts++; return temp; } final void do_send_packet( PACKET p ) { String output; output = generate2(p); do_imcsend(output); } final IMC_CHANNEL imc_findchannel( String name ) { if(channels.get(name)!=null) return (IMC_CHANNEL) channels.get(name); return null; } /* return 'mud' from 'player@mud' */ final String imc_mudof(String fullname ) { String buf; int pos = fullname.indexOf("@"); if(pos > -1) buf = fullname.substring(pos+1); else buf = "*"; return buf; } /* return d from a!b!c!d */ final String imc_lastinpath(String path) { int pos = path.lastIndexOf("!"); if(pos < 0) return path; return path.substring(pos+1, path.length()); } /* return 'player' from 'player@mud' */ final String imc_playerof(String fullname ) { String buf; int pos = fullname.indexOf("@"); if(pos > -1) buf = fullname.substring(0, pos); else buf = "*"; return buf; } /* add "key=value" to "p" */ final void imc_addkey(PACKET p, String key, String value) { for(int i = 0; i < value.length(); i++) { if(value.substring(i, i+1).equals("\"")) { String tmp = value.substring(0, i); tmp = tmp.concat("\\\"").concat(value.substring(i+1, value.length())); value = tmp; i++; } } for (int i = 0; i < PACKET.IMC_MAX_KEYS; i++) { if (!p.key[i].equals("") && (key.equalsIgnoreCase(p.key[i]))) { p.key[i] = ""; p.value[i] = ""; break; } } if (value=="") return; for (int i = 0; i < PACKET.IMC_MAX_KEYS; i++) { if (p.key[i] == "") { p.key[i] = key; if((value.indexOf(" ") > -1)) value = "\""+value+"\""; p.value[i] = value; return; } } } /* add "key=value" for an integer value */ final void imc_addkeyi(PACKET p, String key, int value) { String temp; temp = String.valueOf(value); imc_addkey(p, key, temp); } /* clear all keys in "p" */ final void imc_initdata(PACKET p) { int i; for (i = 0; i < PACKET.IMC_MAX_KEYS; i++) { p.key[i] = ""; p.value[i] = ""; } } /* convert back from 'd' to 'p' */ final void setdata(PACKET p, imc_char_data d) { imc_initdata(p); if (d == null) { p.from = "*"; imc_addkeyi(p, "level", -1); return; } p.from = d.name; if (d.wizi > 0) imc_addkeyi(p, "wizi", d.wizi); // imc_addkeyi(p, "level", d.level); } /* send a who-request to a remote mud */ final void imc_send_who(imc_char_data from, String to, String type) { PACKET out = new PACKET(); if (imc_active < IA_UP) return; if (imc_mudof(to).equals("*")) return; /* don't let them do this */ setdata(out, from); out.to = "*@" + imc_mudof(to); out.type = "who"; imc_addkey(out, "type", type); imc_send(out); } /* send a who-request to a remote mud */ public final void imc_send_whois(String from, String to, int level) { PACKET out = new PACKET(); if (imc_active < IA_UP) return; //if (imc_mudof(to).equals("*")) // return; /* don't let them do this */ imc_initdata(out); out.from = from; out.to = to+"@*"; out.type = "whois"; imc_addkeyi(out, "level", level); imc_send(out); } final void imc_send( PACKET p) { if (imc_active < IA_UP) { tracef(0, "imc_send when not active!"); return; } /* initialize packet fields that the caller shouldn't/doesn't set */ p.i.stamp = 0; p.i.path = ""; p.i.sequence = imc_sequencenumber; if(p.i.sequence == imc_prev_sequencenumber) { p.i.sequence++; imc_sequencenumber++; } imc_prev_sequencenumber = imc_sequencenumber; p.i.to = p.to; p.i.from = p.from; p.i.from = p.i.from.concat("@"); p.i.from = p.i.from.concat(imc_name); // p.i.path = this_imcmud.hubname; do_send_packet(p); } final void imc_loop() { return; } // // list of all active call_out's in the game // static LinkedList call_outs = new LinkedList(); public void imc_register_call_out(int hbeat, String function_name, Object param) { Vector call_out = new Vector(); call_out.add(function_name); call_out.add(Long.valueOf(HeartBeat + hbeat)); call_out.add(param); call_outs.add(call_out); } public void imc_process_call_outs() { if (call_outs.size() < 1) { return; } for (int i = 0; i < call_outs.size(); i++) { Vector call_out = (Vector) call_outs.get(i); String fun = (String) call_out.elementAt(0); long hbeat = ( (Long) call_out.elementAt(1)).longValue(); Object param = call_out.elementAt(2); if (hbeat == HeartBeat) { Object o = this; Class<?> cl = o.getClass(); java.lang.reflect.Method funcs[] = cl.getMethods(); if (funcs.length > 1) { for (int k = 0; k < funcs.length; k++) { String m_name = funcs[k].getName(); if (m_name.equals(fun)) { try { funcs[k].invoke(o, new Object[] {param}); } catch (Exception e) { tracef(0, "imc: call_out failed with error: " + e.toString()); } } } } call_outs.remove(i); i--; } } } final public static String toIMCColours(String res) { // ANSI color macros res = CMStrings.replaceAll(res, "\"", "\\\""); StringBuffer str=new StringBuffer(res); for(int i=0;i<str.length()-1;i++) { if(str.charAt(i)=='`') str.setCharAt(i,'\''); else if(str.charAt(i)=='^') switch(str.charAt(i+1)) { case 'R': case 'r': case 'y': case 'Y': case 'g': case 'G': case 'b': case 'B': case 'w': case 'W': case 'c': case 'C': str.setCharAt(i,'~'); break; case 'm': str.setCharAt(i,'~'); str.setCharAt(i+1,'p'); break; case 'M': str.setCharAt(i,'~'); str.setCharAt(i+1,'P'); break; case 'p': str.setCharAt(i,'~'); str.setCharAt(i+1,'m'); break; case 'P': str.setCharAt(i,'~'); str.setCharAt(i+1,'M'); break; case '?': case '.': str.setCharAt(i,'~'); str.setCharAt(i+1,'!'); break; case '!': str.setCharAt(i,'~'); str.setCharAt(i+1,'L'); break; case '*': str.setCharAt(i,'~'); str.setCharAt(i+1,'$'); break; case '/': str.setCharAt(i,'~'); str.setCharAt(i+1,'s'); break; case '_': str.setCharAt(i,'~'); str.setCharAt(i+1,'u'); break; case '^': str.setCharAt(i,'^'); str.deleteCharAt(i+1); break; default: str.setCharAt(i,'~'); str.setCharAt(i+1,'c'); break; } } return str.toString(); } final String update_wholist() { StringBuffer str=new StringBuffer("Players on "+CMProps.getVar(CMProps.SYSTEM_MUDNAME)+":\\n\\r"); Command C=CMClass.getCommand("Who"); Vector V=new Vector(); if(C!=null) { try{C.execute(null,V,0);}catch(Exception e){} if((V.size()>0)&&(V.firstElement() instanceof String)) { String s=(String)V.firstElement(); s=CMStrings.replaceAll((String)V.firstElement(),"\n\r","\\n\\r"); return str.toString()+s; } } return "Unavailable"; } final String who_help() { return "\\n\\r"+ "Available imcminfo types:\\n\\r"+ "help - this screen\\n\\r"+ "who - who is online\\n\\r"+ "info - mud information\\n\\r"+ "who - who is online\\n\\r"; } final void imc_recv_who(imc_char_data from, String sender, String type) { PACKET out = new PACKET(); imc_initdata(out); out.from = from.name; imc_addkeyi(out, "level", 3); out.to = sender; out.type = "who-reply"; if(type.equals("who")) imc_addkey(out, "text", toIMCColours(update_wholist())); else if(type.equals("istats")) imc_addkey(out, "text", toIMCColours(do_imcstats())); else if(type.equals("info")) imc_addkey(out, "text", toIMCColours(do_imcinfo())); else if(type.equals("help")) imc_addkey(out, "text", toIMCColours(who_help())); imc_send(out); } final void imc_recv_whois(imc_char_data from, String sender, int level) { PACKET out = new PACKET(); imc_initdata(out); out.from = from.name; imc_addkeyi(out, "level", 3); out.to = sender; out.type = "whois-reply"; MOB M=CMLib.players().getPlayer(from.name); if(M==null) return; imc_addkey(out, "text", "imcpfind "+from.name+"@"+imc_name +" is "+(CMLib.flags().isInTheGame(M,false) ? "online":"offline")+ "."); imc_send(out); } final void imc_recv_ping(imc_char_data from, String path, String sender) { PACKET out = new PACKET(); imc_initdata(out); out.from = from.name; out.to = sender; out.type = "ping-reply"; imc_addkey(out, "path", path); imc_send(out); } final void imc_recv_tell(imc_char_data d, String from, String text) { MOB mob=CMClass.getMOB("StdMOB"); mob.setName(from); mob.setLocation(CMClass.getLocale("StdRoom")); MOB smob=findSessMob(d.name); if(smob!=null) CMLib.commands().postSay(mob,smob,text,true,true); Room R=mob.location(); mob.destroy(); if(R!=null) R.destroy(); } protected MOB findSessMob(String mobName) { for(int s=0;s<CMLib.sessions().size();s++) { Session ses=CMLib.sessions().elementAt(s); if((!ses.killFlag())&&(ses.mob()!=null) &&(!ses.mob().amDead()) &&(ses.mob().Name().equalsIgnoreCase(mobName)) &&(ses.mob().location()!=null)) return ses.mob(); } return null; } public REMOTEINFO getIMC2Mud(String named) { Hashtable l=query_muds(); if(l.containsKey(named)) return (REMOTEINFO)l.get(named); for(Enumeration e=l.elements();e.hasMoreElements();) { REMOTEINFO m=(REMOTEINFO)e.nextElement(); if(m.name.equalsIgnoreCase(named)) return m; } return null; } final void imc_recv_chat(imc_char_data d, String from, String channel, String text, int emote) { StringTokenizer st = new StringTokenizer(channel, ":"); if (st.countTokens() > 1) { channel = st.nextToken(); channel = st.nextToken(); } else if(st.countTokens()> 0) channel=st.nextToken(); String channelName=channel; CMMsg msg=null; if(from.toUpperCase().endsWith(imc_name.toUpperCase())) return; if(channelName.length()==0) return; channelName=read_channel_name(channelName); if(channelName.length()==0) return; int channelInt=CMLib.channels().getChannelIndex(channelName); if(channelInt<0) return; MOB mob=CMClass.getMOB("StdMOB"); mob.setName(from); mob.setLocation(CMClass.getLocale("StdRoom")); String str="^Q^<CHANNEL \""+channelName+"\"^>"+mob.name()+" "+channelName+"(S) '"+text+"'^</CHANNEL^>^N^."; if(emote>0) { if(emote==1) str="^Q^<CHANNEL \""+channelName+"\"^>["+channelName+"] "+from+" "+text+"^</CHANNEL^>^N^."; else str="^Q^<CHANNEL \""+channelName+"\"^>["+channelName+"] "+text+"^</CHANNEL^>^N^."; } msg=CMClass.getMsg(mob,null,null,CMMsg.NO_EFFECT,null,CMMsg.NO_EFFECT,null,CMMsg.MASK_CHANNEL|(CMMsg.TYP_CHANNEL+channelInt),str); CMLib.channels().channelQueUp(channelInt,msg); for(int s=0;s<CMLib.sessions().size();s++) { Session ses=CMLib.sessions().elementAt(s); if((CMLib.channels().mayReadThisChannel(mob,false,ses,channelInt)) &&(ses.mob().location()!=null) &&(ses.mob().location().okMessage(ses.mob(),msg))) ses.mob().executeMsg(ses.mob(),msg); } LinkedList l = (LinkedList) chanhist.get(channel); if(l == null) l = new LinkedList(); l.add(str); chanhist.put(channel, l); Room R=mob.location(); mob.destroy(); if(R!=null) R.destroy(); } final void imc_recv_is_alive(imc_char_data d, String from, String path, String version, String netname) { String mudname = imc_mudof(from); REMOTEINFO rinfo = new REMOTEINFO(); rinfo.name = mudname; rinfo.network = netname; rinfo.version = version; int pos = path.indexOf("!"); if(pos > -1) { String hubs = path.substring(pos+1, path.length()); int pos2 = hubs.indexOf("!"); if(pos2 > -1) rinfo.hub = hubs.substring(0, pos2); else rinfo.hub = hubs; } else rinfo.hub = "None"; muds.put(mudname, rinfo); } final void imc_recv_who_reply(imc_char_data d, String text) { text = CMStrings.replaceAll(text, "\\n\\r", "\n\r"); send_to_player(d.name, "\n\r"+text+"^.^?"); } final void imc_recv_whois_reply(imc_char_data d, String to, String text) { text = CMStrings.replaceAll(text, "\\n\\r", "\n\r"); send_to_player(d.name, "\n\r"+to+": "+text+"^.^?"); } final void imc_recv_ping_reply(imc_char_data d, String from, String path) { String route[] = explodeNicely(path, "!"); StringBuffer text = new StringBuffer("Traceroute information for "+from+"\n\r"); text.append("^cSend path:^? "); for(int i = 0; i < route.length; i++) { if (i > 0) text.append("->"); text.append(route[i]); } text.append("\n\r"); text.append("^cReturn path:^? "); for(int i= route.length-1; i >= 0; i--) { if (i < route.length-1) text.append("->"); text.append(route[i]); } send_to_player(d.name, text.toString()); } final String read_channel_name(String channame) { if(channame==null) return ""; channame=channame.toUpperCase(); for(Enumeration e=chan_conf.keys();e.hasMoreElements();) { String key=(String)e.nextElement(); String val=((String)chan_conf.get(key)).toUpperCase(); if(val.equals(channame)) return key; if(val.endsWith(":"+channame)) return key; if(channame.endsWith(":"+val)) return key; } return ""; } public IMC_CHANNEL getAnIMC2Channel(String name) { name=name.toUpperCase(); for(Enumeration e=channels.elements();e.hasMoreElements();) { IMC_CHANNEL c=(IMC_CHANNEL)e.nextElement(); if(read_channel_name(c.name).equalsIgnoreCase(name)) return c; } return null; } final void imc_recv_update(String from, String chan, String owner, String operators, String policy, String invited, String excluded ) { IMC_CHANNEL c; String mud; mud = imc_mudof(from); /* forged? */ if (chan.indexOf(":")<-1 || !mud.equalsIgnoreCase(imc_mudof(chan))) return; c = new IMC_CHANNEL(); c.name = chan; c.owner = owner; c.operators = operators; c.invited = invited; c.excluded = excluded; c.local_name = this.read_channel_name(chan); c.perm_level = PERM_ADMIN; c.refreshed = true; if (policy.equalsIgnoreCase("open")) c.policy = CHAN_OPEN; else if (policy.equalsIgnoreCase("closed")) c.policy = CHAN_CLOSED; else if (policy.equalsIgnoreCase("copen")) c.policy = CHAN_COPEN; else if (policy.equalsIgnoreCase("cprivate")) c.policy = CHAN_CPRIVATE; else c.policy = CHAN_PRIVATE; channels.put(c.name, c); } /* get the value of "key" from "p"; if it isn't present, return "def" */ final String imc_getkey( PACKET p, String key, String def ) { int i; for( i = 0; i < PACKET.IMC_MAX_KEYS; i++ ) if( !p.key[i].equals("") && p.key[i].equalsIgnoreCase(key)) { if(p.value[i].startsWith("\"")) return p.value[i].substring(1, p.value[i].length()-1); return p.value[i]; } return def; } /* identical to imc_getkey, except get the integer value of the key */ final int imc_getkeyi( PACKET p, String key, int def ) { int i; for( i = 0; i < PACKET.IMC_MAX_KEYS; i++ ) if( !p.key[i].equals("") && p.key[i].equalsIgnoreCase(key) ) { return CMath.s_int(p.value[i]); } return def; } final public Hashtable query_channels() { return channels; } final public Hashtable query_muds() { return muds; } final public void exec_commands(PACKET p) { if (p == null) return; imc_char_data d = new imc_char_data(); d.name = p.i.to; d.wizi = imc_getkeyi(p, "wizi", 0); d.level = imc_getkeyi(p, "level", 0); d.invis = 0; String to_mud = imc_mudof(d.name); if (!to_mud.equalsIgnoreCase(imc_name) && !to_mud.equals("*")) { tracef(8, "Message was for "+to_mud+", not "+imc_name+" -- rejecting!"); return; } d.name = imc_playerof(d.name); tracef(8, "Received message was sent to " + d.name+", "+p.type+", "+CMParms.toStringList(p.value)); if (p.type.equals("who")) { tracef(8, "Who request received from " + p.i.from); imc_recv_who(d, p.i.from, imc_getkey(p, "type", "who")); } if (p.type.equals("whois")) { tracef(8, "Whois request received from " + p.i.from); imc_recv_whois(d, p.i.from, imc_getkeyi(p, "level", 0)); } if (p.type.equals("ping")) { tracef(8, "Ping reply received from " + p.i.from); imc_recv_ping(d, p.i.path, p.i.from); } if (p.type.equals("tell")) { tracef(8, "Tell received from " + p.i.from); imc_recv_tell(d, p.i.from, imc_getkey(p, "text", "")); } if (p.type.equals("keepalive-request")) { tracef(8, "Keepalive request received from " + p.i.from); imc_send_isalive(p.i.from); } if (p.type.equals("who-reply")) { tracef(8, "Who reply received from " + p.i.from); imc_recv_who_reply(d, imc_getkey(p, "text", "")); } if (p.type.equals("whois-reply")) { tracef(8, "Who-Is reply received from " + p.i.from); imc_recv_whois_reply(d, p.i.from, imc_getkey(p, "text", "")); } if (p.type.equals("ping-reply")) { tracef(8, "Ping-reply reply received from " + p.i.from); imc_recv_ping_reply(d, p.i.from, imc_getkey(p, "path", "")); } if (p.type.equals("is-alive")) { tracef(8, "is-alive received from " + p.i.from); imc_recv_is_alive(d, p.i.from, p.i.path, imc_getkey(p, "versionid", "Unknown"), imc_getkey(p, "networkname", "None")); } if (p.type.equals("ice-msg-b")) { tracef(8, "Chat received from " + p.i.from); imc_recv_chat(d, p.i.from, imc_getkey(p, "channel", "ICHAT"), imc_getkey(p, "text", ""),CMath.s_int(imc_getkey(p,"emote","0"))); } if (p.type.equals("ice-update")) { tracef(8, "Ice update reply from " + p.i.from); imc_recv_update(p.from, imc_getkey(p, "channel", ""), imc_getkey(p, "owner", ""), imc_getkey(p, "operators", ""), imc_getkey(p, "policy", ""), imc_getkey(p, "invited", ""), imc_getkey(p, "excluded", "")); } } final boolean check_password(String s) { StringTokenizer st = new StringTokenizer(s, " "); if (st.countTokens() < 3) { tracef(0, "Password not found in Hub reply."); return false; } st.nextToken(); st.nextToken(); String pwd = st.nextToken(); if (pwd.equals(this_imcmud.serverpw)) { tracef(8, "Password OK."); return true; } tracef(0, "Password incorrect."); return false; } final public void imc_read_from_socket(BufferedReader in) { try { if ((in!=null)&&(in.ready())) { String s = in.readLine(); if (s == null) return; if (s.length() > 0) { tracef(8, "imc: received '" + s + "'"); if (s.startsWith("PW ")) check_password(s); else { PACKET p = interpret2(s); if(p!=null) exec_commands(p); } } } } catch (Exception e) { String errMsg=e.getMessage()==null?e.toString():e.getMessage(); if((errMsg==null) ||(errMsg.toUpperCase().indexOf("TIMED OUT")<0)) Log.errOut("IMC2Driver", "read: "+errMsg); if((errMsg!=null) &&(!shutdown) &&(errMsg.toUpperCase().indexOf("CONNECTION")>=0)) { imc_active = IA_NONE; tracef(0, "Waiting 20 seconds and try to reconnect."); try { sleep(20000); } catch (Exception ex) {} this.imc_startup(true, imc_name, imc_siteinfo.host, imc_siteinfo.email, imc_siteinfo.www, this_imcmud.hubname, this_imcmud.port, this_imcmud.clientpw, this_imcmud.serverpw, buildChannelMap()); } } } final public void imc_write_to_socket(DataOutputStream out) { try { if (this_imcmud.outbuf.equals("")) return; tracef(8, "imc: sending '" + this_imcmud.outbuf + "'"); out.write(this_imcmud.outbuf.getBytes()); this_imcmud.outbuf = ""; } catch (Exception e) { tracef(0, "write socket error: " + e.toString()); imc_active = IA_NONE; tracef(0, "Waiting 20 seconds and try to reconnect."); try { sleep(20000); } catch (Exception ex) {} this.imc_startup(true, imc_name, imc_siteinfo.host, imc_siteinfo.email, imc_siteinfo.www, this_imcmud.hubname, this_imcmud.port, this_imcmud.clientpw, this_imcmud.serverpw, buildChannelMap()); } } /* send a keepalive to everyone */ final public void imc_send_isalive(String reqFrom) { PACKET out = new PACKET(); if (imc_active < IA_UP) return; imc_initdata(out); out.type = "is-alive"; out.from = "*"; if(reqFrom.endsWith("*")) { Log.errOut("IMC2 SPAM DETECTED: "+reqFrom+"!"); } out.to = reqFrom; imc_addkey(out, "versionid", IMC_VERSIONID); imc_addkey(out, "networkname", this_imcmud.network); if (imc_siteinfo.flags != null && !"".equals(imc_siteinfo.flags)) imc_addkey(out, "flags", imc_siteinfo.flags); imc_send(out); } /* send a keepalive to everyone */ final public void imc_request_keepalive() { PACKET out = new PACKET(); if (imc_active < IA_UP) return; imc_initdata(out); out.type = "keepalive-request"; out.from = "*"; out.to = "*@*"; imc_addkey(out, "versionid", IMC_VERSIONID); if (imc_siteinfo.flags != null && !"".equals(imc_siteinfo.flags)) imc_addkey(out, "flags", imc_siteinfo.flags); imc_send(out); } final class call_out extends Thread { IMC2Driver imc_client; boolean shutdown=false; public boolean isShutdown=false; int seq = 0; public call_out(IMC2Driver _imc_client) { super("IMC2-call_out"); setName("IMC2-call_out"); imc_client = _imc_client; setDaemon(true); } public void shutdown() { shutdown=true; interrupt(); } final public void run() { if (imc_client == null) return; while (!shutdown) { // tracef(1, "call_out: process call outs"); imc_client.imc_process_call_outs(); imc_client.imc_write_to_socket(out); try { sleep(100); seq++; if (seq % 10 == 0) { imc_client.imc_sequencenumber++; seq = 0; } } catch (Exception e) {} } isShutdown=true; } } final class call_in extends Thread { IMC2Driver imc_client; boolean shutdown=false; public boolean isShutdown=false; public call_in(IMC2Driver _imc_client) { super("IMC2-call_in"); setName("IMC2-call_in"); imc_client = _imc_client; setDaemon(true); } public void shutdown() { shutdown=true; interrupt(); } final public void run() { if (imc_client == null) return; while (!shutdown) { // tracef(1, "call_out: process call outs"); imc_client.imc_read_from_socket(in); try { sleep(100); } catch (Exception e) {} } isShutdown=true; } } /* send a ping with a given timestamp */ final public void imc_send_ping(String name, String to, int time_s, int time_u) { PACKET out = new PACKET(); if (imc_active < IA_UP) return; imc_initdata(out); out.type = "ping"; out.from = name; out.to = "*@" + to; imc_addkeyi(out, "time-s", time_s); imc_addkeyi(out, "time-us", time_u); imc_send(out); out = null; } final public void run_imcpinfo(String name, String mudname, String who, int level, int invis) { imc_char_data test = new imc_char_data(); test.name = name; test.level = level; test.invis = invis; imc_send_who(test, "@" + mudname, "finger " + who); } final public void run_imcminfo(String name, String mudname, String type, int level, int invis) { imc_char_data test = new imc_char_data(); test.name = name; test.level = level; test.invis = invis; imc_send_who(test, "@" + mudname, type); } final public void imc_send_who(String name, String mudname, String type, int level, int invis) { imc_char_data test = new imc_char_data(); test.name = name; test.level = level; test.invis = invis; imc_send_who(test, "@" + mudname, type); } final public String imc_send_tell(String from, String to, String text, int level, int invis) { imc_char_data chr = new imc_char_data(); chr.name = from; chr.level = level; chr.invis = invis; return imc_send_tell(chr, to, text, 1); } final public String imc_send_reply(String from, String text, int level, int invis) { imc_char_data chr = new imc_char_data(); chr.name = from; chr.level = level; chr.invis = invis; return imc_send_reply(chr, text); } final public String imc_send_chat(String from, String to, String text, int level, int emote) { imc_char_data chr = new imc_char_data(); chr.name = from; chr.level = level; return imc_send_chat(chr, to, text, level, emote); } /* send a tell to a remote player */ final String imc_send_tell(imc_char_data from, String to, String argument, int isreply) { PACKET out = new PACKET(); if (imc_active < IA_UP) return "IMC is not active."; if (imc_mudof(to).equals("*")) return "You cannot send tell to everyone!"; /* don't let them do this */ setdata(out, from); out.to = to; out.type = "tell"; imc_addkeyi(out, "level", 3); imc_addkey(out, "text", toIMCColours(argument)); imc_send(out); replies.put(from.name, to); String chatText = "You tell " + to + " '^c" + argument + "'^?."; return chatText; } /* send a reply to a remote player */ final String imc_send_reply(imc_char_data from, String argument) { PACKET out = new PACKET(); if (imc_active < IA_UP) return "IMC is not active."; setdata(out, from); String to = (String) replies.get(from.name); if (to == null) return "Noone to reply to."; out.to = to; out.type = "tell"; imc_addkeyi(out, "level", 3); imc_addkey(out, "text", toIMCColours(argument)); imc_send(out); String chatText = "You tell " + to + " ^c'" + argument + "'^?."; return chatText; } /* send a tell to a remote player */ final String imc_send_chat(imc_char_data from, String to, String argument, int isreply, int emote) { PACKET out = new PACKET(); if (imc_active < IA_UP) return "IMC is not running."; setdata(out, from); // imc_addkey(p, "level", 3); out.to = "*@*"; out.type = "ice-msg-b"; imc_addkey(out, "channel", to); imc_addkey(out, "text", toIMCColours(argument)); imc_addkeyi(out, "emote", emote); /* if (isreply > 0) imc_addkeyi(out, "isreply", isreply);*/ imc_send(out); String chan = to; int pos = to.indexOf(":"); if (pos > -1) chan = to.substring(pos + 1, to.length()); String text = argument; if (argument.startsWith(", ") || emote == 1) text = from.name + "@" + this.imc_name; String chatText = from.name + "@" + this.imc_name + " [" + chan + "] " + " " + text + "^?"; LinkedList l = (LinkedList) chanhist.get(chan); if (l == null) l = new LinkedList(); l.add(chatText); chanhist.put(chan, l); return chatText; } final public void run() { imc_read_from_socket(in); HeartBeat = 0; if(c_thread2==null) { c_thread2 = new call_in(this); c_thread2.start(); } if(c_thread==null) { c_thread = new call_out(this); c_thread.start(); } Log.sysOut("IMC2","(c) 1996-2002/Java port by Istvan David"); Log.sysOut("IMC2","Client connected to "+this_imcmud.host.trim()); while (!shutdown) { HeartBeat++; try { sleep(2000); } catch (Exception e) {} isShutdown=true; } } }