/* * 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; } } }