/*
Copyright 2012 Jan Ove Saltvedt
This file is part of KBot.
KBot 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 3 of the License, or
(at your option) any later version.
KBot 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 KBot. If not, see <http://www.gnu.org/licenses/>.
*/
package com.kbotpro.handlers;
import com.kbotpro.bot.BotEnvironment;
import com.kbotpro.handlers.kbotscriptsystem.KBot2Script;
import com.kbotpro.scriptsystem.Methods;
import com.kbotpro.scriptsystem.runnable.Script;
import com.kbotpro.scriptsystem.runnable.Service;
import com.kbotpro.scriptsystem.runnable.ServiceCallback;
import com.kbotpro.servercom.ServerCom;
import com.kbotpro.ui.ErrorBox;
import com.kbotpro.ui.MainForm;
import com.kbotpro.ui.ProgressUI;
import com.kbotpro.utils.ProgressCallback;
import com.kbotpro.various.ScriptAnalyzer;
import com.kbotpro.various.ScriptClassLoader;
import com.kbotpro.various.ScriptMetaData;
import com.kbotpro.various.StaticStorage;
import org.apache.log4j.Logger;
import javax.swing.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.jar.JarInputStream;
/**
* Created by IntelliJ IDEA.
* User: Jan Ove Saltvedt
* Date: Nov 3, 2009
* Time: 6:57:20 PM
* To change this template use File | Settings | File Templates.
*/
public class ScriptManager implements ServiceCallback {
private BotEnvironment bot;
public List<Script> runningScripts = Collections.synchronizedList(new ArrayList<Script>());
private boolean askForAccount = true;
public ScriptManager(BotEnvironment bot) {
this.bot = bot;
}
public void startScript(final ScriptMetaData scriptMetaData) {
if (!scriptMetaData.isTrusted()) {
if (JOptionPane.showConfirmDialog(null, "This script is not verified.\nThe script may contain malicious code.\nDo you still want to run the script?", "Unverified script!", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
return;
}
}
if (scriptMetaData.isProScript() && !StaticStorage.userStorage.canRunProScripts()) {
JOptionPane.showMessageDialog(null, "You don't have privileges to run KBot PRO scripts", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
ProgressCallback progressCallback = new ProgressCallback() {
int counter = 0;
ProgressUI ui = new ProgressUI(StaticStorage.mainForm);
public void update(int pos, int length) {
counter++;
if (counter > 150) {
counter = 0;
if (ui.isVisible()) {
ui.setVisible(true);
if (length == -1) {
ui.progressBar.setIndeterminate(true);
} else {
ui.progressBar.setValue((pos * 100) / length);
}
}
}
}
public void onComplete() {
ui.dispose();
}
};
ServerCom serverCom = StaticStorage.serverCom;
byte[] data = serverCom.downloadScript(scriptMetaData.ID, progressCallback);
//---
/*if (askForAccount && !bot.accountsHandler.isAccountSelected()) {
if (!bot.accountsHandler.showAccountSelector()) {
JOptionPane.showMessageDialog(null, "Can not use accounts, auto login disabled.");
}
askForAccount = false;
} */
//--
JarInputStream zipInputStream = null;
startScript(data, true, scriptMetaData.permissionExceptions);
}
public void startScript(final byte[] data, final boolean loadedFromServer, final List<Permission> permissionExceptions) {
new Thread(new Runnable() {
public void run() {
try {
JarInputStream jarInputStream = new JarInputStream(new ByteArrayInputStream(data));
ScriptAnalyzer scriptAnalyzer = new ScriptAnalyzer(jarInputStream);
if (scriptAnalyzer.usesKBotPROPackages() && !StaticStorage.userStorage.canRunProScripts()) {
JOptionPane.showMessageDialog(null, "You don't have privileges to run KBot PRO scripts", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
/*if(scriptAnalyzer.usesRuntime()){
JOptionPane.showMessageDialog(null, "This script uses methods that may be used for malicious purposes.\n KBot will not run this script.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}*/
jarInputStream = new JarInputStream(new ByteArrayInputStream(data));
try {
ScriptClassLoader classLoader = new ScriptClassLoader(jarInputStream, loadedFromServer, permissionExceptions);
Class klass = classLoader.loadMainClass();
if (klass == null) {
return;
}
Object scriptObject = klass.newInstance();
Script script;
if (scriptObject instanceof com.kbot2.scriptable.Script) {
script = new KBot2Script((com.kbot2.scriptable.Script) scriptObject, bot);
} else {
script = (Script) scriptObject;
}
Method registeMethod = Methods.class.getDeclaredMethod("registerInternal", new Class<?>[]{BotEnvironment.class});
registeMethod.setAccessible(true); // This method is private so we set it by a little reflection hack
registeMethod.invoke(script, bot);
Method getService = Script.class.getDeclaredMethod("getService");
getService.setAccessible(true);
Service service = (Service) getService.invoke(script);
service.setCallback(ScriptManager.this);
service.sStart();
jarInputStream.close();
return;
} catch (IllegalAccessException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
outputError(e);
} catch (InstantiationException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
outputError(e);
} catch (InvocationTargetException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
outputError(e);
} catch (NoSuchMethodException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
outputError(e);
} catch (NoClassDefFoundError e) {
Logger.getRootLogger().error("Exception: ", e);
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return;
}
try {
jarInputStream.close();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
} catch (IOException e) {
Logger.getRootLogger().error("Exception: ", e);
}
}
}).start();
}
public void outputError(Throwable throwable) {
final String[] message = new String[]{""};
PrintStream printStream = new PrintStream(new OutputStream() {
@Override
public void write(int b) throws IOException {
message[0] += (char) b;
}
});
throwable.printStackTrace(printStream);
new ErrorBox(StaticStorage.mainForm, "An error occured:\n\n" + message[0]).setVisible(true);
}
/**
* Callback to update the service state.
*
* @param state state to be set
* @param instance
*/
public synchronized void setState(State state, Object instance) {
if (state == State.ACTIVE) {
Script script = (Script) instance;
bot.log.log("Started script " + script.getName());
runningScripts.add(script);
} else if (state == State.DEAD) {
Script script = (Script) instance;
if (runningScripts.contains(script)) {
bot.log.log("Stopped script " + script.getName());
try {
Method deregisterMethod = Methods.class.getDeclaredMethod("deregisterInternal");
deregisterMethod.setAccessible(true); // This method is private so we set it by a little reflection hack
deregisterMethod.invoke(script);
} catch (NoSuchMethodException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
} catch (InvocationTargetException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
} catch (IllegalAccessException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
}
runningScripts.remove(script);
}
}
}
public void stopScript(Script script) {
Method getService = null;
try {
getService = Script.class.getDeclaredMethod("getService");
getService.setAccessible(true);
Service service = (Service) getService.invoke(script);
service.sStop();
} catch (NoSuchMethodException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
} catch (InvocationTargetException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
} catch (IllegalAccessException e) {
Logger.getRootLogger().error("Exception: ", e); //To change body of catch statement use File | Settings | File Templates.
}
}
public void stopAllScripts() {
bot.randomManager.scriptStopped = true;
for (Script script : runningScripts) {
script.getBotEnv().mouse.stopAllJobs();
stopScript(script);
}
}
private boolean pauseScripts = false;
public boolean isScriptsPaused() {
return pauseScripts;
}
public void setPauseScripts(boolean pauseScripts) {
this.pauseScripts = pauseScripts;
if (StaticStorage.mainForm.getOpenedBotPanel().equals(bot.botPanel)) {
if(pauseScripts){
StaticStorage.mainForm.pauseScriptButton.setIcon(new ImageIcon(MainForm.class.getResource("/images/NewScriptIcon.gif")));
StaticStorage.mainForm.pauseScriptButton.setText("Resume");
}
else{
StaticStorage.mainForm.pauseScriptButton.setIcon(new ImageIcon(MainForm.class.getResource("/images/PauseScriptIcon.gif")));
StaticStorage.mainForm.pauseScriptButton.setText("Pause");
}
}
for (Script script : runningScripts) {
if (pauseScripts) {
script.onPause();
} else {
script.onResume();
}
}
}
public int getRunningScriptCount() {
return runningScripts.size();
}
public void disposeResources() {
bot = null;
runningScripts = null;
}
}