diff --git a/.gitignore b/.gitignore index d4a3c328..7f9b38e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ +bin src/messenger/.idea/workspace.xml src/messenger/webim/install/package src/messenger/absent_* src/messenger/release* +src/mibewjava/.idea/workspace.xml +src/mibewjava/org.mibew.notifier/resources/ +mibew.ini .DS_Store diff --git a/README.md b/README.md new file mode 100644 index 00000000..2cee54c4 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +Mibew Messenger +=============== + +Mibew Messenger is an open-source live support application written +in PHP and MySQL. It enables one-on-one chat assistance in real-time +directly from your website. + +Server requirements +=================== + +1. A webserver or web hosting account running on any major Operating System +2. PHP (5.x and above) with MySQL support +3. MySQL 5.0 and above + +Terms of Use +============ + +Mibew Messenger is distributed under the terms of the Eclipse Public +License (or the General Public License, this means that you can choose +one of two, and use it accordingly) with the following special exception. + +License exception: +------------------ +No one may remove, alter or hide any copyright notices or links to the +community site (http://mibew.org or http://openwebim.org) contained +within the Program. Any derivative work must include this license exception. diff --git a/src/mibewjava/.idea/.name b/src/mibewjava/.idea/.name new file mode 100644 index 00000000..48d42c69 --- /dev/null +++ b/src/mibewjava/.idea/.name @@ -0,0 +1 @@ +mibew \ No newline at end of file diff --git a/src/mibewjava/.idea/ant.xml b/src/mibewjava/.idea/ant.xml new file mode 100644 index 00000000..2581ca3f --- /dev/null +++ b/src/mibewjava/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/mibewjava/.idea/compiler.xml b/src/mibewjava/.idea/compiler.xml new file mode 100644 index 00000000..e644c940 --- /dev/null +++ b/src/mibewjava/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/src/mibewjava/.idea/copyright/profiles_settings.xml b/src/mibewjava/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..3572571a --- /dev/null +++ b/src/mibewjava/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/mibewjava/.idea/encodings.xml b/src/mibewjava/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/src/mibewjava/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/mibewjava/.idea/inspectionProfiles/Project_Default.xml b/src/mibewjava/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..c66df003 --- /dev/null +++ b/src/mibewjava/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/src/mibewjava/.idea/inspectionProfiles/profiles_settings.xml b/src/mibewjava/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..3b312839 --- /dev/null +++ b/src/mibewjava/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/src/mibewjava/.idea/libraries/swt.xml b/src/mibewjava/.idea/libraries/swt.xml new file mode 100644 index 00000000..798fd500 --- /dev/null +++ b/src/mibewjava/.idea/libraries/swt.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/mibewjava/.idea/misc.xml b/src/mibewjava/.idea/misc.xml new file mode 100644 index 00000000..1c091f99 --- /dev/null +++ b/src/mibewjava/.idea/misc.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + diff --git a/src/mibewjava/.idea/modules.xml b/src/mibewjava/.idea/modules.xml new file mode 100644 index 00000000..852f03e3 --- /dev/null +++ b/src/mibewjava/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/mibewjava/.idea/runConfigurations/MibewTray.xml b/src/mibewjava/.idea/runConfigurations/MibewTray.xml new file mode 100644 index 00000000..efbaaaf6 --- /dev/null +++ b/src/mibewjava/.idea/runConfigurations/MibewTray.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/src/mibewjava/.idea/uiDesigner.xml b/src/mibewjava/.idea/uiDesigner.xml new file mode 100644 index 00000000..3b000203 --- /dev/null +++ b/src/mibewjava/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mibewjava/.idea/vcs.xml b/src/mibewjava/.idea/vcs.xml new file mode 100644 index 00000000..9ab281ac --- /dev/null +++ b/src/mibewjava/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/mibewjava/org.mibew.api/.classpath b/src/mibewjava/org.mibew.api/.classpath new file mode 100644 index 00000000..18d70f02 --- /dev/null +++ b/src/mibewjava/org.mibew.api/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/mibewjava/org.mibew.api/.project b/src/mibewjava/org.mibew.api/.project new file mode 100644 index 00000000..3197fa8e --- /dev/null +++ b/src/mibewjava/org.mibew.api/.project @@ -0,0 +1,17 @@ + + + org.mibew.api + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/src/mibewjava/org.mibew.api/org.mibew.api.iml b/src/mibewjava/org.mibew.api/org.mibew.api.iml new file mode 100644 index 00000000..79c37165 --- /dev/null +++ b/src/mibewjava/org.mibew.api/org.mibew.api.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgent.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgent.java new file mode 100644 index 00000000..87a1bcd5 --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgent.java @@ -0,0 +1,151 @@ +package org.mibew.api; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.security.NoSuchAlgorithmException; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; + +/** + * @author inspirer + */ +public class MibewAgent { + + private final MibewAgentOptions fOptions; + private final MibewAgentListener fListener; + private final MibewUpdateThread fThread; + private volatile boolean started; + + public MibewAgent(MibewAgentOptions options, MibewAgentListener listener) { + fOptions = options; + fListener = listener; + fThread = new MibewUpdateThread(); + started = false; + } + + public synchronized void launch() { + if(!started) { + fThread.start(); + started = true; + } + } + + public synchronized void stop() { + if(started) { + fThread.disconnect(); + started = false; + } + } + + public boolean isOnline() { + return fThread.isOnline(); + } + + protected void logError(String message, Throwable th) { + System.err.println(message); + } + + public MibewAgentOptions getOptions() { + return fOptions; + } + + private class MibewUpdateThread extends Thread { + + private volatile boolean fExiting; + private volatile boolean isOnline = false; + private final Object fSync = new Object(); + + public MibewUpdateThread() { + setName("Mibew Connection thread"); + fExiting = false; + } + + public void disconnect() { + synchronized (fSync) { + fExiting = true; + fSync.notifyAll(); + } + } + + @Override + public void run() { + while(!fExiting) { + try { + connectAndTrack(); + } catch(InterruptedException ex) { + /* ignore */ + } catch(Throwable th) { + logError(th.getMessage(), th); + } + } + setOnline(false); + } + + private void setOnline(boolean online) { + if(isOnline != online) { + isOnline = online; + fListener.onlineStateChanged(online); + } + } + + public boolean isOnline() { + return isOnline; + } + + private void connectAndTrack() throws InterruptedException, UnsupportedEncodingException, NoSuchAlgorithmException, MalformedURLException, ParserConfigurationException, SAXException { + setOnline(false); + MibewConnection conn = new MibewConnection(fOptions.getUrl(), fOptions.getLogin(), fOptions.getPassword()) { + @Override + protected void handleError(String message, Exception ex) { + logError(message, ex); + } + }; + if(!conn.connect()) { + logError("Wrong server, login or password.", null); + interruptableSleep(fOptions.getPollingInterval() * 3); + return; + } + final List createdThreads = new LinkedList(); + MibewTracker mt = new MibewTracker(conn, new MibewTrackerListener(){ + @Override + public void threadCreated(MibewThread thread) { + createdThreads.add(thread); + } + }); + long maxTime = System.currentTimeMillis() + fOptions.getConnectionRefreshTimeout()*1000; + + int errorsCount = 0; + while(!fExiting && (System.currentTimeMillis() < maxTime)) { + try { + createdThreads.clear(); + mt.update(); + fListener.updated(mt.getThreads(), createdThreads.toArray(new MibewThread[createdThreads.size()])); + errorsCount = 0; + setOnline(true); + } catch (Throwable th) { + setOnline(false); + errorsCount++; + logError("not updated", th); + interruptableSleep(errorsCount < 10 ? fOptions.getPollingInterval() / 2 : fOptions.getPollingInterval() * 2); + continue; + } + interruptableSleep(fOptions.getPollingInterval()); + } + + conn.disconnect(); + } + + private void interruptableSleep(long millis) throws InterruptedException { + synchronized (fSync ) { + if(fExiting) { + return; + } + fSync.wait(millis); + } + } + } +} diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentListener.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentListener.java new file mode 100644 index 00000000..78df236e --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentListener.java @@ -0,0 +1,10 @@ +package org.mibew.api; + +public abstract class MibewAgentListener { + + protected void onlineStateChanged(boolean isOnline) { + } + + protected void updated(MibewThread[] all, MibewThread[] created) { + } +} diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentOptions.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentOptions.java new file mode 100644 index 00000000..9470af0d --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentOptions.java @@ -0,0 +1,62 @@ +package org.mibew.api; + +import java.io.IOException; +import java.util.Properties; + +/** + * @author inspirer + */ +public class MibewAgentOptions { + + private String fUrl; + private String fLogin; + private String fPassword; + private int fConnectionRefreshTimeout = 900; // in seconds (15 minutes by default) + private int fPollingInterval = 2000; // 2 sec (in milliseconds) + + public MibewAgentOptions(String fUrl, String fLogin, String fPassword) { + super(); + this.fUrl = fUrl; + this.fLogin = fLogin; + this.fPassword = fPassword; + } + + public String getLogin() { + return fLogin; + } + + public String getPassword() { + return fPassword; + } + + public String getUrl() { + return fUrl; + } + + public int getConnectionRefreshTimeout() { + return fConnectionRefreshTimeout; + } + + public int getPollingInterval() { + return fPollingInterval; + } + + private static String getProperty(Properties p, String name, String defaultValue) throws IOException { + String result = p.getProperty(name); + if(result == null) { + if(defaultValue != null) { + return defaultValue; + } + throw new IOException("No '"+name+"' property"); + } + return result; + } + + public static MibewAgentOptions create(Properties p) throws IOException { + String url = getProperty(p, "mibew.host", null); + String login = getProperty(p, "mibew.login", null); + String password = getProperty(p, "mibew.password", null); + + return new MibewAgentOptions(url, login, password); + } +} diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewConnection.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewConnection.java similarity index 100% rename from src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewConnection.java rename to src/mibewjava/org.mibew.api/src/org/mibew/api/MibewConnection.java diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewResponse.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewResponse.java similarity index 100% rename from src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewResponse.java rename to src/mibewjava/org.mibew.api/src/org/mibew/api/MibewResponse.java diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewThread.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewThread.java new file mode 100644 index 00000000..5f3a8207 --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewThread.java @@ -0,0 +1,172 @@ +package org.mibew.api; + + +/** + * @author inspirer + */ +public class MibewThread implements Comparable { + + private final long fId; + private String fState; + private String fClientName = ""; + private String fAgent = ""; + private String fAddress = ""; + private String fFirstMessage = ""; + private boolean fCanOpen = false; + private boolean fCanView = false; + private boolean fCanBan = false; + private String fStateText; + private long fWaitingTime; + + public MibewThread(long id, String state) { + fId = id; + fState = state; + } + + public void updateFrom(MibewThread updated) { + if(fId != updated.fId) { + throw new IllegalArgumentException("different threads"); + } + fState = updated.fState; + fClientName = updated.fClientName; + fAgent = updated.fAgent; + fAddress = updated.fAddress; + fFirstMessage = updated.fFirstMessage; + fCanOpen = updated.fCanOpen; + fCanView = updated.fCanView; + fCanBan = updated.fCanBan; + fStateText = updated.fStateText; + fWaitingTime = updated.fWaitingTime; + } + + public long getId() { + return fId; + } + + public String getState() { + return fState; + } + + public String getStateText() { + return fStateText; + } + + public void setStateText(String stateText) { + fStateText = stateText; + } + + public String getAddress() { + return fAddress; + } + + public void setAddress(String address) { + fAddress = address; + } + + public String getAgent() { + return fAgent; + } + + public void setAgent(String agent) { + fAgent = agent; + } + + public String getClientName() { + return fClientName; + } + + public void setClientName(String clientName) { + fClientName = clientName; + } + + public String getFirstMessage() { + return fFirstMessage; + } + + public void setFirstMessage(String firstMessage) { + fFirstMessage = firstMessage; + } + + public boolean isCanBan() { + return fCanBan; + } + + public void setCanBan(boolean canBan) { + fCanBan = canBan; + } + + public boolean isCanOpen() { + return fCanOpen; + } + + public void setCanOpen(boolean canOpen) { + fCanOpen = canOpen; + } + + public boolean isCanView() { + return fCanView; + } + + public void setCanView(boolean canView) { + fCanView = canView; + } + + public long getWaitingTime() { + return fWaitingTime; + } + + public void setWaitingTime(long value) { + fWaitingTime = value; + } + + public int compareTo(MibewThread o) { + int res = index(this).compareTo(index(o)); + if(res != 0) { + return res; + } + return getClientName().compareTo(o.getClientName()); + } + + private Integer index(MibewThread th) { + if("prio".equals(th.getState())) { + return -1; + } + if("wait".equals(th.getState())) { + return 0; + } + return 1; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + boolean isChat = "chat".equals(getState()); + if(isChat) { + sb.append("(chat) "); + } + sb.append(getClientName()); + if(!isCanOpen() && isCanView()) { + sb.append(" (view only)"); + } + if(!isChat) { + sb.append(" - "); + sb.append(formatWaitingTime((System.currentTimeMillis() - getWaitingTime())/1000)); + } + return sb.toString(); + } + + private static String atLeast2(long i) { + return i < 10 ? "0" + i : Long.toString(i); + } + + private static String formatWaitingTime(long time) { + String s = atLeast2(time/60%60) + ":" + atLeast2(time%60); + if(time >= 3600) { + s = atLeast2(time/3600%24) + ":" + s; + if(time >= 24*3600) { + s = time/24/3600 + "d, " + s; + } + } + return s; + } +} diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTracker.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTracker.java new file mode 100644 index 00000000..8f48957e --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTracker.java @@ -0,0 +1,85 @@ +package org.mibew.api; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.mibew.api.handlers.UpdateHandler; +import org.xml.sax.SAXException; + +/** + * @author inspirer + */ +public class MibewTracker { + + private final MibewConnection fConnection; + private final MibewTrackerListener fListener; + private long fSince = 0; + private long fLastUpdate = 0; + + private final Map fThreads; + + public MibewTracker(MibewConnection conn, MibewTrackerListener listener) { + this.fConnection = conn; + this.fListener = listener; + this.fThreads = new HashMap(); + } + + public void update() throws IOException, SAXException, ParserConfigurationException { + MibewResponse response = fConnection.request("operator/update.php", "since=" + fSince); + SAXParser sp = SAXParserFactory.newInstance().newSAXParser(); + UpdateHandler handler = new UpdateHandler(); + sp.parse(new ByteArrayInputStream(response.getResponse()), handler); + handleResponse(response, handler); + } + + private void handleResponse(MibewResponse response, UpdateHandler handler) throws IOException { + if (handler.getResponse() == UpdateHandler.UPD_ERROR) { + throw new IOException("Update error: " + handler.getMessage()); + } else if (handler.getResponse() == UpdateHandler.UPD_SUCCESS) { + fSince = handler.getRevision(); + fLastUpdate = handler.getTime(); + List threads = handler.getThreads(); + if (threads != null && threads.size() > 0) { + processUpdate(threads); + } + } else { + throw new IOException("Update error: " + response.getResponseText()); + } + } + + private void processUpdate(List updated) { + for (MibewThread mt : updated) { + MibewThread existing = fThreads.get(mt.getId()); + boolean isClosed = mt.getState().equals("closed"); + if (existing == null) { + if (!isClosed) { + fThreads.put(mt.getId(), mt); + fListener.threadCreated(mt); + } + } else if (isClosed) { + fThreads.remove(mt.getId()); + fListener.threadClosed(existing); + } else { + existing.updateFrom(mt); + fListener.threadChanged(existing); + } + } + } + + public long getLastUpdate() { + return fLastUpdate; + } + + public MibewThread[] getThreads() { + Collection values = fThreads.values(); + return values.toArray(new MibewThread[values.size()]); + } +} diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewTrackerListener.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTrackerListener.java similarity index 100% rename from src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewTrackerListener.java rename to src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTrackerListener.java diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/Utils.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/Utils.java similarity index 99% rename from src/mibewjava/org.mibew.jabber/src/org/mibew/api/Utils.java rename to src/mibewjava/org.mibew.api/src/org/mibew/api/Utils.java index bf79cb7f..ba8595d0 100644 --- a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/Utils.java +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/Utils.java @@ -26,6 +26,4 @@ public class Utils { } return sb.toString(); } - - } diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/handlers/LoginHandler.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/handlers/LoginHandler.java similarity index 100% rename from src/mibewjava/org.mibew.jabber/src/org/mibew/api/handlers/LoginHandler.java rename to src/mibewjava/org.mibew.api/src/org/mibew/api/handlers/LoginHandler.java diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/handlers/UpdateHandler.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/handlers/UpdateHandler.java similarity index 51% rename from src/mibewjava/org.mibew.jabber/src/org/mibew/api/handlers/UpdateHandler.java rename to src/mibewjava/org.mibew.api/src/org/mibew/api/handlers/UpdateHandler.java index 58dc8b44..397327a3 100644 --- a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/handlers/UpdateHandler.java +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/handlers/UpdateHandler.java @@ -15,14 +15,18 @@ import org.xml.sax.helpers.DefaultHandler; public class UpdateHandler extends DefaultHandler { public static final int UPD_ERROR = 1; - public static final int UPD_THREADS = 2; + public static final int UPD_SUCCESS = 2; + + private static final int STATE_READING_THREADS = 1; private int fResponse = 0; private String fMessage = ""; private long fRevision; private long fTime; private List fUpdated; - + + private int state = 0; + private Stack fPath = new Stack(); private MibewThread fCurrentThread; @@ -33,27 +37,34 @@ public class UpdateHandler extends DefaultHandler { if (fPath.size() == 0) { if (name.equals("error")) { fResponse = UPD_ERROR; - } else if (name.equals("threads")) { - fResponse = UPD_THREADS; - fTime = Long.parseLong(attributes.getValue("time")); - fRevision = Long.parseLong(attributes.getValue("revision")); + } else if (name.equals("update")) { + fResponse = UPD_SUCCESS; } else { throw new SAXException("unknown root element: " + name); } - } - if (fResponse == UPD_THREADS && fPath.size() == 1 - && name.equals("thread")) { - long id = Long.parseLong(attributes.getValue("id")); - String stateid = attributes.getValue("stateid"); - fCurrentThread = new MibewThread(id, stateid); - - if(!stateid.equals("closed")) { - fCurrentThread.fStateText = attributes.getValue("state"); - fCurrentThread.fCanOpen = booleanAttribute(attributes.getValue("canopen")); - fCurrentThread.fCanView = booleanAttribute(attributes.getValue("canview")); - fCurrentThread.fCanBan = booleanAttribute(attributes.getValue("canban")); + } else if(fResponse == UPD_SUCCESS) { + if(fPath.size() == 1) { + if (name.equals("threads")) { + fTime = Long.parseLong(attributes.getValue("time")); + fRevision = Long.parseLong(attributes.getValue("revision")); + fUpdated = new ArrayList(); + state = STATE_READING_THREADS; + } + /* ignore others for compatibility reasons */ + } + if (fPath.size() == 2 && state == STATE_READING_THREADS && name.equals("thread")) { + long id = Long.parseLong(attributes.getValue("id")); + String stateid = attributes.getValue("stateid"); + fCurrentThread = new MibewThread(id, stateid); + + if(!stateid.equals("closed")) { + fCurrentThread.setStateText(attributes.getValue("state")); + fCurrentThread.setCanOpen(booleanAttribute(attributes.getValue("canopen"))); + fCurrentThread.setCanView(booleanAttribute(attributes.getValue("canview"))); + fCurrentThread.setCanBan(booleanAttribute(attributes.getValue("canban"))); + } + } - } } catch (NumberFormatException ex) { throw new SAXException(ex.getMessage()); @@ -68,17 +79,23 @@ public class UpdateHandler extends DefaultHandler { return false; } + private long longValue(String value) throws SAXException { + try { + return Long.parseLong(value); + } catch(NumberFormatException ex) { + throw new SAXException(ex); + } + } + @Override public void endElement(String uri, String localName, String name) throws SAXException { fPath.pop(); - if (fResponse == UPD_THREADS && fPath.size() == 1 - && name.equals("thread")) { - if(fUpdated == null) { - fUpdated = new ArrayList(); - } + if (fResponse == UPD_SUCCESS && fPath.size() == 2 && state == STATE_READING_THREADS && name.equals("thread")) { fUpdated.add(fCurrentThread); fCurrentThread = null; + } else if(fPath.size() == 1 && state == STATE_READING_THREADS) { + state = 0; } } @@ -91,21 +108,26 @@ public class UpdateHandler extends DefaultHandler { throw new SAXException("unexpected characters"); } fMessage += new String(ch, start, length); - } else if (fResponse == UPD_THREADS) { - if(fCurrentThread == null || fPath.size() != 3) { + } else if (fResponse == UPD_SUCCESS && fCurrentThread != null) { + if(fCurrentThread == null || fPath.size() != 4) { throw new SAXException("unknown characters"); } String subvar = fPath.peek(); String value = new String(ch, start, length); if("name".equals(subvar)) { - fCurrentThread.fClientName += value; + fCurrentThread.setClientName(fCurrentThread.getClientName() + value); } else if("addr".equals(subvar)) { - fCurrentThread.fAddress += value; + fCurrentThread.setAddress(fCurrentThread.getAddress() + value); } else if("message".equals(subvar)) { - fCurrentThread.fFirstMessage += value; + fCurrentThread.setFirstMessage(fCurrentThread.getFirstMessage() + value); } else if("agent".equals(subvar)) { - fCurrentThread.fAgent += value; + fCurrentThread.setAgent(fCurrentThread.getAgent() + value); + } else if("modified".equals(subvar)) { + if(fCurrentThread.getWaitingTime() != 0) { + throw new SAXException("error: waiting time is already set"); + } + fCurrentThread.setWaitingTime(longValue(value) - fTime + System.currentTimeMillis()); } // TODO diff --git a/src/mibewjava/org.mibew.jabber/.classpath b/src/mibewjava/org.mibew.jabber/.classpath index 4257a5dc..89790263 100644 --- a/src/mibewjava/org.mibew.jabber/.classpath +++ b/src/mibewjava/org.mibew.jabber/.classpath @@ -4,5 +4,6 @@ + diff --git a/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/Info.plist b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/Info.plist new file mode 100644 index 00000000..11b4d738 --- /dev/null +++ b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleName + Mibew Notifier + CFBundleIdentifier + org.mibew.notifier + CFBundleVersion + 100.0 + CFBundleAllowMixedLocalizations + true + CFBundleExecutable + MibewNotifier + CFBundleDevelopmentRegion + English + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleGetInfoString + Mibew Notifier 1.0, build 17 Jan, 2010 + CFBundleInfoDictionaryVersion + 6.0 + CFBundleIconFile + mibew.icns + Java + + WorkingDirectory + $APP_PACKAGE/Contents/Resources/Java + VMOptions + -Xms16mm + MainClass + org.mibew.trayapp.NotifyApp + JVMVersion + 1.6+ + ClassPath + + $JAVAROOT/org.mibew.notifier.jar + $JAVAROOT/smackx.jar + $JAVAROOT/smackx-jingle.jar + $JAVAROOT/smackx-debug.jar + $JAVAROOT/smack.jar + + + + diff --git a/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/MacOS/MibewNotifier b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/MacOS/MibewNotifier new file mode 100755 index 00000000..7035592f Binary files /dev/null and b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/MacOS/MibewNotifier differ diff --git a/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/PkgInfo b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/PkgInfo new file mode 100644 index 00000000..bd04210f --- /dev/null +++ b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/Resources/mibew.icns b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/Resources/mibew.icns new file mode 100644 index 00000000..c9a253d6 Binary files /dev/null and b/src/mibewjava/org.mibew.jabber/resources/Mibew Notifier.app/Contents/Resources/mibew.icns differ diff --git a/src/mibewjava/org.mibew.jabber/resources/build.xml b/src/mibewjava/org.mibew.jabber/resources/build.xml new file mode 100644 index 00000000..d9312466 --- /dev/null +++ b/src/mibewjava/org.mibew.jabber/resources/build.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mibewjava/org.mibew.jabber/resources/images/mibew.gif b/src/mibewjava/org.mibew.jabber/resources/images/mibew.gif new file mode 100644 index 00000000..a78219c4 Binary files /dev/null and b/src/mibewjava/org.mibew.jabber/resources/images/mibew.gif differ diff --git a/src/mibewjava/org.mibew.jabber/resources/packdmg.sh b/src/mibewjava/org.mibew.jabber/resources/packdmg.sh new file mode 100755 index 00000000..f9b4da50 --- /dev/null +++ b/src/mibewjava/org.mibew.jabber/resources/packdmg.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +rm -rf *.dmg +hdiutil create mibew-notifier-temp.dmg -volname "Mibew Notifier 1.0" -fs HFS+ -srcfolder "Mibew Notifier.app" +hdiutil convert "mibew-notifier-temp.dmg" -format UDZO -imagekey zlib-level=9 -o "mibew-1.0.0.dmg" +rm mibew-notifier-temp.dmg diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewThread.java b/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewThread.java deleted file mode 100644 index f9d31280..00000000 --- a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewThread.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.mibew.api; - -/** - * @author inspirer - */ -public class MibewThread { - - public final long fId; - public String fState; - public String fClientName = ""; - public String fAgent = ""; - public String fAddress = ""; - public String fFirstMessage = ""; - public boolean fCanOpen = false; - public boolean fCanView = false; - public boolean fCanBan = false; - public String fStateText; - - public MibewThread(long id, String state) { - fId = id; - fState = state; - } - - public void updateFrom(MibewThread updated) { - if(fId != updated.fId) { - throw new IllegalArgumentException("different threads"); - } - fState = updated.fState; - fClientName = updated.fClientName; - fAgent = updated.fAgent; - fAddress = updated.fAddress; - fFirstMessage = updated.fFirstMessage; - fCanOpen = updated.fCanOpen; - fCanView = updated.fCanView; - fCanBan = updated.fCanBan; - fStateText = updated.fStateText; - } -} diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewTracker.java b/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewTracker.java deleted file mode 100644 index 96aa3188..00000000 --- a/src/mibewjava/org.mibew.jabber/src/org/mibew/api/MibewTracker.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.mibew.api; - -import java.io.ByteArrayInputStream; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.mibew.api.handlers.UpdateHandler; - -/** - * @author inspirer - */ -public class MibewTracker { - - private final MibewConnection fConnection; - private final MibewTrackerListener fListener; - private long fSince = 0; - private long fLastUpdate = 0; - - private final Map fThreads; - - public MibewTracker(MibewConnection conn, MibewTrackerListener listener) { - this.fConnection = conn; - this.fListener = listener; - this.fThreads = new HashMap(); - } - - public void track() throws InterruptedException { - for(int i = 0; i < 5; i++) { - try { - MibewResponse response = fConnection.request("operator/update.php", "since="+fSince); - SAXParser sp = SAXParserFactory.newInstance().newSAXParser(); - UpdateHandler handler = new UpdateHandler(); - sp.parse(new ByteArrayInputStream(response.getResponse()), handler); - handleResponse(response, handler); - } catch(Exception e) { - System.err.println("update exception: " + e.getMessage()); - } - Thread.sleep(1000); - } - } - - private void handleResponse(MibewResponse response, UpdateHandler handler) { - if(handler.getResponse() == UpdateHandler.UPD_ERROR) { - System.out.println("Update error: " + handler.getMessage()); - } else if(handler.getResponse() == UpdateHandler.UPD_THREADS) { - System.out.println("Updated.... " + handler.getRevision()); - fSince = handler.getRevision(); - fLastUpdate = handler.getTime(); - List threads = handler.getThreads(); - if(threads != null && threads.size() > 0) { - processUpdate(threads); - } - } else { - System.out.println("Update error"); - System.out.println(response.getResponseText()); - } - } - - private void processUpdate(List updated) { - for(MibewThread mt : updated) { - MibewThread existing = fThreads.get(mt.fId); - boolean isClosed = mt.fState.equals("closed"); - if(existing == null) { - if(!isClosed) { - fThreads.put(mt.fId, mt); - fListener.threadCreated(mt); - } - } else if(isClosed) { - fThreads.remove(mt.fId); - fListener.threadClosed(existing); - } else { - existing.updateFrom(mt); - fListener.threadChanged(existing); - } - } - } - - public long getLastUpdate() { - return fLastUpdate; - } -} diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java b/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java index 961c3970..8733ddbe 100644 --- a/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java +++ b/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java @@ -39,7 +39,7 @@ public class Application { } }); - MibewConnection conn = new MibewConnection("http://localhost:8080/webim/", "admin", ""); + MibewConnection conn = new MibewConnection("http://localhost:8080/webim/", "admin", "1"); if(!conn.connect()) { System.err.println("Wrong server, login or password."); return; @@ -49,14 +49,14 @@ public class Application { @Override public void threadCreated(MibewThread thread) { try { - chat.sendMessage(thread.fId + ": " + thread.fAddress + " " + thread.fClientName); + chat.sendMessage(thread.getId() + ": " + thread.getAddress() + " " + thread.getClientName()); } catch (XMPPException e) { e.printStackTrace(); } } }); - mt.track(); + //mt.track(); connection.disconnect(); } diff --git a/src/mibewjava/org.mibew.notifier/.classpath b/src/mibewjava/org.mibew.notifier/.classpath new file mode 100644 index 00000000..78fdd7f0 --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/mibewjava/org.mibew.notifier/.project b/src/mibewjava/org.mibew.notifier/.project new file mode 100644 index 00000000..4a130331 --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/.project @@ -0,0 +1,17 @@ + + + org.mibew.notifier + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/src/mibewjava/org.mibew.notifier/libs/src.zip b/src/mibewjava/org.mibew.notifier/libs/src.zip new file mode 100644 index 00000000..708c8d33 Binary files /dev/null and b/src/mibewjava/org.mibew.notifier/libs/src.zip differ diff --git a/src/mibewjava/org.mibew.notifier/libs/swt-debug.jar b/src/mibewjava/org.mibew.notifier/libs/swt-debug.jar new file mode 100644 index 00000000..a369b688 Binary files /dev/null and b/src/mibewjava/org.mibew.notifier/libs/swt-debug.jar differ diff --git a/src/mibewjava/org.mibew.notifier/libs/swt.jar b/src/mibewjava/org.mibew.notifier/libs/swt.jar new file mode 100644 index 00000000..9a326dfc Binary files /dev/null and b/src/mibewjava/org.mibew.notifier/libs/swt.jar differ diff --git a/src/mibewjava/org.mibew.notifier/org.mibew.notifier.iml b/src/mibewjava/org.mibew.notifier/org.mibew.notifier.iml new file mode 100644 index 00000000..5efe060c --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/org.mibew.notifier.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/mibewjava/org.mibew.notifier/src/mibew.ini b/src/mibewjava/org.mibew.notifier/src/mibew.ini new file mode 100644 index 00000000..3564fbaa --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/src/mibew.ini @@ -0,0 +1,5 @@ +# Mibew parameters + +mibew.host=http://localhost:8080/webim/ +mibew.login=admin +mibew.password= diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/BrowserUtil.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/BrowserUtil.java new file mode 100644 index 00000000..6ee074bf --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/BrowserUtil.java @@ -0,0 +1,42 @@ +package org.mibew.notifier; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Arrays; + +public class BrowserUtil { + + static final String[] browsers = { "firefox", "opera", "konqueror", "epiphany", "seamonkey", "galeon", + "kazehakase", "mozilla", "netscape" }; + + /** + * Bare Bones Browser Launch + * Version 2.0 (May 26, 2009) + * By Dem Pilafian + * @param url + */ + public static void openURL(String url) throws IOException { + String osName = System.getProperty("os.name"); + try { + if (osName.startsWith("Mac OS")) { + Class fileMgr = Class.forName("com.apple.eio.FileManager"); + Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class }); + openURL.invoke(null, new Object[] { url }); + } else if (osName.startsWith("Windows")) { + Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url); + } else { // assume Unix or Linux + boolean found = false; + for (String browser : browsers) + if (!found) { + found = Runtime.getRuntime().exec(new String[] { "which", browser }).waitFor() == 0; + if (found) + Runtime.getRuntime().exec(new String[] { browser, url }); + } + if (!found) + throw new Exception(Arrays.toString(browsers)); + } + } catch (Throwable th) { + throw new IOException("Error attempting to launch web browser\n" + th.toString()); + } + } +} \ No newline at end of file diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/ConsoleApp.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/ConsoleApp.java new file mode 100644 index 00000000..005b52e7 --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/ConsoleApp.java @@ -0,0 +1,28 @@ +package org.mibew.notifier; + +import org.mibew.api.MibewAgent; +import org.mibew.api.MibewAgentListener; + +public class ConsoleApp { + + public static void main(String[] args) { + Options options = new Options(args); + if(!options.load()) { + return; + } + + MibewAgent agent = new MibewAgent(options.getAgentOptions(), new MibewAgentListener() { + @Override + protected void onlineStateChanged(boolean isOnline) { + System.out.println("now " + (isOnline ? "online" : "offline")); + } + }); + agent.launch(); + try { + Thread.sleep(3500); + } catch (InterruptedException e) { + } + + agent.stop(); + } +} diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/MibewTray.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/MibewTray.java new file mode 100644 index 00000000..bd408425 --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/MibewTray.java @@ -0,0 +1,140 @@ +package org.mibew.notifier; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.*; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.mibew.api.MibewAgent; +import org.mibew.api.MibewAgentListener; +import org.mibew.api.MibewThread; + +import java.awt.*; +import java.io.IOException; + +public class MibewTray extends MibewAgentListener { + + private volatile boolean isStopped = false; + + private Image fImageOn; + private Image fImageOff; + private TrayItem fItem; + private Menu fMenu; + private MibewAgent fAgent; + + void initTray(Display display, Shell shell, MibewAgent agent) { + fAgent = agent; + fImageOn = new Image(display, getClass().getClassLoader().getResourceAsStream("org/mibew/notifier/tray_on.png")); + fImageOff = new Image(display, getClass().getClassLoader().getResourceAsStream("org/mibew/notifier/tray_off.png")); + + final Tray tray = display.getSystemTray(); + if (tray == null) { + System.out.println("The system tray is not available"); + } else { + fItem = new TrayItem(tray, SWT.NONE); + fItem.setToolTipText("SWT TrayItem"); + fItem.addListener(SWT.Show, new Listener() { + public void handleEvent(Event event) { + System.out.println("show"); + } + }); + fItem.addListener(SWT.Hide, new Listener() { + public void handleEvent(Event event) { + System.out.println("hide"); + } + }); + fMenu = new Menu(shell, SWT.POP_UP); + for (int i = 0; i < 8; i++) { + MenuItem mi = new MenuItem(fMenu, SWT.PUSH); + mi.setText("Item" + i); + mi.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + System.out.println("selection " + event.widget); + } + }); + } + Listener listener = new Listener() { + public void handleEvent(Event event) { + fMenu.setVisible(true); + } + }; + fItem.addListener(SWT.MenuDetect, listener); + fItem.addListener(SWT.Selection, listener); + fItem.setImage(fImageOff); + } + shell.setBounds(50, 50, 300, 200); + //shell.open(); + } + + @Override + protected synchronized void onlineStateChanged(final boolean isOnline) { + if(isStopped) + return; + + Display.getDefault().asyncExec(new Runnable() { + public void run() { + if(isStopped) + return; + + fItem.setImage(isOnline ? fImageOn : fImageOff); + } + }); + } + + @Override + protected synchronized void updated(final MibewThread[] all, final MibewThread[] created) { + if(isStopped) + return; + + Display.getDefault().asyncExec(new Runnable() { + public void run() { + if(isStopped) + return; + + for (MenuItem menuItem : fMenu.getItems()) { + menuItem.dispose(); + } + for(MibewThread m : all) { + MenuItem mi = new MenuItem(fMenu, SWT.PUSH); + mi.setText(m.getClientName()); + mi.addListener(SWT.Selection, new LinkActionListener(null, fAgent.getOptions().getUrl() + "operator/agent.php?thread=" + m.getId())); + } + + if(created.length == 1) { + fItem.setToolTipText(created[0].getClientName() + "\n" + created[0].getFirstMessage()); + } else if(created.length > 1) { + fItem.setToolTipText("New " + created.length + " visitors"); + } + + } + }); + } + + synchronized void dispose() { + isStopped = true; + fItem.dispose(); + fImageOn.dispose(); + fImageOff.dispose(); + } + + private static class LinkActionListener implements Listener { + private final Shell shell; + private final String link; + + public LinkActionListener(Shell shell, String link) { + this.shell = shell; + this.link = link; + } + + public void handleEvent(Event event) { + try { + BrowserUtil.openURL(link); + } catch (IOException e1) { + MessageBox messageBox = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR); + messageBox.setText("Browser error"); //$NON-NLS-1$ + messageBox.setMessage(e1.getMessage()); + messageBox.open(); + } + } + }} diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/NotifyApp.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/NotifyApp.java new file mode 100644 index 00000000..ece7777d --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/NotifyApp.java @@ -0,0 +1,34 @@ +package org.mibew.notifier; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.mibew.api.MibewAgent; +import org.mibew.notifier.Options.JOptions; + +public class NotifyApp { + + public static void main(String[] args) { + Display display = new Display(); + Shell shell = new Shell(display); + + Options options = new JOptions(shell, args); + if (!options.load()) { + return; + } + + MibewTray tray = new MibewTray(); + MibewAgent agent = new MibewAgent(options.getAgentOptions(), tray); + agent.launch(); + + tray.initTray(display, shell, agent); + + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + tray.dispose(); + agent.stop(); + display.dispose(); + System.exit(0); + } +} diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/Options.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/Options.java new file mode 100644 index 00000000..a190c98d --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/Options.java @@ -0,0 +1,62 @@ +package org.mibew.notifier; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.mibew.api.MibewAgentOptions; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class Options { + + private MibewAgentOptions agentOptions; + private Properties myProperties; + + public Options(String[] args) { + } + + public boolean load() { + try { + InputStream is = getClass().getClassLoader().getResourceAsStream("mibew.ini"); + if (is != null) { + myProperties = new Properties(); + myProperties.load(is); + agentOptions = MibewAgentOptions.create(myProperties); + return true; + } else { + handleError("cannot find mibew.ini"); + } + } catch (IOException e) { + handleError(e.getMessage()); + } + return false; + } + + protected void handleError(String message) { + System.err.println(message); + } + + public MibewAgentOptions getAgentOptions() { + return agentOptions; + } + + public static class JOptions extends Options { + + private final Shell fShell; + + public JOptions(Shell shell, String[] args) { + super(args); + fShell = shell; + } + + @Override + protected void handleError(final String message) { + MessageBox messageBox = new MessageBox(fShell, SWT.OK | SWT.ICON_ERROR); + messageBox.setText("Options error"); //$NON-NLS-1$ + messageBox.setMessage(message); + messageBox.open(); + } + } +} diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_off.png b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_off.png new file mode 100644 index 00000000..daf8251b Binary files /dev/null and b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_off.png differ diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_on.png b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_on.png new file mode 100644 index 00000000..1e8f871a Binary files /dev/null and b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_on.png differ