/*
* WPCleaner: A tool to help on Wikipedia maintenance tasks.
* Copyright (C) 2013 Nicolas Vervelle
*
* See README.txt file for licensing information.
*/
package org.wikipediacleaner;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wikipediacleaner.api.check.algorithm.CheckErrorAlgorithm;
import org.wikipediacleaner.api.check.algorithm.CheckErrorAlgorithms;
import org.wikipediacleaner.api.constants.EnumLanguage;
import org.wikipediacleaner.api.constants.EnumWikipedia;
import org.wikipediacleaner.api.data.ISBNRange;
import org.wikipediacleaner.gui.swing.basic.BasicWorker;
import org.wikipediacleaner.gui.swing.basic.BasicWorkerListener;
import org.wikipediacleaner.gui.swing.bot.AutomaticCWWorker;
import org.wikipediacleaner.gui.swing.bot.ListCWWorker;
import org.wikipediacleaner.gui.swing.worker.LoginWorker;
import org.wikipediacleaner.gui.swing.worker.UpdateDabWarningWorker;
import org.wikipediacleaner.gui.swing.worker.UpdateDuplicateArgsWarningWorker;
import org.wikipediacleaner.gui.swing.worker.UpdateISBNWarningWorker;
import org.wikipediacleaner.gui.swing.worker.UpdateISSNWarningWorker;
import org.wikipediacleaner.i18n.GT;
import org.wikipediacleaner.utils.Configuration;
import org.wikipediacleaner.utils.ConfigurationConstants;
import org.wikipediacleaner.utils.ConfigurationValueBoolean;
import org.wikipediacleaner.utils.ConfigurationValueString;
/**
* Wikipedia Cleaner running as a bot.
*/
public class Bot implements BasicWorkerListener {
private final static Log log = LogFactory.getLog(Bot.class);
/**
* @param args
*/
public static void main(String[] args) {
log.info("Running as bot");
// Log levels
Logger.getLogger("org.lobobrowser").setLevel(Level.WARNING);
Logger.getLogger("").setLevel(Level.WARNING);
Configuration config = Configuration.getConfiguration();
EnumLanguage language = config.getLanguage();
Locale.setDefault(language.getLocale());
// Debugging
if (config.getBoolean(null, ConfigurationValueBoolean.DEBUG_DETAILS)) {
Logger.getLogger("org.wikipediacleaner").setLevel(Level.FINE);
}
if (config.getBoolean(null, ConfigurationValueBoolean.DEBUG_FILE)) {
try {
Handler fh = new FileHandler("WPCleanerBot.log");
fh.setFormatter(new SimpleFormatter());
Logger.getLogger("").addHandler(fh);
} catch (Exception e) {
// Nothing to do
}
}
// Language
GT.setCurrentLanguage(config.getLanguage());
// Various initializations
ISBNRange.initialize();
new Bot(args);
}
/** Time limit for bot execution. */
private Integer timeLimit;
/** Wiki */
private EnumWikipedia wiki;
/** True if login is done */
private boolean loginDone;
/** Actions to be executed */
private String[] actions;
/**
* @param args Command line arguments
*/
private Bot(String[] args) {
// Analyze command line arguments
int currentArg = 0;
// Process general command line arguments
boolean done = false;
timeLimit = null;
String credentials = null;
while (!done) {
if (args.length > currentArg) {
String arg = args[currentArg];
if ("-timelimit".equals(arg)) {
timeLimit = Integer.valueOf(args[currentArg + 1]);
currentArg += 2;
} else if ("-credentials".equals(arg)) {
credentials = args[currentArg + 1];
currentArg += 2;
} else {
done = true;
}
}
}
// Retrieve wiki
if (args.length > currentArg) {
String wikiCode = args[currentArg];
wiki = EnumWikipedia.getWikipedia(wikiCode);
if ((wiki == null) || !wikiCode.equals(wiki.getSettings().getCode())) {
log.warn("Unable to find wiki " + wikiCode);
return;
}
}
currentArg++;
// Retrieve user name and password
String userName = null;
String password = null;
if (credentials != null) {
Properties properties = new Properties();
try {
properties.load(new FileReader(credentials));
} catch (IOException e) {
log.warn("Unable to load credentials file " + credentials);
return;
}
userName = properties.getProperty("user");
password = properties.getProperty("password");
} else {
if (args.length > currentArg) {
userName = args[currentArg];
}
currentArg++;
if (args.length > currentArg) {
password = args[currentArg];
}
currentArg++;
}
// Retrieve action
actions = (args.length > currentArg) ?
Arrays.copyOfRange(args, currentArg, args.length) : null;
currentArg++;
// Check arguments
if ((wiki == null) ||
(userName == null) ||
(password == null) ||
(actions == null) ||
(actions.length == 0)) {
log.warn("Some parameters are incorrect");
return;
}
// Login
loginDone = false;
LoginWorker loginWorker = new LoginWorker(
wiki, null, null, EnumLanguage.getDefaultLanguage(),
userName, password.toCharArray(),
ConfigurationConstants.VALUE_SAVE_USER_NO_CHANGE, true, false);
loginWorker.setListener(this);
loginWorker.start();
}
/**
* Execute an action.
*
* @param args Action and arguments.
*/
void executeAction(String[] args) {
// Retrieve action
int currentArg = 0;
if (currentArg >= args.length) {
return;
}
String action = args[currentArg];
currentArg++;
// Execute action depending on the parameters
BasicWorker worker = null;
if ("UpdateDabWarnings".equalsIgnoreCase(action)) {
Configuration config = Configuration.getConfiguration();
String start = config.getString(null, ConfigurationValueString.LAST_DAB_WARNING);
if (args.length > currentArg) {
if (args[currentArg].equals("*")) {
start = null;
} else {
start = args[currentArg];
}
}
worker = new UpdateDabWarningWorker(wiki, null, start);
} else if ("UpdateISBNWarnings".equalsIgnoreCase(action)) {
worker = new UpdateISBNWarningWorker(wiki, null, false);
} else if ("ListISBNWarnings".equalsIgnoreCase(action)) {
worker = new UpdateISBNWarningWorker(wiki, null, true);
} else if ("UpdateISSNWarnings".equalsIgnoreCase(action)) {
worker = new UpdateISSNWarningWorker(wiki, null, false);
} else if ("ListISSNWarnings".equalsIgnoreCase(action)) {
worker = new UpdateISSNWarningWorker(wiki, null, true);
} else if ("UpdateDuplicateArgsWarnings".equalsIgnoreCase(action)) {
worker = new UpdateDuplicateArgsWarningWorker(wiki, null, false);
} else if ("FixCheckWiki".equalsIgnoreCase(action)) {
List<CheckErrorAlgorithm> algorithms = new ArrayList<CheckErrorAlgorithm>();
List<CheckErrorAlgorithm> allAlgorithms = new ArrayList<CheckErrorAlgorithm>();
if (args.length > currentArg) {
extractAlgorithms(algorithms, allAlgorithms, args, currentArg);
}
worker = new AutomaticCWWorker(
wiki, null, algorithms, 10000, true, allAlgorithms, null, true, false);
} else if ("MarkCheckWiki".equalsIgnoreCase(action)) {
List<CheckErrorAlgorithm> algorithms = new ArrayList<CheckErrorAlgorithm>();
List<CheckErrorAlgorithm> allAlgorithms = new ArrayList<CheckErrorAlgorithm>();
if (args.length > currentArg) {
extractAlgorithms(algorithms, allAlgorithms, args, currentArg);
}
worker = new AutomaticCWWorker(
wiki, null, algorithms, 10000, true, allAlgorithms, null, false, false);
} else if ("ListCheckWiki".equalsIgnoreCase(action)) {
boolean check = true;
boolean onlyRecheck = false;
boolean optionsFinished = false;
while (!optionsFinished && (args.length > currentArg)) {
if ("-nocheck".equalsIgnoreCase(args[currentArg])) {
check = false;
currentArg++;
} else if ("-onlyRecheck".equalsIgnoreCase(args[currentArg])) {
onlyRecheck = true;
currentArg++;
} else {
optionsFinished = true;
}
}
if (args.length > currentArg + 2) {
File dumpFile = getDumpFile(args[currentArg]);
List<CheckErrorAlgorithm> algorithms = new ArrayList<CheckErrorAlgorithm>();
extractAlgorithms(algorithms, null, args, currentArg + 2);
if (args[currentArg + 1].startsWith("wiki:")) {
String pageName = args[currentArg + 1].substring(5);
worker = new ListCWWorker(
wiki, null, dumpFile, pageName,
algorithms, check, onlyRecheck);
} else {
File output = new File(args[currentArg + 1]);
worker = new ListCWWorker(
wiki, null, dumpFile, output,
algorithms, check);
}
}
}
if (worker != null) {
worker.setListener(this);
worker.setTimeLimit(timeLimit);
worker.start();
}
}
/**
* @param algorithms List of selected algorithms.
* @param allAlgorithms List of all possible algorithms.
* @param args Arguments.
* @param startIndex Start index in the arguments.
*/
private void extractAlgorithms(
List<CheckErrorAlgorithm> algorithms,
List<CheckErrorAlgorithm> allAlgorithms,
String[] args, int startIndex) {
for (int i = startIndex; i < args.length; i++) {
boolean addition = false;
String algorithmNumber = args[i];
if (algorithmNumber.startsWith("+")) {
addition = true;
algorithmNumber = algorithmNumber.substring(1);
}
if (algorithmNumber.equals("*") || algorithmNumber.equals("!")) {
// NOTE: Allowing "!" because of Eclipse bug with "*"
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=212264
List<CheckErrorAlgorithm> possibleAlgorithms = CheckErrorAlgorithms.getAlgorithms(wiki);
for (CheckErrorAlgorithm algorithm : possibleAlgorithms) {
if ((algorithm != null) && algorithm.isAvailable()) {
if (!addition) {
algorithms.add(algorithm);
}
if (allAlgorithms != null) {
allAlgorithms.add(algorithm);
}
}
}
} else {
CheckErrorAlgorithm algorithm = CheckErrorAlgorithms.getAlgorithm(wiki, Integer.parseInt(algorithmNumber));
if (algorithm != null) {
if (!addition) {
algorithms.add(algorithm);
}
if (allAlgorithms != null) {
allAlgorithms.add(algorithm);
}
}
}
}
}
/**
* @param path Path to the dump file.
* @return Dump file.
*/
private File getDumpFile(String path) {
File file = new File(path);
if (file.exists() && file.isFile() && file.canRead()) {
return file;
}
File parent = file.getParentFile();
if ((parent == null) || (!parent.exists()) || (!parent.isDirectory())) {
return null;
}
final String filename = file.getName();
final int starIndex = filename.indexOf('$');
if (starIndex < 0) {
return null;
}
String[] filenames = parent.list(new FilenameFilter() {
@Override
public boolean accept(@SuppressWarnings("unused") File dir, String name) {
if (name.startsWith(filename.substring(0, starIndex)) &&
name.endsWith(filename.substring(starIndex + 1))) {
return true;
}
return false;
}
});
if (filenames.length == 0) {
return null;
}
Arrays.sort(filenames);
return new File(parent, filenames[filenames.length - 1]);
}
/**
* @param worker
* @see org.wikipediacleaner.gui.swing.basic.BasicWorkerListener#beforeStart(org.wikipediacleaner.gui.swing.basic.BasicWorker)
*/
@Override
public void beforeStart(BasicWorker worker) {
// Do nothing
}
/**
* @param worker
* @see org.wikipediacleaner.gui.swing.basic.BasicWorkerListener#afterStart(org.wikipediacleaner.gui.swing.basic.BasicWorker)
*/
@Override
public void afterStart(BasicWorker worker) {
// Do nothing
}
/**
* @param worker
* @see org.wikipediacleaner.gui.swing.basic.BasicWorkerListener#beforeFinished(org.wikipediacleaner.gui.swing.basic.BasicWorker)
*/
@Override
public void beforeFinished(BasicWorker worker) {
// Do nothing
}
/**
* @param worker
* @param ok
* @see org.wikipediacleaner.gui.swing.basic.BasicWorkerListener#afterFinished(org.wikipediacleaner.gui.swing.basic.BasicWorker, boolean)
*/
@Override
public void afterFinished(BasicWorker worker, boolean ok) {
if (!ok) {
System.exit(1);
}
if (loginDone) {
System.exit(0);
}
loginDone = true;
executeAction(actions);
}
}