aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build.xml12
-rw-r--r--lib/felix.client.run.properties1
-rw-r--r--resources/install/build.xml2
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/login/LoginManager.java45
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java33
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/NetworkConfigurationWatcher.java313
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java8
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/EventManager.java28
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/OperationSetTypingNotificationsMsnImpl.java19
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java47
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java22
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java38
-rw-r--r--src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java581
-rw-r--r--src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf17
-rw-r--r--src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java17
-rw-r--r--src/net/java/sip/communicator/service/netaddr/event/ChangeEvent.java100
-rw-r--r--src/net/java/sip/communicator/service/netaddr/event/NetworkConfigurationChangeListener.java22
18 files changed, 1261 insertions, 45 deletions
diff --git a/build.xml b/build.xml
index 2b2cc7f..fde9b4e 100644
--- a/build.xml
+++ b/build.xml
@@ -909,7 +909,7 @@
bundle-filehistory,bundle-metahistory,bundle-metahistory-slick,
bundle-plugin-facebookaccregwizz,
bundle-bouncycastle,bundle-plugin-otr,bundle-plugin-iptelaccregwizz,
- bundle-contactsource"/>
+ bundle-contactsource,bundle-plugin-reconnect"/>
<!--BUNDLE-SC-LAUNCHER-->
<target name="bundle-sc-launcher">
@@ -2325,4 +2325,14 @@ org.apache.http.util"/>
prefix="net/java/sip/communicator/service/contactsource"/>
</jar>
</target>
+
+ <!-- BUNDLE-PLUGIN-RECONNECT -->
+ <target name="bundle-plugin-reconnect">
+ <!-- Creates a bundle for the reconnect plugin.-->
+ <jar compress="false" destfile="${bundles.dest}/reconnectplugin.jar"
+ manifest="${src}/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf">
+ <zipfileset dir="${dest}/net/java/sip/communicator/plugin/reconnectplugin"
+ prefix="net/java/sip/communicator/plugin/reconnectplugin"/>
+ </jar>
+ </target>
</project>
diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties
index d7232ad..442d318 100644
--- a/lib/felix.client.run.properties
+++ b/lib/felix.client.run.properties
@@ -76,6 +76,7 @@ felix.auto.start.52= \
reference:file:sc-bundles/protocol-gibberish.jar \
reference:file:sc-bundles/protocol-ssh.jar \
reference:file:sc-bundles/netaddr.jar \
+ reference:file:sc-bundles/reconnectplugin.jar \
reference:file:sc-bundles/protocol-zeroconf.jar \
reference:file:sc-bundles/protocol-irc.jar \
reference:file:sc-bundles/protocol-dict.jar
diff --git a/resources/install/build.xml b/resources/install/build.xml
index 0378232..f587091 100644
--- a/resources/install/build.xml
+++ b/resources/install/build.xml
@@ -401,7 +401,7 @@
<entry key="last_version" value="${sip-communicator.version}" />
<entry key="download_link"
value="http://download.sip-communicator.org/nightly/windows/${package.name}-${sip-communicator.version}.exe" />
- <entry key="changes_html" value="changes.html" />
+ <entry key="changes_html" value="updates/index.html" />
</propertyfile>
<!--
diff --git a/src/net/java/sip/communicator/impl/gui/main/login/LoginManager.java b/src/net/java/sip/communicator/impl/gui/main/login/LoginManager.java
index 78a199c..412a91e 100644
--- a/src/net/java/sip/communicator/impl/gui/main/login/LoginManager.java
+++ b/src/net/java/sip/communicator/impl/gui/main/login/LoginManager.java
@@ -190,28 +190,29 @@ public class LoginManager
logger.trace(evt.getReason());
}
- else if (newState.equals(RegistrationState.CONNECTION_FAILED))
- {
- String msgText = GuiActivator.getResources().getI18NString(
- "service.gui.CONNECTION_FAILED_MSG",
- new String[]
- { accountID.getUserID(),
- accountID.getService() });
-
- int result = new MessageDialog(
- null,
- GuiActivator.getResources().getI18NString("service.gui.ERROR"),
- msgText,
- GuiActivator.getResources().getI18NString("service.gui.RETRY"),
- false).showDialog();
-
- if (result == MessageDialog.OK_RETURN_CODE)
- {
- this.login(protocolProvider);
- }
-
- logger.trace(evt.getReason());
- }
+// CONNECTION_FAILED events are now dispatched in reconnect plugin
+// else if (newState.equals(RegistrationState.CONNECTION_FAILED))
+// {
+// String msgText = GuiActivator.getResources().getI18NString(
+// "service.gui.CONNECTION_FAILED_MSG",
+// new String[]
+// { accountID.getUserID(),
+// accountID.getService() });
+//
+// int result = new MessageDialog(
+// null,
+// GuiActivator.getResources().getI18NString("service.gui.ERROR"),
+// msgText,
+// GuiActivator.getResources().getI18NString("service.gui.RETRY"),
+// false).showDialog();
+//
+// if (result == MessageDialog.OK_RETURN_CODE)
+// {
+// this.login(protocolProvider);
+// }
+//
+// logger.trace(evt.getReason());
+// }
else if (newState.equals(RegistrationState.EXPIRED))
{
String msgText = GuiActivator.getResources().getI18NString(
diff --git a/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java b/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
index 9b67a47..79f9dd9 100644
--- a/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
@@ -13,6 +13,7 @@ import java.beans.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.netaddr.event.*;
import net.java.sip.communicator.util.*;
import net.java.stun4j.*;
import net.java.stun4j.client.*;
@@ -115,6 +116,11 @@ public class NetworkAddressManagerServiceImpl
*/
public static final int DEFAULT_STUN_SERVER_PORT = 3478;
+ /**
+ * A thread which periodically scans network interfaces and reports
+ * changes in network configuration.
+ */
+ private NetworkConfigurationWatcher networkConfigurationWatcher = null;
/**
* Initializes this network address manager service implementation and
@@ -221,6 +227,8 @@ public class NetworkAddressManagerServiceImpl
configurationService
.removeVetoableChangeListener( PROP_STUN_SERVER_PORT, this);
+ if(networkConfigurationWatcher != null)
+ networkConfigurationWatcher.stop();
}
finally
{
@@ -808,5 +816,30 @@ public class NetworkAddressManagerServiceImpl
+ minPort + " and " + (port -1));
}
+ /**
+ * Adds new <tt>NetworkConfigurationChangeListener</tt> which will
+ * be informed for network configuration changes.
+ * @param listener the listener.
+ */
+ public void addNetworkConfigurationChangeListener(
+ NetworkConfigurationChangeListener listener)
+ {
+ if(networkConfigurationWatcher == null)
+ networkConfigurationWatcher = new NetworkConfigurationWatcher();
+ networkConfigurationWatcher
+ .addNetworkConfigurationChangeListener(listener);
+ }
+
+ /**
+ * Remove <tt>NetworkConfigurationChangeListener</tt>.
+ * @param listener the listener.
+ */
+ public void removeNetworkConfigurationChangeListener(
+ NetworkConfigurationChangeListener listener)
+ {
+ if(networkConfigurationWatcher != null)
+ networkConfigurationWatcher
+ .removeNetworkConfigurationChangeListener(listener);
+ }
}
diff --git a/src/net/java/sip/communicator/impl/netaddr/NetworkConfigurationWatcher.java b/src/net/java/sip/communicator/impl/netaddr/NetworkConfigurationWatcher.java
new file mode 100644
index 0000000..d071fc8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/netaddr/NetworkConfigurationWatcher.java
@@ -0,0 +1,313 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.netaddr;
+
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+import net.java.sip.communicator.service.netaddr.event.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Periodically checks the current network interfaces to track changes
+ * and fire events on those changes.
+ *
+ * @author Damian Minkov
+ */
+public class NetworkConfigurationWatcher
+ implements Runnable
+{
+ /**
+ * Our class logger.
+ */
+ private static Logger logger =
+ Logger.getLogger(NetworkConfigurationWatcher.class);
+
+ /**
+ * Interval between check of network configuration.
+ */
+ private static final int CHECK_INTERVAL = 3000; // 3 sec.
+
+ /**
+ * Listers for network configuration changes.
+ */
+ private final List<NetworkConfigurationChangeListener> listeners =
+ new ArrayList<NetworkConfigurationChangeListener>();
+
+ /**
+ * Whether current thread is running.
+ */
+ private boolean isRunning = false;
+
+ /**
+ * Adds new <tt>NetworkConfigurationChangeListener</tt> which will
+ * be informed for network configuration changes.
+ * @param listener the listener.
+ */
+ void addNetworkConfigurationChangeListener(
+ NetworkConfigurationChangeListener listener)
+ {
+ synchronized(listeners)
+ {
+ listeners.add(listener);
+ }
+
+ if(!isRunning)
+ {
+ isRunning = true;
+ new Thread(this).start();
+ }
+ }
+
+ /**
+ * Remove <tt>NetworkConfigurationChangeListener</tt>.
+ * @param listener the listener.
+ */
+ void removeNetworkConfigurationChangeListener(
+ NetworkConfigurationChangeListener listener)
+ {
+ synchronized(listeners)
+ {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Main loop of this thread.
+ */
+ public void run()
+ {
+ long last = 0;
+ boolean isAfterStandby = false;
+
+ List<NetworkInterface> activeInterfaces =
+ new ArrayList<NetworkInterface>();
+
+ while(isRunning)
+ {
+ long curr = System.currentTimeMillis();
+
+ if(!isAfterStandby && last != 0)
+ isAfterStandby = (last + CHECK_INTERVAL + 100 - curr) < 0;
+
+ try
+ {
+ Enumeration<NetworkInterface> e =
+ NetworkInterface.getNetworkInterfaces();
+
+ boolean networkIsUP = activeInterfaces.size() > 0;
+
+ List<NetworkInterface> currentActiveInterfaces =
+ new ArrayList<NetworkInterface>();
+
+ while (e.hasMoreElements())
+ {
+ NetworkInterface networkInterface = e.nextElement();
+
+ if(isInterfaceLoopback(networkInterface))
+ continue;
+
+ // if interface is up and has some valid(non-local) address
+ if(isInterfaceUp(networkInterface)
+ && hasValidAddress(networkInterface))
+ {
+ currentActiveInterfaces.add(networkInterface);
+ }
+ }
+
+ List<NetworkInterface> inactiveActiveInterfaces =
+ new ArrayList<NetworkInterface>(activeInterfaces);
+ inactiveActiveInterfaces.removeAll(currentActiveInterfaces);
+
+ // fire that interface has gone down
+ for (int i = 0; i < inactiveActiveInterfaces.size(); i++)
+ {
+ NetworkInterface iface = inactiveActiveInterfaces.get(i);
+
+ if(!containsInterfaceWithName(
+ currentActiveInterfaces, iface.getName()))
+ {
+ fireChangeEvent(new ChangeEvent(iface,
+ ChangeEvent.IFACE_DOWN, isAfterStandby));
+
+ activeInterfaces.remove(iface);
+ }
+ }
+
+ // now we leave with only with the new and up interfaces
+ // in currentActiveInterfaces list
+ currentActiveInterfaces.removeAll(activeInterfaces);
+
+ // fire that interface has gone up
+ for (int i = 0; i < currentActiveInterfaces.size(); i++)
+ {
+ NetworkInterface iface = currentActiveInterfaces.get(i);
+
+ fireChangeEvent(new ChangeEvent(iface,
+ ChangeEvent.IFACE_UP, isAfterStandby));
+ activeInterfaces.add(iface);
+ }
+
+ // fire that network has gone up
+ if(!networkIsUP && activeInterfaces.size() > 0)
+ {
+ isAfterStandby = false;
+ }
+
+ last = curr;
+ } catch (SocketException e)
+ {
+ logger.error("Error checking network interfaces", e);
+ }
+
+ synchronized(this)
+ {
+ try{
+ wait(CHECK_INTERVAL);
+ }
+ catch (Exception e){}
+ }
+ }
+ }
+
+ /**
+ * Fire ChangeEvent.
+ * @param evt the event to fire.
+ */
+ private void fireChangeEvent(ChangeEvent evt)
+ {
+ synchronized(listeners)
+ {
+ for (int i = 0; i < listeners.size(); i++)
+ {
+ NetworkConfigurationChangeListener nCChangeListener
+ = listeners.get(i);
+ try
+ {
+ nCChangeListener.configurationChanged(evt);
+ } catch (Throwable e)
+ {
+ logger.warn("Error delivering event:" + evt + ", to:"
+ + nCChangeListener);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Stop current running thread.
+ */
+ void stop()
+ {
+ synchronized(this)
+ {
+ isRunning = false;
+ notifyAll();
+ }
+ }
+
+ /**
+ * Checks whether the supplied network interface name is in the list.
+ * @param ifaces the list of interfaces.
+ * @param name the name to check.
+ * @return whether name is found in the list of interfaces.
+ */
+ private boolean containsInterfaceWithName(
+ List<NetworkInterface> ifaces, String name)
+ {
+ for (int i = 0; i < ifaces.size(); i++)
+ {
+ NetworkInterface networkInterface = ifaces.get(i);
+ if(networkInterface.getName().equals(name))
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Whether the supplied interface has a valid non-local address.
+ * @param iface interface.
+ * @return has a valid address.
+ */
+ private static boolean hasValidAddress(NetworkInterface iface)
+ {
+ Enumeration<InetAddress> as =
+ iface.getInetAddresses();
+ while (as.hasMoreElements())
+ {
+ InetAddress inetAddress = as.nextElement();
+ if(inetAddress.isLinkLocalAddress())
+ continue;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether or not the <tt>iface</tt> interface is a loopback
+ * interface. We use this method as a replacement to the
+ * <tt>NetworkInterface.isLoopback()</tt> method that only comes with
+ * java 1.6.
+ *
+ * @param iface the interface that we'd like to determine as loopback or not.
+ *
+ * @return true if <tt>iface</tt> contains at least one loopback address
+ * and <tt>false</tt> otherwise.
+ */
+ public static boolean isInterfaceLoopback(NetworkInterface iface)
+ {
+ try
+ {
+ Method method = iface.getClass().getMethod("isLoopback");
+
+ return ((Boolean)method.invoke(iface, new Object[]{}))
+ .booleanValue();
+ }
+ catch(Throwable t)
+ {
+ //apparently we are not running in a JVM that supports the
+ //is Loopback method. we'll try another approach.
+ }
+ Enumeration<InetAddress> addresses = iface.getInetAddresses();
+
+ return addresses.hasMoreElements()
+ && addresses.nextElement().isLoopbackAddress();
+ }
+
+ /**
+ * Determines, if possible, whether or not the <tt>iface</tt> interface is
+ * up. We use this method so that we could use {@link
+ * java.net.NetworkInterface}'s <tt>isUp()</tt> when running a JVM that
+ * supports it and return a default value otherwise.
+ *
+ * @param iface the interface that we'd like to determine as Up or Down.
+ *
+ * @return <tt>false</tt> if <tt>iface</tt> is known to be down and
+ * <tt>true</tt> if the <tt>iface</tt> is Up or in case we couldn't
+ * determine.
+ */
+ public static boolean isInterfaceUp(NetworkInterface iface)
+ {
+ try
+ {
+ Method method = iface.getClass().getMethod("isUp");
+
+ return ((Boolean)method.invoke(iface)).booleanValue();
+ }
+ catch(Throwable t)
+ {
+ //apparently we are not running in a JVM that supports the
+ //isUp method. returning default value.
+ }
+
+ return true;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf b/src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf
index af7d319..00eee79 100644
--- a/src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf
+++ b/src/net/java/sip/communicator/impl/netaddr/netaddr.manifest.mf
@@ -9,3 +9,4 @@ Import-Package: net.java.sip.communicator.service.configuration,
net.java.sip.communicator.util,
org.osgi.framework,
Export-Package: net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.service.netaddr.event
diff --git a/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java
index afb1647..3ebcaee 100644
--- a/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java
@@ -605,14 +605,6 @@ public class ProtocolProviderServiceIcqImpl
int reasonCode,
String reason)
{
- if(newState.equals(RegistrationState.CONNECTION_FAILED) &&
- isRegistered())
- {
- // if for some reason (keep alive failed) and connection is
- // still connected disconneted
- unregister();
- }
-
lastRegistrationState = newState;
super.fireRegistrationStateChanged(
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java b/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java
index 0ddce75..ad1f02d 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java
@@ -10,6 +10,7 @@ import java.util.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
import net.sf.jml.*;
import net.sf.jml.impl.*;
import net.sf.jml.net.*;
@@ -25,15 +26,30 @@ import net.sf.jml.protocol.incoming.*;
public class EventManager
extends SessionAdapter
{
+ /**
+ * The class logger.
+ */
private static final Logger logger = Logger.getLogger(EventManager.class);
+ /**
+ * Whether we are connected.
+ */
private boolean connected = false;
+ /**
+ * The timer for monitoring connection.
+ */
private Timer connectionTimer;
+ /**
+ * Event listeners.
+ */
private final List<MsnContactListEventListener> listeners
= new Vector<MsnContactListEventListener>();
+ /**
+ * The messenger.
+ */
private final BasicMessenger msnMessenger;
/**
@@ -143,6 +159,11 @@ public class EventManager
}
}
+ /**
+ * Called when there was timeout on the connection.
+ * @param socketSession
+ * @throws Exception
+ */
public void sessionTimeout(Session socketSession) throws Exception
{
Timer connectionTimer;
@@ -164,8 +185,11 @@ public class EventManager
{
if(!connected && msnProvider.isRegistered())
{
- msnProvider.unregister(false);
- msnProvider.reconnect(SecurityAuthority.CONNECTION_FAILED);
+ msnProvider.fireRegistrationStateChanged(
+ msnProvider.getRegistrationState(),
+ RegistrationState.CONNECTION_FAILED,
+ RegistrationStateChangeEvent.REASON_NOT_SPECIFIED,
+ null);
}
}
}, 20000);
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetTypingNotificationsMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetTypingNotificationsMsnImpl.java
index bdcc12d..2a5c912 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetTypingNotificationsMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetTypingNotificationsMsnImpl.java
@@ -22,6 +22,9 @@ import net.sf.jml.message.*;
public class OperationSetTypingNotificationsMsnImpl
extends AbstractOperationSetTypingNotifications<ProtocolProviderServiceMsnImpl>
{
+ /**
+ * This class logger.
+ */
private static final Logger logger =
Logger.getLogger(OperationSetTypingNotificationsMsnImpl.class);
@@ -31,6 +34,9 @@ public class OperationSetTypingNotificationsMsnImpl
*/
private OperationSetPersistentPresenceMsnImpl opSetPersPresence = null;
+ /**
+ * The messenger.
+ */
private MsnMessenger messenger = null;
/**
@@ -99,12 +105,23 @@ public class OperationSetTypingNotificationsMsnImpl
void setMessenger(MsnMessenger messenger)
{
this.messenger = messenger;
- messenger.addMessageListener(new TypingListener());
+
+ if(messenger != null)
+ messenger.addMessageListener(new TypingListener());
}
+ /**
+ * Listens for typing notifications coming from the protocol.
+ */
private class TypingListener
extends MsnAdapter
{
+ /**
+ * Control message may indicate typing notification.
+ * @param switchboard
+ * @param message
+ * @param contact
+ */
public void controlMessageReceived(MsnSwitchboard switchboard,
MsnControlMessage message,
MsnContact contact)
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java
index 42b2fdd..589484f 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java
@@ -26,9 +26,15 @@ import net.sf.jml.impl.*;
public class ProtocolProviderServiceMsnImpl
extends AbstractProtocolProviderService
{
+ /**
+ * Logger of this class
+ */
private static final Logger logger
= Logger.getLogger(ProtocolProviderServiceMsnImpl.class);
+ /**
+ * The lib messenger.
+ */
private MsnMessenger messenger = null;
/**
@@ -46,8 +52,14 @@ public class ProtocolProviderServiceMsnImpl
*/
private SecurityAuthority authority = null;
+ /**
+ * Operation set for persistent presence.
+ */
private OperationSetPersistentPresenceMsnImpl persistentPresence = null;
+ /**
+ * Operation set for typing notifications.
+ */
private OperationSetTypingNotificationsMsnImpl typingNotifications = null;
/**
@@ -125,6 +137,7 @@ public class ProtocolProviderServiceMsnImpl
/**
* Connects and logins to the server
* @param authority SecurityAuthority
+ * @param reasonCode
* @throws OperationFailedException if login parameters
* as server port are not correct
*/
@@ -234,6 +247,9 @@ public class ProtocolProviderServiceMsnImpl
{
if((messenger != null) && !logoutReceived)
messenger.logout();
+
+ persistentPresence.setMessenger(null);
+ typingNotifications.setMessenger(null);
}
if(fireEvent)
@@ -378,6 +394,10 @@ public class ProtocolProviderServiceMsnImpl
private class MsnConnectionListener
implements MsnMessengerListener
{
+ /**
+ * Fired when login has completed.
+ * @param msnMessenger
+ */
public void loginCompleted(MsnMessenger msnMessenger)
{
logger.trace("loginCompleted " + msnMessenger.getActualMsnProtocol());
@@ -388,6 +408,10 @@ public class ProtocolProviderServiceMsnImpl
null);
}
+ /**
+ * Fire when lib logs out.
+ * @param msnMessenger
+ */
public void logout(MsnMessenger msnMessenger)
{
logger.trace("logout");
@@ -400,6 +424,11 @@ public class ProtocolProviderServiceMsnImpl
}
}
+ /**
+ * Fired when an exception has occurred.
+ * @param msnMessenger
+ * @param throwable
+ */
public void exceptionCaught(MsnMessenger msnMessenger,
Throwable throwable)
{
@@ -430,8 +459,6 @@ public class ProtocolProviderServiceMsnImpl
}
else if(throwable instanceof UnknownHostException)
{
- unregister(false);
-
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.CONNECTION_FAILED,
@@ -484,6 +511,22 @@ public class ProtocolProviderServiceMsnImpl
{
logger.error("Error in Msn lib ", throwable);
+ if(throwable instanceof LoginException)
+ {
+ MsnActivator.getProtocolProviderFactory().
+ storePassword(getAccountID(), null);
+
+ fireRegistrationStateChanged(
+ getRegistrationState(),
+ RegistrationState.AUTHENTICATION_FAILED,
+ RegistrationStateChangeEvent
+ .REASON_AUTHENTICATION_FAILED,
+ null);
+ // We try to reconnect and ask user to retype
+ // password.
+ reconnect(SecurityAuthority.WRONG_PASSWORD);
+ }
+
// We don't want to disconnect on any error, that's why we're
// commenting the following lines for now.
//
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java
index 3bda285..e2d1a19 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java
@@ -71,6 +71,11 @@ public class ServerStoredContactListMsnImpl
private Vector<String> skipAddEvent = new Vector<String>();
/**
+ * Contact list listener.
+ */
+ ContactListListener contactListListener = null;
+
+ /**
* Creates a ServerStoredContactList wrapper for the specified BuddyList.
*
* @param parentOperationSet the operation set that created us and that
@@ -917,7 +922,7 @@ public class ServerStoredContactListMsnImpl
parentOperationSet.earlyStatusesDispatch();
// retreive offline messages
- msnProvider.getMessenger().retreiveOfflineMessages();
+ messenger.retreiveOfflineMessages();
}
public void contactStatusChanged(MsnMessenger messenger,
@@ -1268,6 +1273,18 @@ public class ServerStoredContactListMsnImpl
*/
void setMessenger(MsnMessenger messenger)
{
+ if(messenger == null)
+ {
+ if(contactListModManager != null)
+ contactListModManager.removeModificationListener(
+ contactListModListenerImpl);
+ this.contactListModManager = null;
+ if(contactListListener != null)
+ this.messenger.removeContactListListener(contactListListener);
+ this.contactListListener = null;
+ this.messenger = null;
+ return;
+ }
this.messenger = messenger;
contactListModManager =
@@ -1276,7 +1293,8 @@ public class ServerStoredContactListMsnImpl
contactListModManager.
addModificationListener(contactListModListenerImpl);
- messenger.addContactListListener(new ContactListListener());
+ contactListListener = new ContactListListener();
+ messenger.addContactListListener(contactListListener);
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java
index bd2ca79..6446479 100644
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java
@@ -23,9 +23,15 @@ import ymsg.network.event.*;
public class ProtocolProviderServiceYahooImpl
extends AbstractProtocolProviderService
{
+ /**
+ * This class logger.
+ */
private static final Logger logger =
Logger.getLogger(ProtocolProviderServiceYahooImpl.class);
+ /**
+ * The current yahoo session.
+ */
private YahooSession yahooSession = null;
/**
@@ -48,8 +54,14 @@ public class ProtocolProviderServiceYahooImpl
*/
private SecurityAuthority authority = null;
+ /**
+ * The persistent presence operations set.
+ */
private OperationSetPersistentPresenceYahooImpl persistentPresence = null;
+ /**
+ * Typing notifications operations set.
+ */
private OperationSetTypingNotificationsYahooImpl typingNotifications = null;
/**
@@ -58,6 +70,10 @@ public class ProtocolProviderServiceYahooImpl
private ProtocolIconYahooImpl yahooIcon
= new ProtocolIconYahooImpl();
+ /**
+ * The connection listener.
+ */
+ private YahooConnectionListener connectionListener = null;
/**
* Returns the state of the registration of this protocol provider
@@ -103,7 +119,6 @@ public class ProtocolProviderServiceYahooImpl
* @param authority SecurityAuthority
* @param authReasonCode the authentication reason code, which should
* indicate why are making an authentication request
- * @throws XMPPException if we cannot connect to the server - network problem
* @throws OperationFailedException if login parameters
* as server port are not correct
*/
@@ -152,7 +167,8 @@ public class ProtocolProviderServiceYahooImpl
}
yahooSession = new YahooSession();
- yahooSession.addSessionListener(new YahooConnectionListener());
+ connectionListener = new YahooConnectionListener();
+ yahooSession.addSessionListener(connectionListener);
try
{
@@ -266,6 +282,12 @@ public class ProtocolProviderServiceYahooImpl
try
{
+ if(connectionListener != null && yahooSession != null)
+ {
+ yahooSession.removeSessionListener(connectionListener);
+ connectionListener = null;
+ }
+
if((yahooSession != null)
&& (yahooSession.getSessionStatus() == StatusConstants.MESSAGING))
yahooSession.logout();
@@ -422,8 +444,7 @@ public class ProtocolProviderServiceYahooImpl
int reasonCode,
String reason)
{
- if(newState.equals(RegistrationState.UNREGISTERED) ||
- newState.equals(RegistrationState.CONNECTION_FAILED))
+ if(newState.equals(RegistrationState.UNREGISTERED))
{
unregister(false);
yahooSession = null;
@@ -441,10 +462,11 @@ public class ProtocolProviderServiceYahooImpl
{
/**
* Yahoo has logged us off the system, or the connection was lost
- **/
+ *
+ * @param ev the event
+ */
public void connectionClosed(SessionEvent ev)
{
- unregister(true);
if(isRegistered())
fireRegistrationStateChanged(
getRegistrationState(),
@@ -452,6 +474,10 @@ public class ProtocolProviderServiceYahooImpl
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
}
+ /**
+ * Some exception has occurred in stack.
+ * @param ev
+ */
public void inputExceptionThrown(SessionExceptionEvent ev)
{
if(ev.getException() instanceof YMSG9BadFormatException)
diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java
new file mode 100644
index 0000000..0fc03dc
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java
@@ -0,0 +1,581 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.reconnectplugin;
+
+import java.net.*;
+import java.util.*;
+import java.util.ArrayList;
+
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.netaddr.event.*;
+import net.java.sip.communicator.service.notification.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * Activates the reconnect plug-in.
+ *
+ * @author Damian Minkov
+ */
+public class ReconnectPluginActivator
+ implements BundleActivator,
+ ServiceListener,
+ NetworkConfigurationChangeListener,
+ RegistrationStateChangeListener
+{
+ /**
+ * Logger of this class
+ */
+ private static final Logger logger
+ = Logger.getLogger(ReconnectPluginActivator.class);
+
+ /**
+ * The current BundleContext.
+ */
+ private static BundleContext bundleContext = null;
+
+ /**
+ * The ui service.
+ */
+ private static UIService uiService;
+
+ /**
+ * Notification service.
+ */
+ private static NotificationService notificationService;
+
+ /**
+ * Network address manager service will inform us for changes in
+ * network configuration.
+ */
+ private NetworkAddressManagerService networkAddressManagerService = null;
+
+ /**
+ * Holds every protocol provider which is can be reconnected and
+ * a list of the available and up interfaces when the provider was
+ * registered. When a provider is unregistered it is removed
+ * from this collection.
+ */
+ private Map<ProtocolProviderService, List<String>> autoReconnEnabledProviders =
+ new Hashtable<ProtocolProviderService, List<String>>();
+
+ /**
+ * Holds the currently reconnecting providers and their reconnect tasks.
+ * When they get connected they are removed from this collection.
+ */
+ private Map<ProtocolProviderService, ReconnectTask> currentlyReconnecting =
+ new Hashtable<ProtocolProviderService, ReconnectTask>();
+
+ /**
+ * If network is down we save here the providers which need to be reconnected.
+ */
+ private Set<ProtocolProviderService> needsReconnection =
+ new HashSet<ProtocolProviderService>();
+
+ /**
+ * A list of providers on which we have called unregister. This is a
+ * way to differ our unregister calls from calls coming from user, wanting
+ * to stop all reconnects.
+ */
+ private List<ProtocolProviderService> unregisteredProviders
+ = new ArrayList<ProtocolProviderService>();
+
+ /**
+ * A list of currently connected interfaces. If empty network is down.
+ */
+ private Set<String> connectedInterfaces = new HashSet<String>();
+
+ /**
+ * Timer for scheduling all reconnect operations.
+ */
+ private Timer timer = null;
+
+ /**
+ * Start of the delay interval when starting a reconnect.
+ */
+ private static final int RECONNECT_DELAY_MIN = 8; // sec
+
+ /**
+ * The end of the interval for the initial reconnect.
+ */
+ private static final int RECONNECT_DELAY_MAX = 30; // sec
+
+ /**
+ * Max value for growing the reconnect delay, all subsequent reconnects
+ * use this maximum delay.
+ */
+ private static final int MAX_RECONNECT_DELAY = 300; // sec
+
+ /**
+ * Network notifications event type.
+ */
+ public static final String NETWORK_NOTIFICATIONS = "NetowrkNotifications";
+
+ /**
+ * Starts this bundle
+ *
+ * @param bundleContext BundleContext
+ * @throws Exception
+ */
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ try
+ {
+ logger.logEntry();
+ ReconnectPluginActivator.bundleContext = bundleContext;
+ }
+ finally
+ {
+ logger.logExit();
+ }
+
+ bundleContext.addServiceListener(this);
+
+ if(timer == null)
+ timer = new Timer("Reconnect timer");
+
+ ServiceReference serviceReference = bundleContext.getServiceReference(
+ NetworkAddressManagerService.class.getName());
+
+ this.networkAddressManagerService =
+ (NetworkAddressManagerService)bundleContext
+ .getService(serviceReference);
+
+ this.networkAddressManagerService
+ .addNetworkConfigurationChangeListener(this);
+
+ ServiceReference[] protocolProviderRefs = null;
+ try
+ {
+ protocolProviderRefs = bundleContext.getServiceReferences(
+ ProtocolProviderService.class.getName(), null);
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // this shouldn't happen since we're providing no parameter string
+ // but let's log just in case.
+ logger.error(
+ "Error while retrieving service refs", ex);
+ return;
+ }
+
+ // in case we found any
+ if (protocolProviderRefs != null)
+ {
+ logger.debug("Found "
+ + protocolProviderRefs.length
+ + " already installed providers.");
+ for (int i = 0; i < protocolProviderRefs.length; i++)
+ {
+ ProtocolProviderService provider
+ = (ProtocolProviderService) bundleContext
+ .getService(protocolProviderRefs[i]);
+
+ this.handleProviderAdded(provider);
+ }
+ }
+ }
+
+ /**
+ * Stop the bundle. Nothing to stop for now.
+ * @param bundleContext
+ * @throws Exception
+ */
+ public void stop(BundleContext bundleContext)
+ throws Exception
+ {
+ if(timer != null)
+ {
+ timer.cancel();
+ timer = null;
+ }
+ }
+
+ /**
+ * Returns the <tt>UIService</tt> obtained from the bundle context.
+ *
+ * @return the <tt>UIService</tt> obtained from the bundle context
+ */
+ public static UIService getUIService()
+ {
+ if (uiService == null)
+ {
+ ServiceReference uiReference =
+ bundleContext.getServiceReference(UIService.class.getName());
+
+ uiService =
+ (UIService) bundleContext
+ .getService(uiReference);
+ }
+
+ return uiService;
+ }
+
+ /**
+ * Returns the <tt>NotificationService</tt> obtained from the bundle context.
+ *
+ * @return the <tt>NotificationService</tt> obtained from the bundle context
+ */
+ public static NotificationService getNotificationService()
+ {
+ if (notificationService == null)
+ {
+ ServiceReference serviceReference = bundleContext
+ .getServiceReference(NotificationService.class.getName());
+
+ notificationService = (NotificationService) bundleContext
+ .getService(serviceReference);
+
+ notificationService.registerDefaultNotificationForEvent(
+ NETWORK_NOTIFICATIONS,
+ NotificationService.ACTION_POPUP_MESSAGE,
+ null,
+ null);
+ }
+
+ return notificationService;
+ }
+
+ /**
+ * When new protocol provider is registered we add needed listeners.
+ *
+ * @param serviceEvent ServiceEvent
+ */
+ public void serviceChanged(ServiceEvent serviceEvent)
+ {
+ ServiceReference serviceRef = serviceEvent.getServiceReference();
+
+ // if the event is caused by a bundle being stopped, we don't want to
+ // know
+ if (serviceRef.getBundle().getState() == Bundle.STOPPING)
+ {
+ return;
+ }
+
+ Object sService = bundleContext.getService(serviceRef);
+
+ logger.trace("Received a service event for: " +
+ sService.getClass().getName());
+
+ if(sService instanceof NetworkAddressManagerService)
+ {
+ switch (serviceEvent.getType())
+ {
+ case ServiceEvent.REGISTERED:
+ if(this.networkAddressManagerService != null)
+ break;
+
+ this.networkAddressManagerService =
+ (NetworkAddressManagerService)sService;
+ networkAddressManagerService
+ .addNetworkConfigurationChangeListener(this);
+ break;
+ case ServiceEvent.UNREGISTERING:
+ ((NetworkAddressManagerService)sService)
+ .removeNetworkConfigurationChangeListener(this);
+ break;
+ }
+
+ return;
+ }
+
+ // we don't care if the source service is not a protocol provider
+ if (!(sService instanceof ProtocolProviderService))
+ return;
+
+ logger.debug("Service is a protocol provider.");
+ switch (serviceEvent.getType())
+ {
+ case ServiceEvent.REGISTERED:
+ this.handleProviderAdded((ProtocolProviderService)sService);
+ break;
+
+ case ServiceEvent.UNREGISTERING:
+ this.handleProviderRemoved( (ProtocolProviderService) sService);
+ break;
+ }
+ }
+
+ /**
+ * Add listeners to newly registered protocols.
+ *
+ * @param provider ProtocolProviderService
+ */
+ private void handleProviderAdded(ProtocolProviderService provider)
+ {
+ logger.debug("Adding protocol provider " + provider.getProtocolName());
+
+ if(provider instanceof ProtocolProviderService)
+ {
+ provider.addRegistrationStateChangeListener(this);
+ }
+ }
+
+ /**
+ * Stop listening for events as the provider is removed.
+ *
+ * @param provider the ProtocolProviderService that has been unregistered.
+ */
+ private void handleProviderRemoved(ProtocolProviderService provider)
+ {
+ if(provider instanceof ProtocolProviderService)
+ {
+ provider.removeRegistrationStateChangeListener(this);
+ }
+ }
+
+ /**
+ * Fired when a change has occurred in the computer network configuration.
+ *
+ * @param event the change event.
+ */
+ public synchronized void configurationChanged(ChangeEvent event)
+ {
+ if(!(event.getSource() instanceof NetworkInterface))
+ return;
+
+ NetworkInterface iface = (NetworkInterface)event.getSource();
+
+ if(event.getType() == ChangeEvent.IFACE_UP)
+ {
+ // no connection so one is up, lets connect
+ if(connectedInterfaces.size() == 0)
+ {
+ Iterator<ProtocolProviderService> iter =
+ needsReconnection.iterator();
+ while (iter.hasNext())
+ {
+ ProtocolProviderService pp = iter.next();
+ if(currentlyReconnecting.containsKey(pp))
+ {
+ // now lets cancel it and schedule it again
+ // so it will use this iface
+ currentlyReconnecting.get(pp).cancel();
+ currentlyReconnecting.remove(pp);
+ }
+
+ reconnect(pp);
+ }
+
+ needsReconnection.clear();
+ }
+
+ connectedInterfaces.add(iface.getName());
+ }
+ else if(event.getType() == ChangeEvent.IFACE_DOWN)
+ {
+ connectedInterfaces.remove(iface.getName());
+
+ // one is down and at least one more is connected
+ if(connectedInterfaces.size() > 0)
+ {
+ // lets reconnect all that was connected when this one was
+ // available, cause they maybe using it
+ Iterator<Map.Entry<ProtocolProviderService, List<String>>> iter =
+ autoReconnEnabledProviders.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry<ProtocolProviderService, List<String>> entry
+ = iter.next();
+
+ if(entry.getValue().contains(iface.getName()))
+ {
+ ProtocolProviderService pp = entry.getKey();
+ // hum someone is reconnecting, lets cancel and
+ // schedule it again
+ if(currentlyReconnecting.containsKey(pp))
+ {
+ currentlyReconnecting.get(pp).cancel();
+ currentlyReconnecting.remove(pp);
+ }
+
+ reconnect(pp);
+ }
+ }
+ }
+ else
+ {
+ // we must disconnect every pp and put all to be need of reconnecting
+ needsReconnection.addAll(autoReconnEnabledProviders.keySet());
+
+ Iterator<ProtocolProviderService> iter =
+ needsReconnection.iterator();
+ while (iter.hasNext())
+ {
+ ProtocolProviderService pp = iter.next();
+ try
+ {
+ unregisteredProviders.add(pp);
+ pp.unregister();
+ } catch (Exception e)
+ {
+ logger.error("Cannot unregister provider", e);
+ }
+ }
+
+ connectedInterfaces.clear();
+
+ logger.trace("Network is down!");
+ getNotificationService().fireNotification(
+ NETWORK_NOTIFICATIONS,
+ "Network is down!",
+ "",
+ null,
+ null);
+ }
+ }
+ }
+
+ /**
+ * The method is called by a <code>ProtocolProviderService</code>
+ * implementation whenever a change in the registration state of the
+ * corresponding provider had occurred.
+ *
+ * @param evt the event describing the status change.
+ */
+ public synchronized void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ // we don't care about protocol providers that don't support
+ // reconnection
+ if(!(evt.getSource() instanceof ProtocolProviderService))
+ return;
+
+ ProtocolProviderService pp = (ProtocolProviderService)evt.getSource();
+
+ if(evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))
+ {
+ // if this pp is already in needsReconnection, it means
+ // we got conn failed cause the pp has tried to unregister
+ // with sending network packet
+ // but this unregister is scheduled from us so skip
+ if(needsReconnection.contains(pp))
+ return;
+
+ if(connectedInterfaces.size() == 0)
+ needsReconnection.add(pp);
+ else
+ {
+ // network is up but something happen and cannot reconnect
+ // strange lets try again after some time
+ reconnect(pp);
+ }
+
+ // unregister can finish and with connection failed,
+ // the protocol is unable to unregister
+ unregisteredProviders.remove(pp);
+ }
+ else if(evt.getNewState().equals(RegistrationState.REGISTERED))
+ {
+ autoReconnEnabledProviders.put(
+ (ProtocolProviderService)evt.getSource(),
+ new ArrayList<String>(connectedInterfaces));
+
+ currentlyReconnecting.remove(pp);
+ }
+ else if(evt.getNewState().equals(RegistrationState.UNREGISTERED))
+ {
+ autoReconnEnabledProviders.remove(
+ (ProtocolProviderService)evt.getSource());
+
+ if(!unregisteredProviders.contains(pp)
+ && currentlyReconnecting.containsKey(pp))
+ {
+ currentlyReconnecting.remove(pp).cancel();
+ }
+ unregisteredProviders.remove(pp);
+ }
+ }
+
+ /**
+ * Method to schedule a reconnect for a protocol provider.
+ * @param pp the provider.
+ */
+ private void reconnect(ProtocolProviderService pp)
+ {
+ long delay;
+
+ if(currentlyReconnecting.containsKey(pp))
+ {
+ delay = currentlyReconnecting.get(pp).delay;
+
+ // we never stop trying
+ //if(delay == MAX_RECONNECT_DELAY*1000)
+ // return;
+
+ delay = Math.min(delay * 2, MAX_RECONNECT_DELAY*1000);
+ }
+ else
+ {
+ delay = (long)(RECONNECT_DELAY_MIN
+ + Math.random() * RECONNECT_DELAY_MAX)*1000;
+ }
+
+ // as we will reconnect, lets unregister
+ try
+ {
+ unregisteredProviders.add(pp);
+ pp.unregister();
+ } catch (OperationFailedException e)
+ {
+ logger.error("Cannot unregister provider", e);
+ }
+
+ ReconnectTask task = new ReconnectTask(pp);
+ task.delay = delay;
+ currentlyReconnecting.put(pp, task);
+
+ logger.trace("Reconnect " + pp + " after " + delay + " ms.");
+ timer.schedule(task, delay);
+ }
+
+ /**
+ * The task executed by the timer when time for reconnect comes.
+ */
+ private class ReconnectTask
+ extends TimerTask
+ {
+ /**
+ * The provider to reconnect.
+ */
+ private ProtocolProviderService provider;
+
+ /**
+ * The delay with which was this task scheduled.
+ */
+ private long delay;
+
+ /**
+ * Creates the task.
+ * @param provider
+ */
+ public ReconnectTask(ProtocolProviderService provider)
+ {
+ this.provider = provider;
+ }
+
+ /**
+ * Reconnects the provider.
+ */
+ public void run()
+ {
+ try
+ {
+ logger.trace("Start reconnecting!");
+
+ provider.register(
+ getUIService().getDefaultSecurityAuthority(provider));
+ } catch (OperationFailedException ex)
+ {
+ logger.error("cannot reregister provider will keep going", ex);
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf b/src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf
new file mode 100644
index 0000000..24d859e
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf
@@ -0,0 +1,17 @@
+Bundle-Activator: net.java.sip.communicator.plugin.reconnectplugin.ReconnectPluginActivator
+Bundle-Name: ReconnectPlugin
+Bundle-Description: A bundle that implements the Reconnect Plugin Package.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: org.osgi.framework,
+ net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.service.netaddr.event,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.gui,
+ net.java.sip.communicator.service.notification,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.protocol.event,
+ net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.swing \ No newline at end of file
diff --git a/src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java b/src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java
index eb1edc5..478dd30 100644
--- a/src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java
+++ b/src/net/java/sip/communicator/service/netaddr/NetworkAddressManagerService.java
@@ -9,6 +9,8 @@ package net.java.sip.communicator.service.netaddr;
import java.net.*;
import java.io.*;
+import net.java.sip.communicator.service.netaddr.event.*;
+
/**
* The NetworkAddressManagerService takes care of problems such as
* @author Emil Ivov
@@ -119,4 +121,19 @@ public interface NetworkAddressManagerService
IOException,
BindException;
+ /**
+ * Adds new <tt>NetworkConfigurationChangeListener</tt> which will
+ * be informed for network configuration changes.
+ * @param listener the listener.
+ */
+ public void addNetworkConfigurationChangeListener(
+ NetworkConfigurationChangeListener listener);
+
+ /**
+ * Remove <tt>NetworkConfigurationChangeListener</tt>.
+ * @param listener the listener.
+ */
+ public void removeNetworkConfigurationChangeListener(
+ NetworkConfigurationChangeListener listener);
+
}
diff --git a/src/net/java/sip/communicator/service/netaddr/event/ChangeEvent.java b/src/net/java/sip/communicator/service/netaddr/event/ChangeEvent.java
new file mode 100644
index 0000000..a31d9fc
--- /dev/null
+++ b/src/net/java/sip/communicator/service/netaddr/event/ChangeEvent.java
@@ -0,0 +1,100 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.netaddr.event;
+
+/**
+ * A ChangeEvent is fired on change of the network configuration of the computer.
+ *
+ * @author Damian Minkov
+ */
+public class ChangeEvent
+ extends java.util.EventObject
+{
+ /**
+ * Event type for interface going up.
+ */
+ public static final int IFACE_DOWN = 0;
+
+ /**
+ * Event type for interface going down.
+ */
+ public static final int IFACE_UP = 1;
+
+ /**
+ * The type of the current event.
+ */
+ private int type = -1;
+
+ /**
+ * Whether this event is after computer have been suspended.
+ */
+ private boolean standby = false;
+
+ /**
+ * Creates event.
+ * @param source the source of the event.
+ * @param type the type of the event.
+ */
+ public ChangeEvent(Object source, int type)
+ {
+ super(source);
+
+ this.type = type;
+ }
+
+ /**
+ * Creates event.
+ * @param source the source of the event.
+ * @param type the type of the event.
+ * @param standby is the event after a suspend of the computer.
+ */
+ public ChangeEvent(Object source, int type, boolean standby)
+ {
+ this(source, type);
+
+ this.standby = standby;
+ }
+
+ /**
+ * The type of this event.
+ * @return the type
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ /**
+ * Whether this event is after suspend of the computer.
+ * @return the standby
+ */
+ public boolean isStandby()
+ {
+ return standby;
+ }
+
+ /**
+ * Overrides toString method.
+ * @return string representing the event.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buff = new StringBuilder();
+ buff.append("ChangeEvent ");
+
+ switch(type)
+ {
+ case IFACE_DOWN: buff.append("Interface down"); break;
+ case IFACE_UP: buff.append("Interface up"); break;
+ }
+
+ buff.append(", standby=" + standby);
+
+ return buff.toString();
+ }
+}
diff --git a/src/net/java/sip/communicator/service/netaddr/event/NetworkConfigurationChangeListener.java b/src/net/java/sip/communicator/service/netaddr/event/NetworkConfigurationChangeListener.java
new file mode 100644
index 0000000..7318640
--- /dev/null
+++ b/src/net/java/sip/communicator/service/netaddr/event/NetworkConfigurationChangeListener.java
@@ -0,0 +1,22 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.netaddr.event;
+
+/**
+ * Listens for network changes in the computer configuration.
+ *
+ * @author Damian Minkov
+ */
+public interface NetworkConfigurationChangeListener
+{
+ /**
+ * Fired when a change has occurred in the computer network configuration.
+ *
+ * @param event the change event.
+ */
+ public void configurationChanged(ChangeEvent event);
+}