]> Joshua Wise's Git repositories - dumload.git/blob - src/com/joshuawise/dumload/Uploader.java
GPLv3
[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 com.jcraft.jsch.*;
23 import java.lang.Boolean;
24
25 import android.app.Activity;
26 import android.app.Service;
27 import android.content.Intent;
28 import android.app.PendingIntent;
29 import android.content.Context;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.os.IBinder;
33 import android.widget.TextView;
34 import android.widget.Toast;
35 import android.util.Log;
36 import android.app.NotificationManager;
37 import android.app.Notification;
38 import android.os.Handler;
39 import android.os.Messenger;
40 import android.os.Looper;
41 import android.os.Message;
42 import android.os.SystemClock;
43 import android.widget.RemoteViews;
44
45 public 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;
50         private RemoteViews remote;
51         private int thenotifid;
52         private Notification thenotif;
53         private String headline;
54         private String dest;
55         
56         private InputStream is;
57         
58         public Object _theObject;
59
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
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;
112                                 notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
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]);
193                         if (responses[i] == null)
194                                 return null;
195                 }
196                 return responses;
197         }
198         
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         
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         
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                 
287                 set_up_notif("Dumload upload: " + dest);
288                 
289                 try {
290                         say("Uploading "+(Integer.toString(is.available()))+" bytes");
291                 
292                         update_notif("Connecting...");
293                 
294                         JSch jsch = new JSch();
295                         jsch.setKnownHosts(homedir + "/known_hosts");
296                         try {
297                                 jsch.addIdentity(homedir + "/id_dsa");
298                         } catch (java.lang.Exception e) {
299                         }
300                         Session s = jsch.getSession("joshua", "nyus.joshuawise.com", 22);
301                         s.setUserInfo(this);
302                         s.connect();
303                         
304                         Channel channel = s.openChannel("exec");
305                         ((ChannelExec)channel).setCommand("scp -t "+dest);
306                         channel.connect();
307                         
308                         OutputStream scp_out = channel.getOutputStream();
309                         InputStream scp_in = channel.getInputStream();
310                         
311                         update_notif("Starting send...");
312                         
313                         /* Okay, BS out of the way.  Now go send the file. */
314                         expect_ack(scp_in);
315                         
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());
323                         scp_out.flush();
324                         
325                         expect_ack(scp_in);
326                         
327                         int total, nbytes;
328                         total = is.available();
329                         nbytes = 0;
330                         int len;
331                         byte[] buf = new byte[4096];
332                         while ((len = is.read(buf, 0, buf.length)) > 0)
333                         {
334                                 scp_out.write(buf, 0, len);
335                                 nbytes += len;
336                                 update_notif(nbytes, total);
337                         }
338                         
339                         is.close();
340                         
341                         update_notif("Finishing file transfer...");
342                         
343                         scp_out.write("\0".getBytes());
344                         scp_out.flush();
345                         
346                         expect_ack(scp_in);
347                         
348                         channel.disconnect();
349                         
350                         update_notif("Preparing to resize image...");
351                         
352                         channel = s.openChannel("exec");
353                         ((ChannelExec)channel).setCommand("pscale "+dest);
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                         
365                         sayNullNotification("Dumload upload complete: " + dest, "Upload complete", "Uploaded: " + dest);
366
367                         s.disconnect();
368                 } catch (Exception e) {
369                         Log.e("Dumload.uploader[thread]", "JSchException: "+(e.toString()));
370                         sayNullNotification("Dumload upload failed", "Upload failed", e.toString());
371                 }
372                 
373                 destroy_notif();
374                 
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();
386                 dest = i.getStringExtra("com.joshuawise.dumload.dest");
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 {
396                         is = getContentResolver().openInputStream(uri);
397                 } catch (Exception e) {
398                         say("Failed to open input file.");
399                         return;
400                 }
401                 
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.045134 seconds and 4 git commands to generate.