]>
Commit | Line | Data |
---|---|---|
0763e16d JW |
1 | package com.joshuawise.dumload; |
2 | ||
3 | import java.io.InputStream; | |
035767ac | 4 | import java.io.OutputStream; |
0763e16d JW |
5 | |
6 | import com.jcraft.jsch.*; | |
7 | import java.lang.Boolean; | |
8 | ||
9 | import android.app.Activity; | |
10 | import android.app.Service; | |
11 | import android.content.Intent; | |
12 | import android.app.PendingIntent; | |
13 | import android.content.Context; | |
14 | import android.net.Uri; | |
15 | import android.os.Bundle; | |
16 | import android.os.IBinder; | |
17 | import android.widget.TextView; | |
18 | import android.widget.Toast; | |
19 | import android.util.Log; | |
20 | import android.app.NotificationManager; | |
21 | import android.app.Notification; | |
22 | import android.os.Handler; | |
23 | import android.os.Messenger; | |
24 | import android.os.Looper; | |
25 | import android.os.Message; | |
26 | import android.os.SystemClock; | |
ae61bba6 | 27 | import android.widget.RemoteViews; |
0763e16d JW |
28 | |
29 | public class Uploader extends Service implements Runnable, UserInfo, UIKeyboardInteractive { | |
30 | private Uri uri; | |
31 | private String homedir; | |
32 | private Thread me; | |
33 | private static final int HELPME_ID = 1; | |
ae61bba6 JW |
34 | private RemoteViews remote; |
35 | private int thenotifid; | |
36 | private Notification thenotif; | |
37 | private String headline; | |
0763e16d | 38 | |
035767ac JW |
39 | private InputStream is; |
40 | ||
0763e16d JW |
41 | public Object _theObject; |
42 | ||
ae61bba6 JW |
43 | private void sayNullNotification(final String scroller, final String headline, final String description) |
44 | { | |
45 | int bogon = (int)SystemClock.elapsedRealtime(); | |
46 | NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); | |
47 | Notification notification = new Notification(R.drawable.icon, scroller, System.currentTimeMillis()); | |
48 | ||
49 | Intent intent = new Intent(this, NotifSlave.class); | |
50 | ||
51 | intent.setAction("com.joshuawise.dumload.NotifSlave"); | |
52 | /* no extras to make the notifslave die */ | |
53 | intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime()))); | |
54 | ||
55 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0); | |
56 | notification.defaults |= Notification.DEFAULT_VIBRATE; | |
57 | notification.flags |= Notification.FLAG_AUTO_CANCEL; | |
58 | notification.setLatestEventInfo(getApplicationContext(), headline, description, contentIntent); | |
59 | ||
60 | mNotificationManager.notify(bogon, notification); | |
61 | } | |
62 | ||
0763e16d JW |
63 | private Object /* pick one type, and fixate on it */ dance(final String type, final String text) /* for inside the thread */ |
64 | { | |
65 | final Uploader thisupl = this; | |
66 | final Message msg = Message.obtain(); | |
67 | ||
68 | /* t(*A*t) */ | |
69 | Thread t = new Thread() { | |
70 | public void run() { | |
71 | Looper.prepare(); | |
72 | int bogon = (int)SystemClock.elapsedRealtime(); | |
73 | ||
74 | NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); | |
75 | Notification notification = new Notification(R.drawable.icon, "Dumload prompt", System.currentTimeMillis()); | |
76 | ||
77 | Handler h = new Handler() { | |
78 | public void handleMessage(Message M) { | |
79 | msg.copyFrom(M); | |
80 | Looper.myLooper().quit(); | |
81 | } | |
82 | }; | |
83 | Messenger m = new Messenger(h); | |
84 | ||
85 | Intent intent = new Intent(thisupl, NotifSlave.class); | |
86 | ||
87 | intent.setAction("com.joshuawise.dumload.NotifSlave"); | |
88 | intent.putExtra("com.joshuawise.dumload.returnmessenger", m); | |
89 | intent.putExtra("com.joshuawise.dumload.reqtype", type); | |
90 | intent.putExtra("com.joshuawise.dumload.prompt", text); | |
91 | intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime()))); | |
92 | ||
93 | PendingIntent contentIntent = PendingIntent.getActivity(thisupl, 0, intent, 0); | |
94 | notification.defaults |= Notification.DEFAULT_VIBRATE; | |
ae61bba6 | 95 | notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; |
0763e16d JW |
96 | notification.setLatestEventInfo(getApplicationContext(), "I've been had!", "Dumload needs your input.", contentIntent); |
97 | ||
98 | Log.e("Dumload.Uploader[thread]", "Notifying..."); | |
99 | ||
100 | mNotificationManager.notify(bogon, notification); | |
101 | ||
102 | Log.e("Dumload.Uploader[thread]", "About to go to 'sleep'..."); | |
103 | Looper.loop(); | |
104 | Log.e("Dumload.Uploader[thread]", "And we're alive!"); | |
105 | ||
106 | Log.e("Dumload.Uploader[thread]", "result was: "+(Integer.toString(msg.arg1))); | |
107 | ||
108 | mNotificationManager.cancel(bogon); | |
109 | } | |
110 | }; | |
111 | ||
112 | t.start(); | |
113 | try { | |
114 | t.join(); | |
115 | } catch (Exception e) { | |
116 | return null; | |
117 | } | |
118 | ||
119 | if (type.equals("yesno")) | |
120 | return new Boolean(msg.arg1 == 1); | |
121 | else if (type.equals("message")) | |
122 | return null; | |
123 | else if (type.equals("password")) { | |
124 | if (msg.arg1 == 0) | |
125 | return null; | |
126 | Bundle b = msg.getData(); | |
127 | return b.getString("response"); | |
128 | } else | |
129 | return null; | |
130 | } | |
131 | ||
132 | /* UserInfo bits */ | |
133 | String _password = null; | |
134 | public String getPassword() | |
135 | { | |
136 | return _password; | |
137 | } | |
138 | public boolean promptPassword(String message) | |
139 | { | |
140 | _password = (String)dance("password", message); | |
141 | return (_password != null); | |
142 | } | |
143 | ||
144 | String _passphrase = null; | |
145 | public String getPassphrase() | |
146 | { | |
147 | return _passphrase; | |
148 | } | |
149 | public boolean promptPassphrase(String message) | |
150 | { | |
151 | _passphrase = (String)dance("password", message); | |
152 | return (_passphrase != null); | |
153 | } | |
154 | ||
155 | public boolean promptYesNo(String str) | |
156 | { | |
157 | return ((Boolean)dance("yesno", str)).booleanValue(); | |
158 | } | |
159 | ||
160 | public void showMessage(String str) | |
161 | { | |
162 | dance("message", str); | |
163 | } | |
164 | ||
165 | public String[] promptKeyboardInteractive(String dest, String name, String instr, String[] prompt, boolean[] echo) | |
166 | { | |
167 | int i; | |
168 | String [] responses = new String[prompt.length]; | |
169 | ||
170 | Log.e("Dumload.Uploader", "dest: "+dest); | |
171 | Log.e("Dumload.Uploader", "name: "+name); | |
172 | Log.e("Dumload.Uploader", "instr: "+instr); | |
173 | for (i = 0; i < prompt.length; i++) | |
174 | { | |
175 | responses[i] = (String) dance("password", "[" + dest + "]\n" + prompt[i]); | |
ae61bba6 JW |
176 | if (responses[i] == null) |
177 | return null; | |
0763e16d JW |
178 | } |
179 | return responses; | |
180 | } | |
181 | ||
035767ac JW |
182 | private void expect_ack(InputStream in) throws Exception, java.io.IOException |
183 | { | |
184 | int b = in.read(); | |
185 | ||
186 | if (b == -1) | |
187 | { | |
188 | throw new Exception("unexpected EOF from remote end"); | |
189 | } | |
190 | ||
191 | if (b == 1 /* error */ || b == 2 /* fatal error */) | |
192 | { | |
193 | StringBuffer sb = new StringBuffer(); | |
194 | int c = 0; | |
195 | ||
196 | while ((c = in.read()) != '\n') | |
197 | sb.append((char)c); | |
198 | ||
199 | throw new Exception("error from remote end: " + sb.toString()); | |
200 | } | |
201 | } | |
202 | ||
ae61bba6 JW |
203 | private void set_up_notif(final String _headline) |
204 | { | |
205 | NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); | |
206 | thenotif = new Notification(R.drawable.icon, headline, System.currentTimeMillis()); | |
207 | thenotifid = (int)SystemClock.elapsedRealtime(); | |
208 | ||
209 | Intent intent = new Intent(this, NotifSlave.class); | |
210 | ||
211 | headline = _headline; | |
212 | ||
213 | intent.setAction("com.joshuawise.dumload.NotifSlave"); | |
214 | /* no extras to make the notifslave die */ | |
215 | intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime()))); | |
216 | ||
217 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0); | |
218 | thenotif.defaults |= 0; | |
219 | thenotif.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; | |
220 | ||
221 | remote = new RemoteViews(getPackageName(), R.layout.textnotif); | |
222 | remote.setImageViewResource(R.id.image, R.drawable.icon); | |
223 | remote.setTextViewText(R.id.headline, headline); | |
224 | remote.setTextViewText(R.id.status, "Beginning upload..."); | |
225 | thenotif.contentView = remote; | |
226 | thenotif.contentIntent = contentIntent; | |
227 | ||
228 | mNotificationManager.notify(thenotifid, thenotif); | |
229 | } | |
230 | ||
231 | private void destroy_notif() | |
232 | { | |
233 | NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); | |
234 | mNotificationManager.cancel(thenotifid); | |
235 | } | |
236 | ||
237 | private void update_notif(String text) | |
238 | { | |
239 | NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); | |
240 | ||
241 | remote = new RemoteViews(getPackageName(), R.layout.textnotif); | |
242 | remote.setImageViewResource(R.id.image, R.drawable.icon); | |
243 | remote.setTextViewText(R.id.headline, headline); | |
244 | remote.setTextViewText(R.id.status, text); | |
245 | thenotif.contentView = remote; | |
246 | ||
247 | mNotificationManager.notify(thenotifid, thenotif); | |
248 | } | |
249 | ||
250 | private void update_notif(int n, int total) | |
251 | { | |
252 | NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); | |
253 | ||
254 | remote = new RemoteViews(getPackageName(), R.layout.progressnotif); | |
255 | remote.setImageViewResource(R.id.image, R.drawable.icon); | |
256 | remote.setTextViewText(R.id.headline, headline); | |
257 | remote.setProgressBar(R.id.status, total, n, false); | |
258 | thenotif.contentView = remote; | |
259 | ||
260 | mNotificationManager.notify(thenotifid, thenotif); | |
261 | } | |
262 | ||
0763e16d JW |
263 | @Override |
264 | public void run() | |
265 | { | |
266 | Looper.prepare(); | |
267 | ||
268 | Log.e("Dumload.Uploader[thread]", "This brought to you from the new thread."); | |
269 | ||
ae61bba6 JW |
270 | set_up_notif("Dumload upload in progress"); |
271 | ||
0763e16d | 272 | try { |
035767ac JW |
273 | say("Uploading "+(Integer.toString(is.available()))+" bytes"); |
274 | ||
ae61bba6 JW |
275 | update_notif("Connecting..."); |
276 | ||
0763e16d JW |
277 | JSch jsch = new JSch(); |
278 | jsch.setKnownHosts(homedir + "/known_hosts"); | |
279 | Session s = jsch.getSession("joshua", "nyus.joshuawise.com", 22); | |
280 | s.setUserInfo(this); | |
281 | s.connect(); | |
282 | ||
283 | Channel channel = s.openChannel("exec"); | |
e1916520 | 284 | ((ChannelExec)channel).setCommand("scp -t /tmp/lol.jpg"); |
0763e16d JW |
285 | channel.connect(); |
286 | ||
035767ac JW |
287 | OutputStream scp_out = channel.getOutputStream(); |
288 | InputStream scp_in = channel.getInputStream(); | |
289 | ||
ae61bba6 JW |
290 | update_notif("Starting send..."); |
291 | ||
035767ac JW |
292 | /* Okay, BS out of the way. Now go send the file. */ |
293 | expect_ack(scp_in); | |
294 | ||
e1916520 | 295 | scp_out.write(("C0644 " + (Integer.toString(is.available())) + " lol.jpg\n").getBytes()); |
035767ac JW |
296 | scp_out.flush(); |
297 | ||
298 | expect_ack(scp_in); | |
299 | ||
ae61bba6 JW |
300 | int total, nbytes; |
301 | total = is.available(); | |
302 | nbytes = 0; | |
035767ac JW |
303 | int len; |
304 | byte[] buf = new byte[4096]; | |
305 | while ((len = is.read(buf, 0, buf.length)) > 0) | |
ae61bba6 | 306 | { |
035767ac | 307 | scp_out.write(buf, 0, len); |
ae61bba6 JW |
308 | nbytes += len; |
309 | update_notif(nbytes, total); | |
310 | } | |
035767ac JW |
311 | |
312 | is.close(); | |
313 | ||
e1916520 | 314 | update_notif("Finishing file transfer..."); |
ae61bba6 | 315 | |
035767ac JW |
316 | scp_out.write("\0".getBytes()); |
317 | scp_out.flush(); | |
318 | ||
319 | expect_ack(scp_in); | |
320 | ||
e1916520 JW |
321 | channel.disconnect(); |
322 | ||
323 | update_notif("Preparing to resize image..."); | |
324 | ||
325 | channel = s.openChannel("exec"); | |
326 | ((ChannelExec)channel).setCommand("pscale /tmp/lol.jpg"); | |
327 | channel.connect(); | |
328 | ||
329 | scp_in = channel.getInputStream(); | |
330 | ||
331 | update_notif("Resizing image..."); | |
332 | while ((len = scp_in.read(buf, 0, buf.length)) > 0) | |
333 | ; | |
334 | ||
335 | channel.disconnect(); | |
336 | update_notif("Upload complete."); | |
337 | ||
ae61bba6 | 338 | sayNullNotification("Dumload upload complete", "Upload complete", "Dumload has finished uploading your file."); |
0763e16d | 339 | |
0763e16d | 340 | s.disconnect(); |
035767ac | 341 | } catch (Exception e) { |
0763e16d | 342 | Log.e("Dumload.uploader[thread]", "JSchException: "+(e.toString())); |
ae61bba6 | 343 | sayNullNotification("Dumload upload failed", "Upload failed", e.toString()); |
0763e16d JW |
344 | } |
345 | ||
ae61bba6 JW |
346 | destroy_notif(); |
347 | ||
0763e16d JW |
348 | Log.e("Dumload.uploader[thread]", "And now I'm back to life!"); |
349 | } | |
350 | ||
351 | private void say(String s) { | |
352 | Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show(); | |
353 | } | |
354 | ||
355 | @Override | |
356 | public void onStart(Intent i, int startId) | |
357 | { | |
358 | uri = i.getData(); | |
359 | homedir = getApplicationContext().getFilesDir().getAbsolutePath(); | |
360 | int shits = 0; | |
361 | ||
362 | super.onStart(i, startId); | |
363 | ||
364 | Log.e("Dumload.Uploader", "Started."); | |
365 | Log.e("Dumload.Uploader", "My path is "+homedir); | |
366 | ||
367 | try { | |
035767ac | 368 | is = getContentResolver().openInputStream(uri); |
0763e16d | 369 | } catch (Exception e) { |
035767ac JW |
370 | say("Failed to open input file."); |
371 | return; | |
0763e16d JW |
372 | } |
373 | ||
0763e16d JW |
374 | |
375 | me = new Thread(this, "Uploader thread"); | |
376 | me.start(); | |
377 | } | |
378 | ||
379 | @Override | |
380 | public IBinder onBind(Intent i) { | |
381 | Log.e("Dumload.Uploader", "bound"); | |
382 | ||
383 | return null; | |
384 | } | |
385 | } |