package edu.washington.cs.oneswarm.ui.gwt; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.Semaphore; import org.bouncycastle.util.encoders.Base64; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.HashWrapper; import org.gudy.azureus2.plugins.PluginInterface; import org.gudy.azureus2.plugins.ipc.IPCException; import org.gudy.azureus2.plugins.ipc.IPCInterface; import edu.washington.cs.oneswarm.f2f.FileCollection; import edu.washington.cs.oneswarm.f2f.FileList; import edu.washington.cs.oneswarm.f2f.FileListFile; import edu.washington.cs.oneswarm.f2f.Friend; import edu.washington.cs.oneswarm.f2f.FriendConnectListener; import edu.washington.cs.oneswarm.f2f.FriendInvitation; import edu.washington.cs.oneswarm.f2f.TextSearchResult; import edu.washington.cs.oneswarm.f2f.share.ShareManagerTools; import edu.washington.cs.oneswarm.plugins.PluginCallback; import edu.washington.cs.oneswarm.ui.gwt.rpc.FileListLite; import edu.washington.cs.oneswarm.ui.gwt.rpc.FriendInfoLite; import edu.washington.cs.oneswarm.ui.gwt.server.FriendInfoLiteFactory; public class F2FInterface { private IPCInterface f2fIpc; public F2FInterface(final PluginInterface pi) { PluginInterface f2fIf = pi.getPluginManager().getPluginInterfaceByID("osf2f"); if (f2fIf != null && f2fIf.isOperational()) { f2fIpc = f2fIf.getIPC(); } else { Debug.out("Friend to friend plugin not available yet, will try again later"); Thread t = new Thread(new Runnable() { public void run() { try { int tryNum = 1; while (f2fIpc == null) { Thread.sleep(2000); Debug.out("trying to load f2f stuff again, try num=" + tryNum); PluginInterface f2fIf = pi.getPluginManager().getPluginInterfaceByID( "osf2f"); if (f2fIf != null && f2fIf.isOperational()) { f2fIpc = f2fIf.getIPC(); } else { Debug.out("Friend to friend plugin not available, trynum=" + tryNum + " failed! " + f2fIf); } tryNum++; } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); t.setDaemon(true); t.start(); } } public boolean f2fPluginLoaded() { return f2fIpc != null; } public FriendInfoLite[] getFriends() { return getFriends(true, true); } // public FriendInfoLite[] getOnlineFriends() { // return getFriends(true, false); // } @SuppressWarnings("unchecked") public FriendInfoLite[] getFriends(boolean includeDisconnected, boolean includeBlocked) { if (f2fIpc != null) { try { List<Friend> friends = (List<Friend>) f2fIpc.invoke("getFriends", new Object[0]); List<FriendInfoLite> selectedFriends = new LinkedList<FriendInfoLite>(); for (Friend f : friends) { if (!f.isBlocked() || includeBlocked) switch (f.getStatus()) { case Friend.STATUS_OFFLINE: if (includeDisconnected) { selectedFriends.add(FriendInfoLiteFactory.createFriendInfo(f)); } break; case Friend.STATUS_CONNECTING: if (includeDisconnected) { selectedFriends.add(FriendInfoLiteFactory.createFriendInfo(f)); } break; case Friend.STATUS_HANDSHAKING: selectedFriends.add(FriendInfoLiteFactory.createFriendInfo(f)); break; case Friend.STATUS_ONLINE: selectedFriends.add(FriendInfoLiteFactory.createFriendInfo(f)); break; } } return selectedFriends.toArray(new FriendInfoLite[selectedFriends.size()]); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return new FriendInfoLite[0]; } public int addFriend(Friend f) { if (f2fIpc != null) { try { return (Integer) f2fIpc.invoke("addFriend", new Object[] { f }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); return -1; } } return 0; } public void connectToFriend(String friendsPublicKey) { if (f2fIpc != null) { try { f2fIpc.invoke("connectToFriend", new Object[] { friendsPublicKey }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void disconnectFriend(Friend inFriend) { if (f2fIpc != null) { try { f2fIpc.invoke("disconnectFriend", new Object[] { inFriend }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void sendChatMessage(Friend inFriend, String inPlaintext) { if (f2fIpc != null) { try { f2fIpc.invoke("sendChatToFriend", new Object[] { inFriend, inPlaintext }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public Friend getFriend(String friendsPublicKey) { if (f2fIpc != null) { try { return (Friend) f2fIpc.invoke("getFriend", new Object[] { friendsPublicKey }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } return null; } public String getMyPublicKey() { if (f2fIpc != null) { try { return (String) f2fIpc.invoke("getMyPublicKey", new Object[0]); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } return null; } public String getGtalkStatus() { if (f2fIpc != null) { try { return (String) f2fIpc.invoke("getGtalkStatus", new Object[0]); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } return null; } /** * Blocking method * * @param connectionId * @param filter * @param startNum * @param num * @return */ public List<FileListLite> getFileList(int connectionId, String filter, int startNum, int num, long maxCacheAge) { // array of pointers to FileList final FileList[] result = new FileList[1]; final Semaphore resultWaiter = new Semaphore(0); PluginCallback<FileList> callback = new PluginCallback<FileList>() { public void dataRecieved(long bytes) { } public void errorOccured(String e) { throw new RuntimeException("An error occured: " + e); } public void progressUpdate(int progress) { } public void requestCompleted(FileList data) { result[0] = data; resultWaiter.release(); } }; if (f2fIpc != null) { try { f2fIpc.invoke("sendFileListRequest", new Object[] { connectionId, maxCacheAge, callback }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } try { System.out.println("F2F interface waiting for FileList"); resultWaiter.acquire(); if (result == null) { throw new RuntimeException("F2F interface got FileList list = null"); } System.out.println("F2F interface got FileList list len=" + result[0].getFileNum()); FileList filtered; if (filter.equals("")) { filtered = result[0]; } else { filtered = result[0].searchMatches(filter); System.out.println("filtering for '" + filter + "' got " + filtered.getFileNum() + " matches"); } List<FileListLite> converted = convertFileList(filtered); // return converted.subList(startNum, Math.min(startNum + num, // converted.size())); return groupAwareSubList(converted, startNum, num); } catch (InterruptedException e) { throw new RuntimeException("interupted during filelist request"); } } private List<FileListLite> groupAwareSubList(List<FileListLite> inRawFilesList, int inStartGroup, int inMaxGroups) { int skippedGroups = 0; String lastSkippedID = ""; int addedGroups = 0; String lastAddedID = ""; boolean adding = false; List<FileListLite> outList = new ArrayList<FileListLite>(); for (int fileItr = 0; fileItr < inRawFilesList.size(); fileItr++) { FileListLite f = inRawFilesList.get(fileItr); if (skippedGroups < inStartGroup) { /** * hopefully the files list is grouped... (this should work * otherwise, but will be weird) */ if (lastSkippedID.equals(f.getCollectionId()) == false) { lastSkippedID = f.getCollectionId(); skippedGroups++; } } else { if (f.getCollectionId().equals(lastSkippedID) && !adding) // adding // is // in // case // list // is // not // sorted // by // group { continue; // need to finish skipping everything here... } else { adding = true; } if (lastAddedID.equals(f.getCollectionId()) == false) { lastAddedID = f.getCollectionId(); addedGroups++; } if (addedGroups > inMaxGroups) break; outList.add(f); } } return outList; } private static List<FileListLite> convertFileList(FileList fileList) { List<FileListLite> converted = new ArrayList<FileListLite>(); // int totalFiles = (int)fileList.getFileNum(); int totalGroups = fileList.getElements().size(); for (FileCollection collection : fileList.getElements()) { String collectionName = collection.getName(); String collectionId = collection.getUniqueID(); List<FileListFile> files = collection.getChildren(); for (FileListFile file : files) { FileListLite fll = new FileListLite(collectionId, collectionName, file.getFileName(), file.getLength(), collection.getFileNum(), collection.getAddedTimeUTC(), totalGroups, false, false); if (file.getSha1Hash() != null) { fll.setSha1Hash(new String(Base64.encode(file.getSha1Hash()))); } if (file.getEd2kHash() != null) { fll.setEd2kHash(new String(ShareManagerTools.base16Encode(file.getEd2kHash()))); } converted.add(fll); } } return converted; } public void getMetaInfo(int connectionId, int channelId, String torrentId, int lengthHint, PluginCallback<byte[]> callback) { if (f2fIpc != null) { try { // if the length of the infohash is known we can speed up things // one rtt, -1 means not known f2fIpc.invoke("sendMetaInfoRequest", new Object[] { connectionId, channelId, Base64.decode(torrentId), lengthHint, callback }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); callback.errorOccured(e.getMessage()); } } } // /** // * Blocking // * // * @param connectionId // * @param channelId // * @param lengthHint // * @param torrentId // * @return // */ // public byte[] getMetaInfo(int connectionId, int channelId, String // torrentId, int lengthHint) { // // // array of pointers to FileList // final byte[][] result = new byte[1][0]; // final Semaphore resultWaiter = new Semaphore(0); // // PluginCallback<byte[]> callback = new PluginCallback<byte[]>() { // public void dataRecieved(long bytes) { // } // // public void errorOccured(String error) { // resultWaiter.release(); // } // // public void progressUpdate(int progress) { // } // // public void requestCompleted(byte[] data) { // result[0] = data; // resultWaiter.release(); // } // }; // // this.getMetaInfo(connectionId, channelId, torrentId, lengthHint, // callback); // // try { // System.out.println("F2F interface waiting metainfo"); // resultWaiter.acquire(); // if (result != null) { // System.out.println("F2F interface got metainfo len=" + result[0].length); // return result[0]; // } else { // System.out.println("F2F interface got null metainfo!"); // } // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // // return null; // // } public void setTorrentPrivacy(byte[] infohash, boolean publicNet, boolean f2fNet) { if (f2fIpc != null) { try { f2fIpc.invoke("setTorrentPrivacy", new Object[] { infohash, publicNet, f2fNet }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public boolean isSharedWithPublic(byte[] infohash) { if (f2fIpc != null) { try { return (Boolean) f2fIpc.invoke("isSharedWithPublic", new Object[] { infohash }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return true; } public boolean isSharedWithFriends(byte[] infohash) { if (f2fIpc != null) { try { return (Boolean) f2fIpc.invoke("isSharedWithFriends", new Object[] { infohash }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return true; } public int sendSearch(String search) { if (f2fIpc != null) { try { return (Integer) f2fIpc.invoke("sendTextSearch", new Object[] { search }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return -1; } @SuppressWarnings("unchecked") public List<TextSearchResult> getSearchResult(int searchId) { if (f2fIpc != null) { try { return (List<TextSearchResult>) f2fIpc.invoke("getTextSearchResult", new Object[] { searchId }); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return new ArrayList<TextSearchResult>(); } @SuppressWarnings("unchecked") public HashMap<String, String>[] getTransferStats() { if (f2fIpc != null) { try { return (HashMap<String, String>[]) f2fIpc.invoke("getTransferStats", new Object[0]); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return new HashMap[0]; } public String[] getSupportedXMPPNetworks() { if (f2fIpc != null) { try { return (String[]) f2fIpc.invoke("getSupportedXMPPNetworks", new Object[0]); } catch (IPCException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return new String[0]; } @SuppressWarnings("unchecked") public FriendInfoLite[] getNewUsersFromXMPP(String xmppNetworkName, String username, char[] password, String machineName) throws Exception { List<Friend> friends = (List<Friend>) f2fIpc.invoke("getNewUsersFromXMPP", new Object[] { xmppNetworkName, username, password, machineName }); if (friends == null) { return null; } FriendInfoLite[] fLite = new FriendInfoLite[friends.size()]; for (int i = 0; i < fLite.length; i++) { Friend f = friends.get(i); fLite[i] = FriendInfoLiteFactory.createFriendInfo(f); } return fLite; } public void setFriendSettings(String publicKey, String nickname, boolean blocked, boolean canSeeFileList, boolean allowChat, boolean requestFileList, String group) { if (group == null) { group = ""; } System.out.println(publicKey + " " + nickname + " " + blocked + " " + canSeeFileList + " " + allowChat); if (f2fIpc != null) { try { f2fIpc.invoke("setFriendSettings", new Object[] { publicKey, nickname, blocked, canSeeFileList, allowChat, requestFileList, group }); } catch (IPCException e) { e.printStackTrace(); } } } @SuppressWarnings("unchecked") public Map<Friend, FileList> getOnlineFileLists() { if (f2fIpc != null) { try { Map<Friend, FileList> f = (Map<Friend, FileList>) f2fIpc.invoke( "getOnlineFileLists", new Object[0]); return f; } catch (IPCException e) { e.printStackTrace(); } } return new HashMap<Friend, FileList>(); } public void registerForFriendConnectNotifications(FriendConnectListener callback) { if (f2fIpc != null) { try { f2fIpc.invoke("registerForFriendConnectNotifications", new Object[] { callback }); } catch (IPCException e) { e.printStackTrace(); } } } @SuppressWarnings("unchecked") public FriendInfoLite[] getLanOneSwarmUsers() { try { List<Friend> friends = (List<Friend>) f2fIpc.invoke("getLanOneSwarmUsers", new Object[] {}); if (friends == null) { return null; } FriendInfoLite[] fLite = new FriendInfoLite[friends.size()]; for (int i = 0; i < fLite.length; i++) { Friend f = friends.get(i); fLite[i] = FriendInfoLiteFactory.createFriendInfo(f); } return fLite; } catch (IPCException e) { return null; } } @SuppressWarnings("unchecked") public HashMap<String, String> getDeniedIncomingConnections() { try { HashMap<byte[], String> connections = (HashMap<byte[], String>) f2fIpc.invoke( "getDeniedIncomingConnections", new Object[] {}); HashMap<String, String> withBase64 = new HashMap<String, String>(); for (byte[] pubkey : connections.keySet()) { withBase64.put(new String(Base64.encode(pubkey)), (connections.get(pubkey))); } return withBase64; } catch (IPCException e) { e.printStackTrace(); return new HashMap<String, String>(); } } @SuppressWarnings("unchecked") public Map<String, Integer> getNewFriendsCountsFromAutoCheck() { try { Map<String, Integer> counts = (Map<String, Integer>) f2fIpc.invoke( "getNewFriendsCountsFromAutoCheck", new Object[] {}); return counts; } catch (IPCException e) { e.printStackTrace(); return new HashMap<String, Integer>(); } } public void deleteFriend(FriendInfoLite friend) { try { f2fIpc.invoke("deleteFriend", new Object[] { friend.getPublicKey() }); } catch (IPCException e) { e.printStackTrace(); } } public void stopTransfers() { try { f2fIpc.invoke("stopTransfers", new Object[0]); } catch (IPCException e) { e.printStackTrace(); } } public void restartTransfers() { try { f2fIpc.invoke("restartTransfers", new Object[0]); } catch (IPCException e) { e.printStackTrace(); } } public void addToIgnoreRequestList(FriendInfoLite friend) { try { f2fIpc.invoke("addToIgnoreRequestList", new Object[] { friend.getPublicKey() }); } catch (IPCException e) { e.printStackTrace(); } } public String getDebugInfo() { try { return (String) f2fIpc.invoke("getDebugInfo", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); return "error: " + e.getMessage(); } } public String getDebugMessageLog(String friendPublicKey) { try { return (String) f2fIpc.invoke("getDebugMessageLog", new Object[] { friendPublicKey }); } catch (IPCException e) { e.printStackTrace(); return "error: " + e.getMessage(); } } public Friend[] scanXMLForFriends(String xml) { try { return (Friend[]) f2fIpc.invoke("scanXMLForFriends", new Object[] { xml }); } catch (IPCException e) { e.printStackTrace(); return null; } } public FriendInvitation createInvitation(String name, boolean canSeeFileList, long maxAge, byte securityLevel) { try { return (FriendInvitation) f2fIpc.invoke("createInvitation", new Object[] { name, canSeeFileList, maxAge, securityLevel }); } catch (IPCException e) { e.printStackTrace(); return null; } } public void redeemInvitation(FriendInvitation invitation, boolean testOnly) throws Exception { f2fIpc.invoke("redeemInvitation", new Object[] { invitation, testOnly }); } public void updateInvitation(FriendInvitation invitation) { try { f2fIpc.invoke("updateInvitation", new Object[] { invitation }); } catch (IPCException e) { e.printStackTrace(); } } public FriendInvitation getInvitation(HashWrapper key) { try { return (FriendInvitation) f2fIpc.invoke("redeemInvitation", new Object[] { key }); } catch (IPCException e) { e.printStackTrace(); return null; } } @SuppressWarnings("unchecked") public List<FriendInvitation> getLocallyCreatedInvitations() { try { return (List<FriendInvitation>) f2fIpc.invoke("getLocallyCreatedInvitations", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); return new LinkedList<FriendInvitation>(); } } @SuppressWarnings("unchecked") public List<FriendInvitation> getRedeemedInvitations() { try { return (List<FriendInvitation>) f2fIpc .invoke("getRedeemedInvitations", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); return new LinkedList<FriendInvitation>(); } } public void deleteInvitation(FriendInvitation invitation) { try { f2fIpc.invoke("deleteInvitation", new Object[] { invitation }); } catch (IPCException e) { e.printStackTrace(); } } public String getSearchDebugLog() { try { return (String) f2fIpc.invoke("getSearchDebugLog", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); } return ""; } public String getLockDebug() { try { return (String) f2fIpc.invoke("getLockDebug", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); } return ""; } public String getForwardQueueLengthDebug() { try { return (String) f2fIpc.invoke("getForwardQueueLengthDebug", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); } return ""; } public int performSpeedCheck() { try { return (Integer) f2fIpc.invoke("performSpeedCheck", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); } return -1; } @SuppressWarnings("unchecked") public HashMap<String, Double> getSpeedCheckResult(int checkId) { try { return (HashMap<String, Double>) f2fIpc.invoke("getSpeedCheckResult", new Object[] { checkId }); } catch (IPCException e) { e.printStackTrace(); } return null; } public void cancelSpeedCheck(int checkId) { try { f2fIpc.invoke("cancelSpeedCheck", new Object[] { checkId }); } catch (IPCException e) { e.printStackTrace(); } } public void triggerNATCheck() { try { f2fIpc.invoke("triggerNATCheck", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); } } @SuppressWarnings("unchecked") public HashMap<String, String> getNatCheckResult() { try { return (HashMap<String, String>) f2fIpc.invoke("getNatCheckResult", new Object[] {}); } catch (IPCException e) { e.printStackTrace(); } return null; } }