package net.pocketmine.forum; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import net.pocketmine.forum.PluginListManager.PluginDownloadInfo; import net.pocketmine.server.ServerUtils; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.Toast; public class DownloadService extends Service { private static class QueueDownload { public int id; public String url; public String path; public String filename; public int updated; public QueueDownload(int id, String url, String path, String filename, int updated) { this.id = id; this.url = url; this.path = path; this.filename = filename; this.updated = updated; } } private Handler handler = new Handler(); private static ArrayList<QueueDownload> downloads = new ArrayList<QueueDownload>(); private static Boolean downloading = false; private static int cid = -1; private static int progress = -1; private static Thread t; private static URLConnection connection; private static BufferedInputStream input; private static Boolean stop = false; public static DownloadService runningService = null; public static final String RECEIVER = "net.pocketmine.forum.download.receiver"; @Override public int onStartCommand(Intent intent, int flags, int startId) { runningService = this; final int id = intent.getIntExtra("id", -1); Log.d("DownloadService", "ID:" + id); if (intent.getBooleanExtra("stop", false)) { if (id == cid) { Log.d("DownloadService", "Stop current"); try { ((HttpURLConnection) connection).disconnect(); stop = true; input.close(); Log.d("DownloadService", "Stopping"); } catch (Exception e) { e.printStackTrace(); } if (downloads.size() <= 0) { stopSelf(); } return START_NOT_STICKY; } Log.d("DownloadService", "Stop other"); for (int i = 0; i < downloads.size(); i++) { if (downloads.get(i).id == id) { downloads.remove(i); } } return START_NOT_STICKY; } final String url = intent.getStringExtra("url"); if (url == null) { Log.e("DownloadService", "Stopping: No URL"); return START_NOT_STICKY; } final String path = intent.getStringExtra("path"); if (path == null) { Log.e("DownloadService", "Stopping: No path"); return START_NOT_STICKY; } final int updated = intent.getIntExtra("updated", -1); final String filename = intent.getStringExtra("filename"); if (downloading) { downloads.add(new QueueDownload(id, url, path, filename, updated)); } else { t = new Thread(new Runnable() { @Override public void run() { download(id, url, path, filename, updated); } }); t.start(); } return START_NOT_STICKY; } private void download(int id, String url, String path, String filename, int updated) { downloading = true; stop = false; Log.d("DownloadService", "Starting..."); cid = id; progress = -1; NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); try { NotificationCompat.Builder builder = new NotificationCompat.Builder( this); builder.setContentTitle("Plugin download") .setContentText("Downloading...") .setSmallIcon(android.R.drawable.stat_sys_download) .setOngoing(true); builder.setProgress(0, 0, true); startForeground(2, builder.build()); manager.notify(2, builder.build()); URL mURL = new URL(url); connection = mURL.openConnection(); int fileLength = connection.getContentLength(); if (!stop) { input = new BufferedInputStream(mURL.openStream()); OutputStream output = new FileOutputStream(path + ".download"); byte data[] = new byte[1024]; long total = 0; int count; int lastProgress = 0; Intent iStart = new Intent(RECEIVER); iStart.putExtra("id", id); iStart.putExtra("type", 0); sendBroadcast(iStart); Log.d("DownloadService", "Started."); while ((count = input.read(data)) != -1) { total += count; int progress = (int) (total * 100 / fileLength); if (progress != lastProgress) { DownloadService.progress = progress; Log.d("DownloadService", "Progress: " + progress); builder.setProgress(100, progress, false) .setContentText(progress + "%"); manager.notify(2, builder.build()); Intent iProgress = new Intent(RECEIVER); iProgress.putExtra("id", id); iProgress.putExtra("type", 1); iProgress.putExtra("progress", progress); sendBroadcast(iProgress); lastProgress = progress; } output.write(data, 0, count); } output.flush(); output.close(); input.close(); PluginDownloadInfo info = PluginListManager.getPluginInfo(id); if(info != null){ // we are updating! // first of all, deinstall the plugin ArrayList<String> files = info.files; if (files != null) { for (int i = 0; i < files.size(); i++) { File f = new File(ServerUtils.getDataDirectory() + "/plugins/" + files.get(i)); if (f.exists()) f.delete(); } } // Deinstall from db - in case everything fails - user doesn't have a broken entry! PluginListManager.removePlugin(info); } int iof = path.indexOf("."); Boolean installAsIs = true; ArrayList<String> files = null; if (iof != -1) { String ext = path.substring(iof); if (ext.equals(".php") || ext.equals(".pmf") || ext.equals(".phar")) { installAsIs = true; } else if (ext.equals(".zip")) { installAsIs = false; // it will extract all .pmf/.php into plugins/ files = new ArrayList<String>(); filename += ".download"; String zipFileName = path + ".download"; // ZipFile zip = new ZipFile(zipFileName); FileInputStream fin = new FileInputStream(zipFileName); ZipInputStream zin = new ZipInputStream(fin); ZipEntry ze = null; String loc = ServerUtils.getDataDirectory() + "/plugins/"; while ((ze = zin.getNextEntry()) != null) { if (!ze.isDirectory()) { String zeName = ze.getName(); int extDot = zeName.lastIndexOf("."); Boolean extract = false; if (extDot != -1) { String extresion = zeName .substring(extDot + 1); if (extresion.equals("php") || extresion.equals("pmf") || extresion.equals("phar")) extract = true; } if (extract) { int firstSlash = zeName.lastIndexOf("/"); if (firstSlash != -1) { zeName = zeName .substring(firstSlash + 1); } java.io.File f = new java.io.File(loc + zeName); f = new java.io.File(f.getParent()); if (!f.isDirectory()) f.mkdirs(); FileOutputStream fout = new FileOutputStream( loc + zeName); byte[] buffer = new byte[1024 * 2 * 2]; int b = -1; while ((b = zin.read(buffer)) != -1) { fout.write(buffer, 0, b); } fout.close(); files.add(zeName); } zin.closeEntry(); } } zin.close(); // zip.close(); } else if (ext.equals(".gz") || ext.equals(".tar")) { if (ext.equals(".tar")) { installAsIs = false; } else { String withoutExt = path.substring(0, iof); iof = withoutExt.lastIndexOf("."); if (iof != -1) { String ext2 = withoutExt.substring(iof); if (ext2.equals(".tar")) { installAsIs = false; } } } if (!installAsIs) { files = new ArrayList<String>(); filename += ".download"; String zipFileName = path + ".download"; FileInputStream fin = new FileInputStream( zipFileName); ArchiveInputStream in = null; if (ext.equals(".gz")) { in = new TarArchiveInputStream( new GzipCompressorInputStream( new BufferedInputStream(fin))); } else { in = new TarArchiveInputStream( new BufferedInputStream(fin)); } String loc = ServerUtils.getDataDirectory() + "/plugins/"; ArchiveEntry ze; while ((ze = in.getNextEntry()) != null) { if (!ze.isDirectory()) { String zeName = ze.getName(); int extDot = zeName.lastIndexOf("."); Boolean extract = false; if (extDot != -1) { String extresion = zeName .substring(extDot + 1); if (extresion.equals("php") || extresion.equals("pmf") || extresion.equals("phar")) extract = true; } if (extract) { int firstSlash = zeName .lastIndexOf("/"); if (firstSlash != -1) { zeName = zeName .substring(firstSlash + 1); } java.io.File f = new java.io.File(loc + zeName); f = new java.io.File(f.getParent()); if (!f.isDirectory()) f.mkdirs(); FileOutputStream fout = new FileOutputStream( loc + zeName); byte[] buffer = new byte[1024 * 2 * 2]; int b = -1; while ((b = in.read(buffer)) != -1) { fout.write(buffer, 0, b); } fout.close(); files.add(zeName); } } } in.close(); files = new ArrayList<String>(); filename += ".download"; } } } if (installAsIs) { File f = new File(path); if (f.exists()) { f.delete(); } new File(path + ".download").renameTo(f); } PluginListManager.installPlugin(id, updated, filename, files); Log.d("DownloadService", "Done."); Intent iEnd = new Intent(RECEIVER); iEnd.putExtra("id", id); iEnd.putExtra("type", 2); iEnd.putExtra("filename", path); sendBroadcast(iEnd); } else { File f = new File(path); if (f.exists()) { f.delete(); } Intent iErr = new Intent(RECEIVER); iErr.putExtra("id", id); iErr.putExtra("type", 4); sendBroadcast(iErr); } manager.cancel(2); } catch (Exception e) { manager.cancel(2); if (stop) { File f = new File(path); if (f.exists()) { f.delete(); } Intent iErr = new Intent(RECEIVER); iErr.putExtra("id", id); iErr.putExtra("type", 4); sendBroadcast(iErr); } else { Intent iErr = new Intent(RECEIVER); iErr.putExtra("id", id); iErr.putExtra("type", 3); sendBroadcast(iErr); handler.post(new Runnable() { @Override public void run() { Toast.makeText(DownloadService.this, "Failed to download the plugin.", Toast.LENGTH_SHORT).show(); } }); e.printStackTrace(); } } cid = -1; downloading = false; if (downloads.size() > 0) { QueueDownload dl = downloads.get(0); downloads.remove(0); download(dl.id, dl.url, dl.path, dl.filename, dl.updated); } else { stopSelf(); } } /* * Returns: 0-100: progress -1: not started -2: not on the list */ public int getProgress(int id) { if (id == cid) { return progress; } else { for (int i = 0; i < downloads.size(); i++) { if (downloads.get(i).id == id) { return -1; } } } return -2; } @Override public IBinder onBind(Intent arg0) { return null; } }