package edu.washington.cs.oneswarm.ui.gwt.server.community; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import javax.servlet.http.HttpServletResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.gudy.azureus2.core3.download.DownloadManager; import org.gudy.azureus2.core3.torrent.TOTorrent; import org.gudy.azureus2.core3.torrent.TOTorrentAnnounceURLSet; import org.gudy.azureus2.core3.torrent.TOTorrentException; import org.gudy.azureus2.core3.torrent.TOTorrentFactory; import org.gudy.azureus2.core3.util.BEncoder; import org.gudy.azureus2.core3.util.HashWrapper; import org.gudy.azureus2.plugins.download.Download; import org.gudy.azureus2.plugins.torrent.Torrent; import com.aelitis.azureus.core.impl.AzureusCoreImpl; import edu.washington.cs.oneswarm.ui.gwt.BackendErrorLog; import edu.washington.cs.oneswarm.ui.gwt.CoreInterface; import edu.washington.cs.oneswarm.ui.gwt.rpc.BackendTask; import edu.washington.cs.oneswarm.ui.gwt.rpc.CommunityRecord; import edu.washington.cs.oneswarm.ui.gwt.rpc.TorrentInfo; import edu.washington.cs.oneswarm.ui.gwt.server.BackendTaskManager; import edu.washington.cs.oneswarm.ui.gwt.server.OneSwarmHashUtils; import edu.washington.cs.oneswarm.ui.gwt.server.PreviewImageGenerator; public class PublishSwarmsThread extends Thread { private static Logger logger = Logger.getLogger(PublishSwarmsThread.class.getName()); private CommunityRecord toServer; private String[] previewPaths; private TorrentInfo[] infos; private boolean cancelled = false; private BackendTask task = null; private String[] comments; private CoreInterface coreInterface; private String[] categories; public PublishSwarmsThread(CoreInterface coreInterface, TorrentInfo[] infos, String[] previewPaths, String[] comments, String[] categories, CommunityRecord toServer) { this.coreInterface = coreInterface; this.infos = infos; this.previewPaths = previewPaths; this.toServer = toServer; this.comments = comments; this.categories = categories; } public void cancel() { cancelled = true; } static class ConversionException extends IOException { public ConversionException(String s) { super(s); } } public void run() { if (task != null) { task.setSummary("Preparing..."); } try { /** * First convert all the preview images to max 800x800 (also makes * sure they are all image data!) */ List<File> converted = new ArrayList<File>(); for (int pathItr = 0; pathItr < previewPaths.length; pathItr++) { String path = previewPaths[pathItr]; if (cancelled) { return; } File scratchFile = null; FileOutputStream scratch = null; try { if (path != null && path.length() > 0) { scratchFile = File.createTempFile("osul", "png"); scratchFile.deleteOnExit(); scratch = new FileOutputStream(scratchFile); PreviewImageGenerator.previewImageForArbitraryPath(path, 800, scratch); scratch.flush(); scratch.close(); } else { Download download = coreInterface .getDownload(infos[pathItr].getTorrentID()); if (download == null) { scratchFile = null; throw new ConversionException("null download"); } try { scratchFile = coreInterface.getImageFile(download); } catch (Exception e) { logger.warning("Error during preview grab during publish: " + e.toString()); throw new ConversionException("Error during preview grab: " + e.toString()); } if (scratchFile == null) { throw new ConversionException("null scratchFile"); } if (scratchFile.exists() == false) { scratchFile = null; throw new ConversionException("scratchFile doesn't exist"); } } } catch (ConversionException e) { logger.warning("Conversion exception: " + e.toString()); } converted.add(scratchFile); } /** * Now submit form requests for each */ for (int swarmItr = 0; swarmItr < infos.length; swarmItr++) { if (cancelled) { return; } TorrentInfo swarm = infos[swarmItr]; File previewFile = converted.get(swarmItr); String commentStr = comments[swarmItr]; String categoryStr = categories[swarmItr]; /** * Next, assemble the form post, comprised of the torrents, * previews, and comments */ // DefaultHttpClient httpclient = new DefaultHttpClient(); // // httpclient.getParams().setParameter(HttpProtocolParams.USER_AGENT, // Constants.AZUREUS_NAME + "/" + Constants.AZUREUS_VERSION); // if( toServer.isAuth_required() ) { // final Credentials creds = new // UsernamePasswordCredentials(toServer.getUsername(), // toServer.getPw()); // httpclient.setCredentialsProvider(new CredentialsProvider(){ // public void clear() {} // public Credentials getCredentials(AuthScope arg0) { // return creds; // } // public void setCredentials(AuthScope arg0, Credentials arg1) // {}}); // } String theURLString = CommunityServerOperation.getCommunityBase(new URL(toServer .getUrl())) + "/" + toServer.getSupports_publish(); HttpPost httppost = new HttpPost(theURLString); MultipartEntity reqEntity = new MultipartEntity(); if (commentStr != null) { StringBody comment = new StringBody(commentStr); reqEntity.addPart("commentstr", comment); } if (categoryStr != null) { StringBody category = new StringBody(categoryStr); reqEntity.addPart("categorystr", category); } DownloadManager dm = AzureusCoreImpl .getSingleton() .getGlobalManager() .getDownloadManager( new HashWrapper(OneSwarmHashUtils.bytesFromOneSwarmHash(swarm .getTorrentID()))); File scratchFile = File.createTempFile("osul", ".torrent"); FileOutputStream scratch = new FileOutputStream(scratchFile); serializeForPublishing(dm.getTorrent(), scratch); logger.finer("Torrent path: " + scratchFile.getAbsolutePath()); FileBody bin = new FileBody(new File(scratchFile.getAbsolutePath())); reqEntity.addPart("torrentbin", bin); if (previewFile != null) { bin = new FileBody(previewFile); reqEntity.addPart("previewpng", bin); } httppost.setEntity(reqEntity); logger.fine("executing request " + httppost.getRequestLine()); if (task != null) { task.setProgress((swarmItr + 1) + "/" + infos.length); task.setSummary("Uploading... "); } // HttpResponse response = httpclient.execute(httppost); // HttpEntity resEntity = response.getEntity(); /** * We need to use HttpURLConnection instead of HttpClient to * ensure the use of our SSL security handlers, which are * adapted to accept community-server style certificates. */ URL url = new URL(theURLString); Map<String, String> extraHeaders = new HashMap<String, String>(); /** * Transmoprh this connection to line up with the post. */ extraHeaders.put("Content-Type", httppost.getEntity().getContentType().getValue()); extraHeaders.put("Content-Length", httppost.getEntity().getContentLength() + ""); HttpURLConnection conn = CommunityServerOperation.getConnection(url, "POST", toServer.isAuth_required(), toServer, extraHeaders); /** * Copy everything */ httppost.getEntity().writeTo(conn.getOutputStream()); if (conn.getResponseCode() == HttpServletResponse.SC_UNAUTHORIZED) { StringBuilder err = new StringBuilder(); err.append("Server does not permit publishing from this account."); if (toServer.isAuth_required() == false) { err.append(" Many community servers require an account to publish. If you have an account, enter your username and password in the settings. "); } else { err.append(" Check that you have a valid account with the server and that you have entered your username and password correctly. "); } err.append("\r\n\r\n (" + (toServer.getServer_name() == null ? toServer.getUrl() : toServer .getServer_name()) + ")"); throw new IOException(err.toString()); } if (conn.getResponseCode() != HttpServletResponse.SC_OK) { throw new IOException( "Server responded with bad status code: " + conn.getResponseCode() + (conn.getResponseCode() == HttpServletResponse.SC_CONFLICT ? " Duplicate entry -- this file has already been published at this community server" : "")); } } task.setSummary("Publish complete. " + infos.length); task.setShortname("Publish complete."); logger.finer("Publish complete: " + infos.length); Thread.sleep(7 * 1000); BackendTaskManager.get().removeTask(task.getTaskID()); logger.finest("Removed task"); BackendErrorLog .get() .logString( "Publish succeeded. Note that your swarm will not appear immediately on community servers that require moderation.", false); } catch (Exception e) { e.printStackTrace(); logger.warning(e.toString()); if (task != null) { task.setGood(false); task.setProgress("100"); task.setSummary("An error occurred: " + e.toString()); try { Thread.sleep(7 * 1000); } catch (Exception e2) { } BackendTaskManager.get().removeTask(task.getTaskID()); BackendErrorLog.get().logString("Publishing failed: " + e.getMessage(), false); } } } private static void serializeForPublishing(TOTorrent torrent, OutputStream scratch) throws IOException, TOTorrentException { TOTorrent clone = TOTorrentFactory.deserialiseFromMap(torrent.serialiseToMap()); if (clone.getPrivate()) { String replaceWithUrl = "http://tracker.removed.invalid/announce"; clone.setAnnounceURL(new URL(replaceWithUrl)); clone.getAnnounceURLGroup().setAnnounceURLSets(new TOTorrentAnnounceURLSet[0]); } clone.removeAdditionalProperties(); Map root = clone.serialiseToMap(); scratch.write(BEncoder.encode(root)); } public void associateTask(BackendTask task) { this.task = task; } }