]> Joshua Wise's Git repositories - dumload.git/blob - src/com/joshuawise/dumload/Uploader.java
A few icon tweaks
[dumload.git] / src / com / joshuawise / dumload / Uploader.java
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
17 package com.joshuawise.dumload;
18
19 import java.io.InputStream;
20 import java.io.OutputStream;
21
22 import android.app.Notification;
23 import android.app.NotificationManager;
24 import android.app.PendingIntent;
25 import android.app.Service;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.SharedPreferences;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.Messenger;
36 import android.os.SystemClock;
37 import android.preference.PreferenceManager;
38 import android.util.Log;
39 import android.widget.RemoteViews;
40 import android.widget.Toast;
41
42 import com.jcraft.jsch.Channel;
43 import com.jcraft.jsch.ChannelExec;
44 import com.jcraft.jsch.JSch;
45 import com.jcraft.jsch.Session;
46 import com.jcraft.jsch.UIKeyboardInteractive;
47 import com.jcraft.jsch.UserInfo;
48
49 public 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.046377 seconds and 4 git commands to generate.