/*
* Created on Aug 14, 2012
* Created by Paul Gardner
*
* Copyright 2012 Vuze, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
package com.aelitis.azureus.core.pairing.impl.swt;
import java.net.InetAddress;
import java.util.*;
import org.eclipse.swt.graphics.Image;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TimeFormatter;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.ui.UIInstance;
import org.gudy.azureus2.plugins.ui.UIManagerListener;
import org.gudy.azureus2.plugins.ui.config.BooleanParameter;
import org.gudy.azureus2.plugins.ui.config.Parameter;
import org.gudy.azureus2.plugins.ui.config.ParameterListener;
import org.gudy.azureus2.plugins.ui.menus.MenuItem;
import org.gudy.azureus2.plugins.ui.menus.MenuItemListener;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.plugins.UISWTInstance;
import org.gudy.azureus2.ui.swt.plugins.UISWTStatusEntry;
import org.gudy.azureus2.ui.swt.plugins.UISWTStatusEntryListener;
import org.gudy.azureus2.ui.swt.auth.CryptoWindow;
import com.aelitis.azureus.core.pairing.impl.PairingManagerImpl;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdmin;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminNetworkInterface;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminNetworkInterfaceAddress;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminPropertyChangeListener;
import com.aelitis.azureus.core.security.CryptoManagerPasswordHandler;
import com.aelitis.azureus.core.util.AZ3Functions;
import com.aelitis.azureus.ui.UIFunctions;
import com.aelitis.azureus.ui.UIFunctionsManager;
import com.aelitis.azureus.ui.common.updater.UIUpdater;
import com.aelitis.azureus.ui.swt.imageloader.ImageLoader;
public class
PMSWTImpl
implements PairingManagerImpl.UIAdapter
{
private UISWTStatusEntry status;
private volatile Set<String> local_addresses = new HashSet<String>();
private Image icon_idle;
private Image icon_green;
private Image icon_red;
private int last_update_count;
private Image last_image;
private String last_tooltip_text = "";
private long last_image_expiry_mono;
private long last_image_expiry_uc_min;
public void
initialise(
final PluginInterface pi,
final BooleanParameter icon_enable )
{
final NetworkAdmin na = NetworkAdmin.getSingleton();
na.addPropertyChangeListener(
new NetworkAdminPropertyChangeListener()
{
public void
propertyChanged(
String property)
{
if ( property == NetworkAdmin.PR_NETWORK_INTERFACES ){
updateLocalAddresses( na );
}
}
});
updateLocalAddresses( na );
pi.getUIManager().addUIListener(
new UIManagerListener()
{
public void
UIAttached(
final UIInstance instance )
{
if ( instance instanceof UISWTInstance ){
UIFunctions uif = UIFunctionsManager.getUIFunctions();
if ( uif != null ){
uif.getUIUpdater().addListener(
new UIUpdater.UIUpdaterListener()
{
public void
updateComplete(
int count )
{
last_update_count = count;
updateStatus( true );
}
});
}
Utils.execSWTThread(
new AERunnable()
{
public void
runSupport()
{
ImageLoader imageLoader = ImageLoader.getInstance();
icon_idle = imageLoader.getImage( "pair_sb_idle" );
icon_green = imageLoader.getImage( "pair_sb_green" );
icon_red = imageLoader.getImage( "pair_sb_red" );
UISWTInstance ui_instance = (UISWTInstance)instance;
status = ui_instance.createStatusEntry();
last_tooltip_text = MessageText.getString( "pairing.ui.icon.tip" );
status.setTooltipText( last_tooltip_text );
status.setImageEnabled( true );
status.setImage( icon_idle );
last_image = icon_idle;
boolean is_visible = icon_enable.getValue();
status.setVisible( is_visible );
if ( is_visible ){
updateStatus( false );
}
final MenuItem mi_show =
pi.getUIManager().getMenuManager().addMenuItem(
status.getMenuContext(),
"pairing.ui.icon.show" );
mi_show.setStyle( MenuItem.STYLE_CHECK );
mi_show.setData( new Boolean( is_visible ));
mi_show.addListener(
new MenuItemListener()
{
public void
selected(
MenuItem menu,
Object target )
{
icon_enable.setValue( false );
}
});
icon_enable.addListener(
new ParameterListener()
{
public void
parameterChanged(
Parameter param )
{
boolean is_visible = icon_enable.getValue();
status.setVisible( is_visible );
mi_show.setData( new Boolean( is_visible ));
if ( is_visible ){
updateStatus( false );
}
}
});
final AZ3Functions.provider az3 = AZ3Functions.getProvider();
if ( az3 != null ){
MenuItem mi_pairing =
pi.getUIManager().getMenuManager().addMenuItem(
status.getMenuContext(),
"MainWindow.menu.pairing" );
mi_pairing.addListener(
new MenuItemListener()
{
public void
selected(
MenuItem menu,
Object target )
{
az3.openRemotePairingWindow();
}
});
}
MenuItem mi_sep =
pi.getUIManager().getMenuManager().addMenuItem(
status.getMenuContext(),
"" );
mi_sep.setStyle( MenuItem.STYLE_SEPARATOR );
MenuItem mi_options =
pi.getUIManager().getMenuManager().addMenuItem(
status.getMenuContext(),
"MainWindow.menu.view.configuration" );
mi_options.addListener(
new MenuItemListener()
{
public void
selected(
MenuItem menu,
Object target )
{
UIFunctions uif = UIFunctionsManager.getUIFunctions();
if ( uif != null ){
uif.openView( UIFunctions.VIEW_CONFIG, "Pairing" );
}
}
});
UISWTStatusEntryListener click_listener =
new UISWTStatusEntryListener()
{
public void
entryClicked(
UISWTStatusEntry entry )
{
UIFunctions uif = UIFunctionsManager.getUIFunctions();
if ( uif != null ){
uif.openView( UIFunctions.VIEW_CONFIG, "Pairing" );
}
}
};
status.setListener( click_listener );
}
});
}
}
public void
UIDetached(
UIInstance instance )
{
}
});
}
private void
updateLocalAddresses(
NetworkAdmin network_admin )
{
NetworkAdminNetworkInterface[] interfaces = network_admin.getInterfaces();
Set<String> ias = new HashSet<String>();
for ( NetworkAdminNetworkInterface intf: interfaces ){
NetworkAdminNetworkInterfaceAddress[] addresses = intf.getAddresses();
for ( NetworkAdminNetworkInterfaceAddress address: addresses ){
InetAddress ia = address.getAddress();
ias.add( ia.getHostAddress());
}
}
local_addresses = ias;
}
private Map<String,RemoteHistory> history_map = new HashMap<String, RemoteHistory>();
public void
recordRequest(
final String name,
final String ip,
final boolean good )
{
Utils.execSWTThread(
new AERunnable()
{
public void
runSupport()
{
RemoteHistory entry = history_map.get( name );
if ( entry == null ){
entry = new RemoteHistory();
history_map.put( name, entry );
}
entry.addRequest( ip, good );
updateStatus( false );
}
});
}
private void
updateStatus(
boolean update_completed )
{
final int RECORD_EXPIRY = 60*60*1000;
final int GOOD_EXPIRY = 1*1000;
final int BAD_EXPIRY = 5*60*1000;
final int MAX_IPS_PER_TYPE = 10;
final int MAX_TYPES = 10;
if ( status == null ){
return;
}
long now_mono = SystemTime.getMonotonousTime();
if ( update_completed ){
if ( last_image != icon_idle && last_update_count >= last_image_expiry_uc_min ){
if ( now_mono >= last_image_expiry_mono ){
last_image = icon_idle;
status.setImage( icon_idle );
}
}
}
StringBuffer tooltip_text = new StringBuffer( 256 );
tooltip_text.append( MessageText.getString( "pairing.ui.icon.tip" ));
long newest_bad_mono = -1;
long newest_good_mono = -1;
Iterator<Map.Entry<String,RemoteHistory>> it = history_map.entrySet().iterator();
String oldest_type = null;
long oldest_type_mono = Long.MAX_VALUE;
int records_added = 0;
while( it.hasNext()){
Map.Entry<String,RemoteHistory> entry = it.next();
String name = entry.getKey();
RemoteHistory history = entry.getValue();
String oldest_ip = null;
long oldest_ip_mono = Long.MAX_VALUE;
Map<String,RemoteHistoryEntry> records = history.getEntries();
Iterator<Map.Entry<String,RemoteHistoryEntry>> record_it = records.entrySet().iterator();
StringBuffer tt_ip_details = new StringBuffer( 256 );
while( record_it.hasNext()){
Map.Entry<String,RemoteHistoryEntry> record = record_it.next();
String ip = record.getKey();
RemoteHistoryEntry e = record.getValue();
long e_mono = e.getLastReceivedMono();
if ( e_mono < oldest_ip_mono ){
oldest_ip_mono = e_mono;
oldest_ip = ip;
}
long age = now_mono - e_mono;
if ( age > RECORD_EXPIRY ){
record_it.remove();
}else{
String age_str = TimeFormatter.format( age/1000 );
tt_ip_details.append( "\n " );
if ( local_addresses.contains( ip )){
tt_ip_details.append( MessageText.getString( "DHTView.db.local" ) + " (" + ip + ")" );
}else{
tt_ip_details.append( ip );
}
if ( e.wasLastGood()){
tt_ip_details.append( " OK" );
newest_good_mono = Math.max( newest_good_mono, e_mono );
}else{
tt_ip_details.append( " " + MessageText.getString( "label.access.denied" ));
newest_bad_mono = Math.max( newest_bad_mono, e_mono );
}
tt_ip_details.append( " - " + age_str + " ago");
}
}
if ( records.size() == 0 ){
it.remove();
}else{
if ( oldest_ip_mono < oldest_type_mono ){
oldest_type_mono = oldest_ip_mono;
oldest_type = name;
}
if ( records.size() >= MAX_IPS_PER_TYPE ){
records.remove( oldest_ip );
}else{
tooltip_text.append( "\n " + name );
tooltip_text.append( tt_ip_details );
records_added++;
}
}
}
if ( history_map.size() > MAX_TYPES ){
history_map.remove( oldest_type );
}
if ( records_added == 0 ){
tooltip_text.append( "\n " + MessageText.getString( "pairing.ui.icon.tip.no.recent" ));
}
String tooltip_text_str = tooltip_text.toString();
if ( !tooltip_text_str.equals( last_tooltip_text )){
last_tooltip_text = tooltip_text_str;
status.setTooltipText( last_tooltip_text );
}
Image target_image = null;
long age_newest_bad = now_mono - newest_bad_mono;
if ( newest_bad_mono >= 0 && age_newest_bad <= BAD_EXPIRY ){
target_image = icon_red;
last_image_expiry_mono = newest_bad_mono + BAD_EXPIRY;
}else{
long age_newest_good = now_mono - newest_good_mono;
if ( newest_good_mono >= 0 && age_newest_good <= GOOD_EXPIRY ){
target_image = icon_green;
last_image_expiry_mono = age_newest_good + GOOD_EXPIRY;
}
}
if ( target_image != null && target_image != last_image ){
last_image = target_image;
last_image_expiry_uc_min = last_update_count + 2;
status.setImage( target_image );
}
}
public char[]
getSRPPassword()
{
CryptoWindow pw_win = new CryptoWindow( true );
CryptoWindow.passwordDetails result =
pw_win.getPassword(
-1,
CryptoManagerPasswordHandler.ACTION_PASSWORD_SET,
true, "Change SRP Password");
if ( result != null ){
return( result.getPassword());
}
return( null );
}
private static class
RemoteHistory
{
private Map<String,RemoteHistoryEntry> map = new HashMap<String, RemoteHistoryEntry>();
private void
addRequest(
String ip,
boolean good )
{
RemoteHistoryEntry entry = map.get( ip );
if ( entry == null ){
entry = new RemoteHistoryEntry();
map.put( ip, entry );
}
entry.update( good );
}
private Map<String,RemoteHistoryEntry>
getEntries()
{
return( map );
}
}
private static class
RemoteHistoryEntry
{
private long last_received_mono;
private long last_received_rtc;
private int request_count;
private boolean last_was_good;
private long
getLastReceivedMono()
{
return( last_received_mono );
}
private long
getLastReceivedRTC()
{
return( last_received_rtc );
}
private int
getRequestCount()
{
return( request_count );
}
private boolean
wasLastGood()
{
return( last_was_good );
}
private void
update(
boolean good )
{
last_received_mono = SystemTime.getMonotonousTime();
last_received_rtc = SystemTime.getCurrentTime();
request_count++;
last_was_good = good;
}
}
}