View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.plugin.opennap.net;
21  
22  import java.beans.PropertyChangeEvent;
23  import java.beans.PropertyChangeListener;
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.LinkedList;
29  import java.util.List;
30  import java.util.StringTokenizer;
31  
32  import org.apache.log4j.Logger;
33  import org.xnap.XNap;
34  import org.xnap.event.ListListener;
35  import org.xnap.event.ListSupport;
36  import org.xnap.event.StatusListener;
37  import org.xnap.io.Library;
38  import org.xnap.io.MetaInfoFile;
39  import org.xnap.io.MetaInfoManager;
40  import org.xnap.net.NetHelper;
41  import org.xnap.plugin.opennap.OpenNapPlugin;
42  import org.xnap.plugin.opennap.net.msg.ExceptionListener;
43  import org.xnap.plugin.opennap.net.msg.MessageHandler;
44  import org.xnap.plugin.opennap.net.msg.client.AddHotlistEntryMessage;
45  import org.xnap.plugin.opennap.net.msg.client.ShareFileMessage;
46  import org.xnap.plugin.opennap.user.OpenNapGlobalUser;
47  import org.xnap.plugin.opennap.util.OpenNapPreferences;
48  import org.xnap.search.SearchManager;
49  import org.xnap.util.Formatter;
50  import org.xnap.util.IllegalOperationException;
51  import org.xnap.util.Notifier;
52  import org.xnap.util.PortRange;
53  import org.xnap.util.Range;
54  import org.xnap.util.Scheduler;
55  import org.xnap.util.XNapTask;
56  
57  public class OpenNapServerManager implements PropertyChangeListener {
58      
59      //--- Constant(s) ---
60  
61      //--- Data field(s) ---
62  
63      private static Logger logger = Logger.getLogger(OpenNapServerManager.class);
64  
65      private OpenNapPreferences napPrefs = OpenNapPlugin.getPreferences();
66  
67      private String stats;
68  	private OpenNapListener listener = new OpenNapListener();
69      protected ListSupport ls = new ListSupport(this);
70  
71      /***
72       * A list of {@link StatusListener} objects.
73       */
74      private LinkedList sl = new LinkedList();
75  
76      /***
77       * Set to true by {@link #add(OpenNapServer,boolean)} if a
78       * temporary server has been added.  
79  	 */
80      private boolean addedTemporary = false;
81  
82      /***
83       * A list of {@link OpenNapServer} objects.
84       */
85      private List servers = new ArrayList();
86  
87      /***
88       * A list of connected {@link OpenNapServer} objects.
89       *
90       * @see #setConnected(OpenNapServer, boolean)
91       */
92      private List connectedServers = new LinkedList();
93  
94      /***
95       * A list of {@link OpenNapNetwork} objects.
96       */
97      private HashMap networkByName = new HashMap();
98  
99      private AutoConnector connector = new AutoConnector();
100 
101     /***
102      * The indes of the next repository file to share.
103      *
104      * @see PostLoginRunner.shareFiles()
105      */
106     private int repositoryIndex = 0;
107 
108 	private AutoFetchTask autoFetchTask;
109 
110 	/***
111 	 * Set to true once downloads have been auto resumed.
112 	 */
113 	private boolean resumed = false;
114 
115     //--- Constructor(s) ---
116     
117     public OpenNapServerManager()
118     {
119 		OpenNapPlugin.getPreferences().addPropertyChangeListener(this);
120 		//  	Repository.getInstance().addListListener(this);
121 
122 		// use the "Other" network as a fallback
123 		networkByName.put("", new OpenNapDefaultNetwork());
124 
125 		updateStats();
126     }
127 
128     //--- Method(s) ---
129 
130     /***
131      * <code>listener</code> is notified when a server is added or removed.
132      */
133     public void addListListener(ListListener listener)
134     {
135 		ls.addListListener(listener);
136     }
137 
138     public void removeListListener(ListListener listener)
139     {
140 		ls.removeListListener(listener);
141     }
142 
143     /***
144      * <code>listener</code> is notified when a server is added or removed.
145      */
146     public synchronized void addStatsListener(StatusListener listener) 
147     {
148 		sl.add(listener);
149     }
150 
151     public synchronized void removeStatsListener(StatusListener listener) 
152     {
153 		sl.remove(listener);
154     }
155 
156     public boolean add(String url, String network, boolean login) 
157     {
158         StringTokenizer s = new StringTokenizer(url, ":");
159 
160         if (s.countTokens() != 2) {
161             return false;
162 		}
163 
164         String ip = s.nextToken();
165 		int port = 0;
166 		try {
167 			port = Integer.parseInt(s.nextToken());
168 		} 
169 		catch (NumberFormatException e) {
170 		}
171 
172 		if (ip.length() == 0 
173 			|| port < PortRange.MIN_PORT || port > PortRange.MAX_PORT) {
174 			return false;
175 		}
176 	
177 		OpenNapServer server = new OpenNapServer(ip, port, network);
178 		add(server, true);
179 
180 //  		if (login) {
181 //  			server.connect();
182 //  		}
183 
184 		return true;
185     }
186 
187     /***
188      * Adds <code>server</code> if it is not already in the list.
189 	 *
190 	 * @return true, if the server was added; false, otherwise
191      */
192     public boolean add(OpenNapServer server, boolean login)
193     {
194 		synchronized (this) {
195 			// keep servers sorted by lastConnect, higher values come first
196 			int index = 0;
197 			for (int i = 0; i < servers.size(); i++) {
198 				OpenNapServer next = (OpenNapServer)servers.get(i);
199 				if (next.equals(server)) {
200 					// we already have the server
201 					return false;
202 				}
203 				if (next.getLastConnect() > server.getLastConnect()) {
204 					index++;
205 				}
206 			}
207 			
208 			OpenNapNetwork network = getNetworkByName(server.getNetworkName());
209 			server.setNetwork(network);
210 			server.setListener(listener);
211 			
212 			servers.add(index, server);
213 			
214 			addedTemporary |= server.isTemporary();
215 			server.addPropertyChangeListener(this);
216 			ls.fireItemAdded(server);
217 			network.add(server);
218 		}
219 		
220 		if (login) {
221 			server.connect();
222 		}
223 			
224 		connector.wakeup();
225 
226 		return true;
227     }
228 
229 	/***
230 	 * Returns the number of servers that were added.
231 	 */
232     public int addFrom(OpenNapServerReader reader, boolean temporary) 
233 		throws IOException
234     {
235 		int count = 0;
236 		try {
237 			reader.open();
238 
239 			OpenNapServer s;
240 			while ((s = reader.read()) != null) {
241 				s.setTemporary(temporary);
242 
243 				if (s.getAutoConnect()) {
244 					if (add(s, true)) {
245 						count++;
246 					}
247 				}
248 				else {
249 					if (add(s, false)) {
250 						count++;
251 					}
252 				}
253 			}
254 			
255 			
256 		}
257 		finally {
258 			reader.close();
259 		}
260 
261 		return count;
262     }	
263 
264     public void die()
265     {
266 		setAutoFetchInterval(-1);
267 
268 		OpenNapPlugin.getPreferences().removePropertyChangeListener(this);
269 		connector.die();
270 
271 		try {
272 			saveTo(new OpenNapServerFileWriter(napPrefs.getServerFile()), false);
273 		}
274 		catch (IOException e) {
275 			logger.debug("could not write file", e);
276 		}
277 
278 		if (addedTemporary) {
279 			try {
280 				saveTo(new OpenNapServerFileWriter(napPrefs.getNapigatorFile()), true);
281 			}
282 			catch (IOException e) {
283 				logger.debug("could not write file", e);
284 			}
285 		}
286 
287 		removeAll();
288 		listener.die();
289     }
290 
291     public void fetchServerLists() 
292 	{
293 		Notifier.info(XNap.tr("Downloading list of OpenNap servers") + "...");
294 		Runnable r = new Runnable()
295 			{
296 				public void run() 
297 				{
298 					String urls
299 						= OpenNapPlugin.getPreferences().getNapigatorURL();
300 					StringTokenizer t = new StringTokenizer(urls, "\n");
301 					while (t.hasMoreTokens()) {
302 						String url = t.nextToken().trim();
303 						if (!url.startsWith("#")) {
304 							try {
305 								addFrom(new NapigatorReader(url), true);
306 							}
307 							catch (IOException e) {
308 								Notifier.error(XNap.tr("Could not get list of OpenNap servers: {0}", NetHelper.getErrorMessage(e)), e);
309 							}
310 						}
311 					}
312 					updateStats();
313 				}
314 			};
315 	
316 		Thread t = new Thread(r, "AskNapigator");
317 		t.start();
318 	}
319 
320     public void remove(OpenNapServer server)
321     {
322 		try {
323 			server.disconnect();
324 		}
325 		catch (IllegalOperationException e) {
326 			// ignore exception, server might not be connected at all
327 		}
328 
329 		synchronized (this) {
330 			server.removePropertyChangeListener(this);
331 			servers.remove(server);
332 			ls.fireItemRemoved(server);
333 		}
334     }
335 
336     public synchronized void removeAll()
337     {
338 		for (Iterator i = servers.iterator(); i.hasNext();) {
339 			OpenNapServer server = (OpenNapServer)i.next();
340 			try {
341 				server.disconnect();
342 			}
343 			catch (IllegalOperationException e) {
344 				// ignore exception, server might not be connected at all
345 			}
346 			server.removePropertyChangeListener(this);
347 		}
348 		servers.clear();
349     }
350 
351     public synchronized OpenNapServer getServerByHost(String host)
352     {
353 		for (Iterator i = servers.iterator(); i.hasNext();) {
354 			OpenNapServer s = (OpenNapServer)i.next();
355 			if (s.getHost().equals(host)) {
356 				return s;
357 			}
358 		}
359 		return null;
360     }
361 
362     public AutoConnector getConnector()
363     {
364 		return connector;
365     }
366 
367     public synchronized int getConnectedCount()
368     {
369 		return connectedServers.size();
370     }
371 
372     public synchronized OpenNapServer[] getConnectedServers()
373     {
374 		return (OpenNapServer[])connectedServers.toArray(new OpenNapServer[0]);
375     }
376 
377     public OpenNapNetwork getNetworkByName(String name)
378     {
379 		OpenNapNetwork n = (OpenNapNetwork)networkByName.get(name);
380 		if (n == null) {
381 			n = new OpenNapNetwork(name);
382 			networkByName.put(name, n);
383 		}
384 		return n;
385     }
386 
387     public synchronized OpenNapServer[] getServers()
388     {
389 		return (OpenNapServer[])servers.toArray(new OpenNapServer[0]);
390     }
391 
392     /***
393      * Returns the stats that were calculated during the last call to 
394      * {@link #updateStats()}.
395      */
396     public String getStats()
397     {
398 		return stats;
399     }
400 
401     public void init()
402     {
403 		updateListener();
404 
405 		Thread t = new Thread(new InitRunner(), "OpenNapServerManagerInit");
406 		t.start();
407     }
408 
409 	public void changeNetwork(OpenNapServer server, String newNetworkName)
410 	{
411 		if (!newNetworkName.equals(server.getNetworkName())) {
412 			OpenNapNetwork oldNetwork = server.getNetwork();
413 			oldNetwork.remove(server);
414 			
415 			OpenNapNetwork newNetwork = getNetworkByName(newNetworkName);
416 			server.setNetwork(newNetwork);
417 			newNetwork.add(server);
418 		}
419 	}
420 
421     public int saveTo(OpenNapServerWriter writer, boolean temporary)
422 		throws IOException
423     {
424 		int count = 0;
425 		try {
426 			writer.open();
427 			for (Iterator i = servers.iterator(); i.hasNext();) {
428 				OpenNapServer s = (OpenNapServer)i.next();
429 				if (s.isTemporary() == temporary) {
430 					writer.write(s);
431 					count++;
432 				}
433 			}
434 		}
435 		finally {
436 			writer.close();
437 		}
438 
439 		return count;
440     }	
441 
442     public int saveTo(OpenNapServerWriter writer)
443 		throws IOException
444     {
445 		int count = 0;
446 		try {
447 			writer.open();
448 			for (Iterator i = servers.iterator(); i.hasNext();) {
449 				OpenNapServer s = (OpenNapServer)i.next();
450 				writer.write(s);
451 				count++;
452 			}
453 		}
454 		finally {
455 			writer.close();
456 		}
457 
458 		return count;
459     }	
460 
461 	/***
462 	 * Sets the interval for the auto fetch task. 
463 	 *
464 	 * @param interval the auto fetch interval in milli seconds; if <= 0,
465 	 * auto fetching is disabled */
466 	public synchronized void setAutoFetchInterval(long interval)
467 	{
468 		if (interval <= 0) {
469 			if (autoFetchTask != null) {
470 				autoFetchTask.cancel();
471 				autoFetchTask = null;
472 			}
473 		}
474 		else {
475 			autoFetchTask = new AutoFetchTask();
476 			Scheduler.run(0, interval, autoFetchTask);
477 		}
478 	}
479 	
480 	/***
481 	 * Invoked by {@link OpenNapServer} objects once their state
482 	 * changes to connected.  */
483     void setConnected(OpenNapServer server, boolean connected)
484     {
485 		synchronized (connectedServers) {
486 			synchronized (this) {
487 				if (connected) {
488 					connectedServers.add(server);
489 					Thread t 
490 						= new Thread(new PostLoginRunner(server), "PostLogin");
491 					t.start();
492 				}
493 				else {
494 					connectedServers.remove(server);
495 				}
496 			}
497 
498 			int size = connectedServers.size();
499 			if (size == 1) {
500 				SearchManager.getInstance().add
501 					(OpenNapPlugin.getSearchManager());
502 			}
503 			else if (size == 0) {
504 				SearchManager.getInstance().remove
505 					(OpenNapPlugin.getSearchManager());
506 			}
507 			
508 			if (!resumed 
509 				&& napPrefs.getAutoResumeDownloads() 
510 				&& size == napPrefs.getAutoResumeConnectedCount()) {
511 
512 				resumed = true;
513 				OpenNapPlugin.getTransferManager().startAllDownloads();
514 			}
515 		}
516 
517 		updateStats();
518     }
519     
520     public void propertyChange(PropertyChangeEvent e)
521     {
522 		String p = e.getPropertyName();
523 
524 		if (p.equals("stats")) {
525 			updateStats();
526 		}
527 		else if (p.equals("firewalled") || p.equals("localPort")) {
528 			updateListener();
529 		}
530 		else if (p.equals("autoFetchNapigator") 
531 				 || p.equals("autoFetchNapigatorInterval")) {
532 			updateAutoFetch();
533 		}
534 	}
535 	
536 	private void updateAutoFetch()
537 	{
538 		setAutoFetchInterval
539 			(napPrefs.getAutoFetchNapigator()
540 			 ? napPrefs.getAutoFetchNapigatorInterval() * 60 * 60 * 1000
541 			 : -1);
542 	}
543 
544     private void updateListener()
545     {
546 		if (napPrefs.getFirewalled()) {
547 			listener.setPortRange(null);
548 		}
549 		else {
550 			PortRange range = new PortRange(napPrefs.getLocalPortRange());
551 			listener.setPortRange(range);
552 			if (listener.getPort() == 0) {
553 		  		logger.info(XNap.tr("Could not start listener (check local port)"));
554 			}
555 		}
556     }
557 
558     /***
559      * Iterates through all servers and notifies the stats listeners.
560      */
561     private synchronized void updateStats()
562     {
563 		long userCount = 0;
564 		long fileCount = 0;
565 		long fileSize = 0;
566 
567 		if (connectedServers.size() > 0) {
568 			for (Iterator i = connectedServers.iterator(); i.hasNext();) {
569 				OpenNapServer s = (OpenNapServer)i.next();
570 				userCount += s.getUserCount();
571 				fileCount += s.getFileCount();
572 				fileSize += s.getFileSize();
573 			}
574 	    
575 			// gb -> byte
576 			fileSize = fileSize * 1024 * 1024 * 1024;
577 			StringBuffer sb = new StringBuffer();
578 			sb.append(Formatter.formatNumber(connectedServers.size()));
579 			sb.append(" " + XNap.tr("of") + " ");
580 			sb.append(Formatter.formatNumber(servers.size()));
581 			sb.append(" " + XNap.tr("Servers") + " / ");
582 			sb.append(Formatter.formatNumber(userCount));
583 			sb.append(" " + XNap.tr("Users") + " / ");
584 			sb.append(Formatter.formatNumber(fileCount));
585 			sb.append(" " + XNap.tr("Files") + " / ");
586 			sb.append(Formatter.formatSize(fileSize));
587 			sb.append(" " + XNap.tr("Shared"));
588 			stats = sb.toString();
589 		}
590 		else {
591 			stats = XNap.tr("{0} Servers (Not Connected)", 
592 							new Integer(servers.size()));
593 		}
594 
595 		for (Iterator i = sl.iterator(); i.hasNext();) {
596 			((StatusListener)i.next()).setStatus(stats);
597 		}
598     }
599 
600 	/***
601 	 * Spin-locks until library is read.  */
602 	private void waitUntilLibraryIsRead()
603 	{
604 		while (!Library.getInstance().isRead()) {
605 			try {
606 				Thread.sleep(512);
607 			}
608 			catch (InterruptedException e) {
609 				return;
610 			}
611 		}
612 	}
613 
614     //--- Inner Class(es) ---
615 
616 	private class InitRunner implements Runnable
617     {
618 
619 		public void run() 
620 		{
621 			try {
622 				String filename = napPrefs.getServerFile();
623 				addFrom(new OpenNapServerFileReader(filename), false);
624 			}
625 			catch (IOException e) {
626 				logger.debug("Could not add hosts from file" , e); 
627 			}
628 			if (napPrefs.getAutoLoadNapigator()) {
629 				try {
630 					String filename = napPrefs.getNapigatorFile();
631 					addFrom(new OpenNapServerFileReader(filename), true);
632 				}
633 				catch (IOException e) {
634 					logger.debug("Could not add hosts from file" , e);
635 				}
636 			}
637 
638 			updateAutoFetch();
639 		}
640     }
641     
642     private class ServerIterator {
643 
644 		private int start;
645 		private boolean looped;
646 		private int next = 0;
647 
648 		/***
649 		 * This needs to called prior to each cycle.
650 		 */
651 		public void init() 
652 		{
653 			start = next;
654 			looped = false;
655 		}
656 
657 		/***
658 		 * Called by AutoConnector to cycle through servers.
659 		 */
660 		public OpenNapServer getNext()
661 		{
662 			synchronized (OpenNapServerManager.this) {
663 				if (servers.isEmpty()) {
664 					return null;
665 				}
666 
667 				if (next > servers.size()) {
668 					if (looped) {
669 						return null;
670 					}
671 
672 					if (start > servers.size() - 1) {
673 						start = servers.size() - 1;
674 					}
675 					next = 0;
676 					looped = true;
677 				}
678 	    
679 				int index = next;
680 
681 				next++;
682 				if (next >= servers.size()) {
683 					next = 0;
684 					looped = true;
685 				}
686 				if (looped && next >= start) {
687 					return null;
688 				}
689 
690 				return (OpenNapServer)servers.get(index);
691 			}
692 		}
693     }
694 
695     public class AutoConnector implements Runnable
696     {
697 
698 		private boolean die = false;
699 		private boolean enabled = false;
700 		private Thread runner;
701 		private ServerIterator iterator = new ServerIterator();
702 
703 		void die()
704 		{
705 			die = true;
706 			synchronized (this) {
707 				this.notify();
708 			}
709 		}
710 
711 		public synchronized boolean isEnabled()
712 		{
713 			return enabled;
714 		}
715 
716 		public synchronized void setEnabled(boolean newValue)
717 		{
718 			enabled = newValue;
719 	
720 			if (enabled) {
721 				if (runner != null) {
722 					wakeup();
723 				}
724 				else {
725 					runner = new Thread(this, "OpenNapConnector");
726 					runner.start();
727 				}
728 			}
729 		}
730 
731 		public void wakeup()
732 		{
733 			if (isEnabled()) {
734 				synchronized (this) {
735 					this.notify();
736 				}
737 			}
738 		}
739 
740 		/***
741 		 * Auto connects servers.
742 		 */
743 		public void run() 
744 		{
745 			waitUntilLibraryIsRead();
746 
747 			while (!die) {
748 				int left = 2 * (napPrefs.getMaxAutoconnectServers()
749 								- connectedServers.size());
750 				left -= OpenNapNetwork.getTotalConnecting();
751 
752 				iterator.init();
753 
754 				OpenNapServer s;		
755 				while ((s = iterator.getNext()) != null && left > 0
756 					   && enabled) {
757 					if (!s.getNetwork().isBusy() && s.isDisconnected()) {
758 						long t = s.getNextAutoConnectTime();
759 						if (t >= 0 && System.currentTimeMillis() >= t) {
760 							s.connect();
761 							left--;
762 						}
763 					}
764 				}
765 		    
766 				synchronized (this) {
767 					try {
768 						if (enabled) {
769 							this.wait(OpenNapServer.FAILED_INTERVAL);
770 						}
771 						else {
772 							this.wait();
773 						}
774 					}
775 					catch (InterruptedException e) {
776 					}
777 				}
778 			}
779 		}
780 	
781     }
782 
783     public class PostLoginRunner implements Runnable, ExceptionListener {
784 
785 		OpenNapServer server;
786 		boolean die;
787 
788 		public PostLoginRunner(OpenNapServer server)
789 		{
790 			this.server = server;
791 		}
792 
793 		public void exceptionThrown(Exception e)
794 		{
795 			die = true;
796 		}
797 
798 		public void run()
799 		{
800 			sendHotlist();
801 			shareFiles();
802 		}
803 	
804 		public void sendHotlist()
805 		{
806 			// add hotlist users
807 			OpenNapGlobalUser[] users
808 				= OpenNapPlugin.getUserManager().getHotlistUsers();
809 			for (int i = 0; i < users.length && !die; i++) {
810 				AddHotlistEntryMessage msg 
811 					= new AddHotlistEntryMessage(users[i].getName());
812 				msg.setExceptionListener(this);
813 				MessageHandler.send(server, msg);
814 			}
815 		}
816 
817 		public void shareFiles()
818 		{
819 			waitUntilLibraryIsRead();
820 
821 			int size = Library.getInstance().size();
822 			if (size == 0) {
823 				return;
824 			}
825 
826 			// share files
827 			if (napPrefs.getLimitSharesPerServer()) {
828 				boolean looped = false;
829 				int toShare = napPrefs.getMaxSharesPerServer();
830 				int start;
831 				int next;
832 
833 				synchronized(OpenNapServerManager.this) {
834 					if (repositoryIndex >= size) {
835 						repositoryIndex = 0;
836 					}
837 					start = repositoryIndex;
838 					next = start;
839 					repositoryIndex += toShare;
840 				}
841 
842 				while (toShare > 0 && !die) {
843 					if (shareFile(next)) {
844 						toShare--;
845 					}
846 					next++;
847 					if (next >= size) {
848 						server.setShared(new Range(start, size - 1));
849 
850 						next = 0;
851 						looped = true;
852 					}
853 					if (next >= start && looped) {
854 						break;
855 					}
856 				}
857 				
858 				if (looped) {
859 					if (next > 0) {
860 						server.setShared(new Range(0, next - 1));
861 					}
862 				}
863 				else {
864 					server.setShared(new Range(start, next - 1));
865 				}
866 				
867 				synchronized(OpenNapServerManager.this) {
868 					repositoryIndex = next;
869 				}
870 			}
871 			else {
872 				for (int i = 0; i < size; i++) {
873 					shareFile(i);
874 				}
875 				server.setShared(new Range(0, size - 1));
876 			}
877 		}
878     
879 		/***
880 		 * Returns the number of files that have been shared.
881 		 *
882 		 * @return -1, if server disconnected
883 		 */
884 		public boolean shareFile(int index)
885 		{
886 			MetaInfoFile f = Library.getInstance().get(index);
887 			if (f != null && f.isShared()) {
888 				MetaInfoManager.handle(f);
889 				
890 				ShareFileMessage msg = new ShareFileMessage(index, f);
891 				msg.setExceptionListener(this);
892 				MessageHandler.send(server, msg);
893 
894 				return true;
895 			}
896 			return false;
897 		}
898 	
899     }
900 
901 	private class AutoFetchTask extends XNapTask {
902 
903 		public AutoFetchTask()
904 		{
905 		}
906 
907 		public void run() 
908 		{
909 			fetchServerLists();
910 		}
911 
912 	}
913 
914 	//      public synchronized void elementAdded(ListEvent e)
915 	//      {
916 	//  	if (e.getSource() == Repository.getInstance()) {
917 	//  	    if (!napPrefs.getLimitSharesPerOpenNapServer()) {
918 	//  		RepositoryFile f = (RepositoryFile)e.getElement();
919 	//  		MessageHandler.send(new ShareFileMessage(e.getIndex(), f));
920 	//  	    }
921 	//  	}
922 	//      }
923 
924 	//      public synchronized void elementRemoved(ListEvent e)
925 	//      {
926 	//  	if (e.getSource() == Repository.getInstance()) {
927 	//  	    // FIX ME: check if file is really shared
928 	//  	    RepositoryFile f = (RepositoryFile)e.getElement();
929 	//  	    MessageHandler.send(new UnshareFileMessage(e.getIndex(), f));
930 	//  	}
931 	//      }
932 
933 }