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