X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;f=src%2Fro%2Fieval%2Ffonbot%2FHeavy.java;h=b1f443c5f6067fb8a1366f2e51e71777d3504b32;hb=251aceaaa3379c65d66a975ff9e7524f7d2f1d73;hp=f734437f4c452d8c3ee8dc11f25db109dbfa11f1;hpb=c0c92599e4794433ad69fffcfcd3af677a37b03a;p=fonbot.git diff --git a/src/ro/ieval/fonbot/Heavy.java b/src/ro/ieval/fonbot/Heavy.java index f734437..b1f443c 100644 --- a/src/ro/ieval/fonbot/Heavy.java +++ b/src/ro/ieval/fonbot/Heavy.java @@ -3,15 +3,22 @@ package ro.ieval.fonbot; import static ro.ieval.fonbot.R.string.*; import static ro.ieval.fonbot.Utils.toNonNull; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; +import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; +import java.net.URL; +import java.net.URLConnection; import java.nio.channels.FileChannel; import java.nio.channels.SocketChannel; import java.util.ArrayList; @@ -53,6 +60,7 @@ import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; +import android.os.SystemClock; import android.os.Vibrator; import android.preference.PreferenceManager; import android.provider.BaseColumns; @@ -166,7 +174,14 @@ final class Heavy { final Date locationDate=new Date(loc.getTime()); sb.append(" "); sb.append(toNonNull(context.getString(at))); + sb.append(" "); sb.append(locationDate.toString()); + sb.append(". "); + + sb.append("http://openstreetmap.org/?zoom=15&mlat="); + sb.append(loc.getLatitude()); + sb.append("&mlon="); + sb.append(loc.getLongitude()); Utils.sendMessage(toNonNull(context), toNonNull(replyTo), toNonNull(sb.toString())); } @@ -280,6 +295,153 @@ final class Heavy { } } + /** + * ExecutableRunnable that uploads a file to a given host and port, netcat-style + * + * @author Marius Gavrilescu + */ + private static final class NcfileExecutableRunnable extends ExecutableRunnable { + private final Context context; + private final Address replyTo; + private final String filename; + private final String hostname; + private final int port; + + /** + * Construct a NcfileExecutableRunnable + * + * @param context Context instance + * @param replyTo reply Address + * @param filename filename to upload + * @param hostname hostname to upload to + * @param port port to upload to + */ + NcfileExecutableRunnable(final Context context, final Address replyTo, final String filename, final String hostname, final int port){ + this.context=context; + this.replyTo=replyTo; + this.filename=filename; + this.hostname=hostname; + this.port=port; + } + + @Override public void run(){ + final FileChannel in; + final SocketChannel sock; + try{ + in=new FileInputStream(filename).getChannel(); + } catch (final FileNotFoundException e){ + Utils.sendMessage(context, replyTo, file_not_found, filename); + return; + } + + try{ + sock = SocketChannel.open(new InetSocketAddress(hostname, port)); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, toNonNull(context.getString(cannot_connect_to_host_on_port, hostname, Integer.valueOf(port)))); + try { + in.close(); + } catch (IOException ex) { + //ignored + } + return; + } + + try{ + in.transferTo(0, in.size(), sock); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, toNonNull(context.getString(io_error, e.getMessage()))); + } finally { + try{ + in.close(); + } catch (IOException e){ + //ignored + } + try{ + sock.close(); + } catch(IOException e){ + //ignored + } + } + Utils.sendMessage(context, replyTo, file_sent); + } + } + + /** + * ExecutableRunnable that downloads a file from a given host and port, netcat-style + * + * @author Marius Gavrilescu + */ + private static final class GetfileExecutableRunnable extends ExecutableRunnable { + private final Context context; + private final Address replyTo; + private final String filename; + private final String hostname; + private final int port; + + /** + * Construct a GetfileExecutableRunnable + * + * @param context Context instance + * @param replyTo reply Address + * @param filename filename to save to + * @param hostname hostname to download from + * @param port port to download from + */ + GetfileExecutableRunnable(final Context context, final Address replyTo, final String filename, final String hostname, final int port){ + this.context=context; + this.replyTo=replyTo; + this.filename=filename; + this.hostname=hostname; + this.port=port; + } + + @Override public void run(){ + final InputStream in; + final FileOutputStream out; + final Socket sock; + try{ + out=new FileOutputStream(filename); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, error_opening_file, filename, e.getMessage()); + return; + } + + try{ + sock = new Socket(hostname, port); + in = sock.getInputStream(); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, toNonNull(context.getString(cannot_connect_to_host_on_port, hostname, Integer.valueOf(port)))); + try { + out.close(); + } catch (IOException ex) { + //ignored + } + return; + } + + try{ + byte[] buffer=new byte[1024*1024*2]; + int nread; + while((nread = in.read(buffer)) > 0) + out.write(buffer, 0, nread); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, toNonNull(context.getString(io_error, e.getMessage()))); + } finally { + try{ + out.close(); + } catch (IOException e){ + //ignored + } + try{ + sock.close(); + } catch(IOException e){ + //ignored + } + } + Utils.sendMessage(context, replyTo, file_received); + } + } + /** * PictureCallback that sends the picture to a server. * @@ -322,6 +484,42 @@ final class Heavy { } } + /** + * Runnable that takes a screen capture and stores it in a file. + */ + private static final class ScreencapRunnable implements Runnable{ + private final Context context; + private final Address replyTo; + private final String filename; + + ScreencapRunnable(final Context context, final Address replyTo, final String filename){ + this.context=context; + this.replyTo=replyTo; + this.filename=filename; + } + + @Override + public void run(){ + final int exitCode; + try { + exitCode=Runtime.getRuntime().exec(new String[]{ + "su", + "-c", + "screencap -p \"" + filename + "\"" + }).waitFor(); + } catch (final Exception e){ + e.printStackTrace(); + Utils.sendMessage(toNonNull(context), toNonNull(replyTo), screencap_failed); + return; + } + + if(exitCode == 0 && new File(filename).exists()) + Utils.sendMessage(toNonNull(context), toNonNull(replyTo), screencap_successful); + else + Utils.sendMessage(toNonNull(context), toNonNull(replyTo), screencap_failed); + } + } + /** * Get help for a particular command * @@ -460,11 +658,21 @@ final class Heavy { case REBOOT: Utils.sendMessage(context, replyTo, reboot_help); break; - case SHUTDOWN: - Utils.sendMessage(context, replyTo, shutdown_help); - break; case NOTIFY: Utils.sendMessage(context, replyTo, notify_help); + break; + case SCREENCAP: + Utils.sendMessage(context, replyTo, screencap_help); + break; + case TORCH: + Utils.sendMessage(context, replyTo, torch_help); + break; + case SH: + Utils.sendMessage(context, replyTo, sh_help); + break; + case ROOTSH: + Utils.sendMessage(context, replyTo, rootsh_help); + break; } } @@ -593,11 +801,15 @@ final class Heavy { * @param context Context instance * @param replyTo reply Address */ - private static void startCamera(final Context context, final Address replyTo){ + private static void startCamera(final Context context, final Address replyTo, final int cameraNumber){ if(camera!=null) return; try{ - camera=Camera.open(); + try{ + camera=Camera.open(cameraNumber); + } catch (Exception ex){ + camera=Camera.open(); + } } catch (Exception e){ Utils.sendMessage(context, replyTo, cannot_grab_camera); } @@ -696,9 +908,6 @@ final class Heavy { case LOCATION: nolocation(context, toNonNull(Address.BLACKHOLE)); break; - case POLL: - poll(context, toNonNull(Address.BLACKHOLE), 0); - break; case RING: ring(context, toNonNull(Address.BLACKHOLE), false); break; @@ -912,7 +1121,7 @@ final class Heavy { * @param on requested flashlight state */ public static void flash(final Context context, final Address replyTo, final boolean on){ - startCamera(context, replyTo); + startCamera(context, replyTo, 0); if(camera==null) return; final Camera.Parameters parms=camera.getParameters(); @@ -938,7 +1147,7 @@ final class Heavy { * @see LocationManager#requestLocationUpdates(String, long, float, LocationListener) */ public static void location(final Context context, final Address replyTo, final String provider,final long minTime,final float minDistance){ - final LocationManager man=(LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + final LocationManager man=(LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); if(locationListener!=null) nolocation(context, toNonNull(Address.BLACKHOLE)); Utils.registerOngoing(context, toNonNull(OngoingEvent.LOCATION)); @@ -989,55 +1198,7 @@ final class Heavy { * @param port server port */ public static void ncfile(final Context context, final Address replyTo, final String filename,final String hostname,final int port){ - new AsyncTask() { - @Override - protected @Nullable Void doInBackground(@Nullable final Void... params) { - final FileChannel in; - try{ - in=new FileInputStream(filename).getChannel(); - } catch (final FileNotFoundException e){ - Utils.sendMessage(context, replyTo, file_not_found, filename); - return null; - } - final SocketChannel sock; - try{ - sock = SocketChannel.open(new InetSocketAddress(hostname, port)); - } catch (final IOException e){ - Utils.sendMessage(context, replyTo, toNonNull(context.getString( - cannot_connect_to_host_on_port, hostname, Integer.valueOf(port)))); - try { - in.close(); - } catch (IOException ex) { - //ignored - } - return null; - } - - try{ - in.transferTo(0, in.size(), sock); - } catch (final IOException e){ - Utils.sendMessage(context, replyTo, toNonNull(context.getString( - io_error, e.getMessage()))); - } finally { - try{ - in.close(); - } catch (IOException e){ - //ignored - } - try{ - sock.close(); - } catch(IOException e){ - //ignored - } - } - return null; - } - - @Override - protected void onPostExecute(@Nullable final Void result) { - Utils.sendMessage(context, replyTo, file_sent); - } - }.execute(); + new NcfileExecutableRunnable(context, replyTo, filename, hostname, port).execute(); } /** @@ -1048,7 +1209,7 @@ final class Heavy { */ public static void nolocation(final Context context, final Address replyTo){ Utils.unregisterOngoing(context, toNonNull(OngoingEvent.LOCATION)); - final LocationManager man=(LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + final LocationManager man=(LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); man.removeUpdates(locationListener); locationListener=null; Utils.sendMessage(context, replyTo, no_longer_listening_for_location_updates); @@ -1059,11 +1220,12 @@ final class Heavy { * * @param context Context instance * @param replyTo reply Address + * @param cameraNumber camera to take photo with * @param hostname server hostname * @param port server port */ - public static void photo(final Context context, final Address replyTo, final String hostname, final int port){ - startCamera(context, replyTo); + public static void photo(final Context context, final Address replyTo, final int cameraNumber, final String hostname, final int port){ + startCamera(context, replyTo, cameraNumber); if(camera==null) return; final Camera.Parameters parms=camera.getParameters(); @@ -1084,16 +1246,16 @@ final class Heavy { new Thread(new Runnable() { @Override public void run() { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - //ignored - } + SystemClock.sleep(2000); handler.post(new Runnable() { @Override public void run() { - camera.takePicture(null, null, new FonBotPictureCallback(context, replyTo, hostname, port)); + try { + camera.takePicture(null, null, new FonBotPictureCallback(context, replyTo, hostname, port)); + } catch(Exception e){ + Utils.sendMessage(context, replyTo, error_while_processing_command, e.getClass().getName(), e.getMessage()); + } } }); } @@ -1273,7 +1435,7 @@ final class Heavy { sent.putExtra(SmsStatusReceiver.EXTRA_PART, i+1); sent.putExtra(SmsStatusReceiver.EXTRA_TOTAL, messages.size()); sent.putExtra(SmsStatusReceiver.EXTRA_REPLY_TO, replyTo.toString()); - sent.setAction(SmsStatusReceiver.SENT_ACTION+i);//actions must be unique + sent.setAction(SmsStatusReceiver.SENT_ACTION+i+System.currentTimeMillis());//actions must be unique sents.add(PendingIntent.getBroadcast(context, 0, sent, PendingIntent.FLAG_UPDATE_CURRENT)); final Intent delivered=new Intent(context, SmsStatusReceiver.class); @@ -1281,7 +1443,7 @@ final class Heavy { delivered.putExtra(SmsStatusReceiver.EXTRA_PART, i+1); delivered.putExtra(SmsStatusReceiver.EXTRA_TOTAL, messages.size()); delivered.putExtra(SmsStatusReceiver.EXTRA_REPLY_TO, replyTo.toString()); - delivered.setAction(SmsStatusReceiver.DELIVERED_ACTION+i);//actions must be unique + delivered.setAction(SmsStatusReceiver.DELIVERED_ACTION+i+System.currentTimeMillis());//actions must be unique delivereds.add(PendingIntent.getBroadcast(context, 0, delivered, PendingIntent.FLAG_UPDATE_CURRENT)); } @@ -1311,11 +1473,16 @@ final class Heavy { do { final String fromNumber=cursor.getString(1); final String from; - final String name=Utils.callerId(context, Utils.toNonNull(fromNumber)); - if(name==null) - from=fromNumber; - else - from=fromNumber+" ("+name+')'; + if(fromNumber == null) + from = null; + else { + final String name=Utils.callerId(context, Utils.toNonNull(fromNumber)); + if(name==null) + from=fromNumber; + else + from=fromNumber+" ("+name+')'; + } + final String message=cursor.getString(2).replace("\n", "\n "); final Date date=new Date(cursor.getLong(3)); @@ -1500,37 +1667,14 @@ final class Heavy { } /** - * Poll the server for pending commands. + * Start long polling if stopped * * @param context Context instance * @param replyTo reply Address */ public static void poll(final Context context, final Address replyTo) { - Utils.sendMessage(context, replyTo, polling_server); - Utils.pollServer(context); - } - - /** - * Change the server poll interval. - * - * @param context Context instance - * @param replyTo reply Address - * @param ms server poll interval in milliseconds. If 0, server poll is disabled - */ - public static void poll(final Context context, final Address replyTo, final long ms){ - final AlarmManager man=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - final Intent pollAlarm=new Intent(context, FonBotMainService.class); - pollAlarm.setAction(FonBotMainService.ACTION_TRIGGER_POLL); - final PendingIntent intent=PendingIntent.getService(context, 0, pollAlarm, 0); - if(ms==0){ - Utils.unregisterOngoing(context, toNonNull(OngoingEvent.POLL)); - man.cancel(intent); - Utils.sendMessage(context, replyTo, polling_stopped); - } else { - Utils.registerOngoing(context, toNonNull(OngoingEvent.POLL)); - man.setRepeating(AlarmManager.RTC_WAKEUP, 0, ms, intent); - Utils.sendMessage(context, replyTo, polling_every_milliseconds, Long.valueOf(ms)); - } + Utils.sendMessage(context, replyTo, starting_long_polling_if_stopped); + context.startService(new Intent(context, FonBotMainService.class)); } /** @@ -1707,8 +1851,22 @@ final class Heavy { */ public static void reboot(final Context context, final Address replyTo, final @Nullable String reason) { final PowerManager pm=(PowerManager) context.getSystemService(Context.POWER_SERVICE); - Utils.sendMessage(context, replyTo, rebooting); - pm.reboot(reason); + Utils.sendMessage(context, replyTo, rebooting); + try { + pm.reboot(reason); + } catch (final Exception e){ + e.printStackTrace(); + } + try { + Runtime.getRuntime().exec(new String[]{ + "su", + "-c", + "reboot" + }).waitFor(); + } catch (final Exception e){ + e.printStackTrace(); + } + Utils.sendMessage(toNonNull(context), toNonNull(replyTo), reboot_failed); } /** @@ -1742,4 +1900,65 @@ final class Heavy { build()); Utils.sendMessage(context, replyTo, notification_shown); } + + /** + * Take a screen capture. Uses the screencap utility and requires root. + * + * @param context Context instance + * @param replyTo reply Address + * @param filename capture file location + */ + public static void screencap(final Context context, final Address replyTo, final String filename){ + new Thread(new ScreencapRunnable(context, replyTo, filename)).start(); + } + + /** + * Toggle the torch state using the Torch (net.cactii.torch2) app. + * + * @param context Context instance + * @param replyTo reply Address + */ + public static void torch(final Context context, final Address replyTo){ + context.sendBroadcast(new Intent("net.cactii.flash2.TOGGLE_FLASHLIGHT")); + Utils.sendMessage(context, replyTo, toggling_torch_state); + } + + /** + * Download a file from a given URL to a given filename + * + * @param context Context instance + * @param replyTo reply Address + * @param filename filename to save to + * @param hostname hostname to download from + * @param port port to download from + */ + public static void getfile(final Context context, final Address replyTo, final String filename, final String hostname, final int port){ + new GetfileExecutableRunnable(context, replyTo, filename, hostname, port).execute(); + } + + /** + * Execute a command using a given shell and reply with the output. + * + * @param context Context instance + * @param replyTo reply Address + * @param shell The shell to execute with. Usually sh or su. + * @param command The command to pass to the shell. + */ + public static void execute(final Context context, final Address replyTo, final String shell, final String command) { + try { + final Process proc = Runtime.getRuntime().exec(new String[]{ + shell, + "-c", + command + }); + final BufferedReader br = new BufferedReader (new InputStreamReader(proc.getInputStream())); + String line; + while((line = br.readLine()) != null) + Utils.sendMessage(context, replyTo, line); + proc.waitFor(); + } catch (final Exception e){ + Utils.sendMessage(context, replyTo, error_while_processing_command, e.getClass().getName(), e.getMessage()); + Log.w(Heavy.class.getName(), "Error while processing command", e); + } + } }