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