1 package com.joshuawise.dumload;
3 import java.io.InputStream;
4 import java.io.OutputStream;
6 import android.app.Notification;
7 import android.app.NotificationManager;
8 import android.app.PendingIntent;
9 import android.app.Service;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.content.SharedPreferences;
13 import android.net.Uri;
14 import android.os.Bundle;
15 import android.os.Handler;
16 import android.os.IBinder;
17 import android.os.Looper;
18 import android.os.Message;
19 import android.os.Messenger;
20 import android.os.SystemClock;
21 import android.preference.PreferenceManager;
22 import android.util.Log;
23 import android.widget.RemoteViews;
24 import android.widget.Toast;
26 import com.jcraft.jsch.Channel;
27 import com.jcraft.jsch.ChannelExec;
28 import com.jcraft.jsch.JSch;
29 import com.jcraft.jsch.Session;
30 import com.jcraft.jsch.UIKeyboardInteractive;
31 import com.jcraft.jsch.UserInfo;
33 public class Uploader extends Service implements Runnable, UserInfo, UIKeyboardInteractive {
35 private String homedir;
37 private static final int HELPME_ID = 1;
38 private RemoteViews remote;
39 private int thenotifid;
40 private Notification thenotif;
41 private String headline;
44 private InputStream is;
46 public Object _theObject;
48 private void sayNullNotification(final String scroller, final String headline, final String description)
50 int bogon = (int)SystemClock.elapsedRealtime();
51 NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
52 Notification notification = new Notification(R.drawable.icon, scroller, System.currentTimeMillis());
54 Intent intent = new Intent(this, NotifSlave.class);
56 intent.setAction("com.joshuawise.dumload.NotifSlave");
57 /* no extras to make the notifslave die */
58 intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime())));
60 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
61 notification.defaults |= Notification.DEFAULT_VIBRATE;
62 notification.flags |= Notification.FLAG_AUTO_CANCEL;
63 notification.setLatestEventInfo(getApplicationContext(), headline, description, contentIntent);
65 mNotificationManager.notify(bogon, notification);
68 private Object /* pick one type, and fixate on it */ dance(final String type, final String text) /* for inside the thread */
70 final Uploader thisupl = this;
71 final Message msg = Message.obtain();
74 Thread t = new Thread() {
77 int bogon = (int)SystemClock.elapsedRealtime();
79 NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
80 Notification notification = new Notification(R.drawable.icon, "Dumload prompt", System.currentTimeMillis());
82 Handler h = new Handler() {
83 public void handleMessage(Message M) {
85 Looper.myLooper().quit();
88 Messenger m = new Messenger(h);
90 Intent intent = new Intent(thisupl, NotifSlave.class);
92 intent.setAction("com.joshuawise.dumload.NotifSlave");
93 intent.putExtra("com.joshuawise.dumload.returnmessenger", m);
94 intent.putExtra("com.joshuawise.dumload.reqtype", type);
95 intent.putExtra("com.joshuawise.dumload.prompt", text);
96 intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime())));
98 PendingIntent contentIntent = PendingIntent.getActivity(thisupl, 0, intent, 0);
99 notification.defaults |= Notification.DEFAULT_VIBRATE;
100 notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
101 notification.setLatestEventInfo(getApplicationContext(), "I've been had!", "Dumload needs your input.", contentIntent);
103 Log.e("Dumload.Uploader[thread]", "Notifying...");
105 mNotificationManager.notify(bogon, notification);
107 Log.e("Dumload.Uploader[thread]", "About to go to 'sleep'...");
109 Log.e("Dumload.Uploader[thread]", "And we're alive!");
111 Log.e("Dumload.Uploader[thread]", "result was: "+(Integer.toString(msg.arg1)));
113 mNotificationManager.cancel(bogon);
120 } catch (Exception e) {
124 if (type.equals("yesno"))
125 return new Boolean(msg.arg1 == 1);
126 else if (type.equals("message"))
128 else if (type.equals("password")) {
131 Bundle b = msg.getData();
132 return b.getString("response");
138 String _password = null;
139 public String getPassword()
143 public boolean promptPassword(String message)
145 _password = (String)dance("password", message);
146 return (_password != null);
149 String _passphrase = null;
150 public String getPassphrase()
154 public boolean promptPassphrase(String message)
156 _passphrase = (String)dance("password", message);
157 return (_passphrase != null);
160 public boolean promptYesNo(String str)
162 return ((Boolean)dance("yesno", str)).booleanValue();
165 public void showMessage(String str)
167 dance("message", str);
170 public String[] promptKeyboardInteractive(String dest, String name, String instr, String[] prompt, boolean[] echo)
173 String [] responses = new String[prompt.length];
175 Log.e("Dumload.Uploader", "dest: "+dest);
176 Log.e("Dumload.Uploader", "name: "+name);
177 Log.e("Dumload.Uploader", "instr: "+instr);
178 for (i = 0; i < prompt.length; i++)
180 responses[i] = (String) dance("password", "[" + dest + "]\n" + prompt[i]);
181 if (responses[i] == null)
187 private void expect_ack(InputStream in) throws Exception, java.io.IOException
193 throw new Exception("unexpected EOF from remote end");
196 if (b == 1 /* error */ || b == 2 /* fatal error */)
198 StringBuffer sb = new StringBuffer();
201 while ((c = in.read()) != '\n')
204 throw new Exception("error from remote end: " + sb.toString());
208 private void set_up_notif(final String _headline)
210 NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
211 thenotif = new Notification(R.drawable.icon, headline, System.currentTimeMillis());
212 thenotifid = (int)SystemClock.elapsedRealtime();
214 Intent intent = new Intent(this, NotifSlave.class);
216 headline = _headline;
218 intent.setAction("com.joshuawise.dumload.NotifSlave");
219 /* no extras to make the notifslave die */
220 intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime())));
222 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
223 thenotif.defaults |= 0;
224 thenotif.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
226 remote = new RemoteViews(getPackageName(), R.layout.textnotif);
227 remote.setImageViewResource(R.id.image, R.drawable.icon);
228 remote.setTextViewText(R.id.headline, headline);
229 remote.setTextViewText(R.id.status, "Beginning upload...");
230 thenotif.contentView = remote;
231 thenotif.contentIntent = contentIntent;
233 mNotificationManager.notify(thenotifid, thenotif);
236 private void destroy_notif()
238 NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
239 mNotificationManager.cancel(thenotifid);
242 private void update_notif(String text)
244 NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
246 remote = new RemoteViews(getPackageName(), R.layout.textnotif);
247 remote.setImageViewResource(R.id.image, R.drawable.icon);
248 remote.setTextViewText(R.id.headline, headline);
249 remote.setTextViewText(R.id.status, text);
250 thenotif.contentView = remote;
252 mNotificationManager.notify(thenotifid, thenotif);
255 private void update_notif(int n, int total)
257 NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
259 remote = new RemoteViews(getPackageName(), R.layout.progressnotif);
260 remote.setImageViewResource(R.id.image, R.drawable.icon);
261 remote.setTextViewText(R.id.headline, headline);
262 remote.setProgressBar(R.id.status, total, n, false);
263 thenotif.contentView = remote;
265 mNotificationManager.notify(thenotifid, thenotif);
272 Log.e("Dumload.Uploader[thread]", "This brought to you from the new thread.");
274 set_up_notif("Dumload upload: " + dest);
277 say("Uploading "+(Integer.toString(is.available()))+" bytes");
279 update_notif("Connecting...");
281 JSch jsch = new JSch();
282 jsch.setKnownHosts(homedir + "/known_hosts");
284 jsch.addIdentity(homedir + "/id_dsa");
285 } catch (java.lang.Exception e) {
287 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
288 String server = prefs.getString("server", "").trim();
289 String userName = prefs.getString("userName", "").trim();
290 Integer port = prefs.getInt("serverPort", 22);
291 Log.d("dbg", userName + "@" + server + ":" + port);
292 Session s = jsch.getSession(userName, server, port);
296 Channel channel = s.openChannel("exec");
297 ((ChannelExec)channel).setCommand("scp -t "+dest);
300 OutputStream scp_out = channel.getOutputStream();
301 InputStream scp_in = channel.getInputStream();
303 update_notif("Starting send...");
305 /* Okay, BS out of the way. Now go send the file. */
309 if (dest.lastIndexOf("/") > 0)
310 stfu = dest.substring(dest.lastIndexOf("/") + 1);
314 scp_out.write(("C0644 " + (Integer.toString(is.available())) + " "+stfu+"\n").getBytes());
320 total = is.available();
323 byte[] buf = new byte[4096];
324 while ((len = is.read(buf, 0, buf.length)) > 0)
326 scp_out.write(buf, 0, len);
328 update_notif(nbytes, total);
333 update_notif("Finishing file transfer...");
335 scp_out.write("\0".getBytes());
340 channel.disconnect();
342 update_notif("Preparing to resize image...");
344 channel = s.openChannel("exec");
345 ((ChannelExec)channel).setCommand("pscale "+dest);
348 scp_in = channel.getInputStream();
350 update_notif("Resizing image...");
351 while ((len = scp_in.read(buf, 0, buf.length)) > 0)
354 channel.disconnect();
355 update_notif("Upload complete.");
357 sayNullNotification("Dumload upload complete: " + dest, "Upload complete", "Uploaded: " + dest);
360 } catch (Exception e) {
361 Log.e("Dumload.uploader[thread]", "JSchException: "+(e.toString()));
362 sayNullNotification("Dumload upload failed", "Upload failed", e.toString());
367 Log.e("Dumload.uploader[thread]", "And now I'm back to life!");
370 private void say(String s) {
371 Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
375 public void onStart(Intent i, int startId)
378 dest = i.getStringExtra("com.joshuawise.dumload.dest");
379 homedir = getApplicationContext().getFilesDir().getAbsolutePath();
383 super.onStart(i, startId);
385 Log.e("Dumload.Uploader", "Started.");
386 Log.e("Dumload.Uploader", "My path is "+homedir);
389 is = getContentResolver().openInputStream(uri);
390 } catch (Exception e) {
391 say("Failed to open input file.");
396 me = new Thread(this, "Uploader thread");
401 public IBinder onBind(Intent i) {
402 Log.e("Dumload.Uploader", "bound");