001: /*
002: * This program is free software; you can redistribute it and/or
003: * modify it under the terms of the GNU General Public License
004: * as published by the Free Software Foundation; either version 2
005: * of the License, or (at your option) any later version.
006: *
007: * This program is distributed in the hope that it will be useful,
008: * but WITHOUT ANY WARRANTY; without even the implied warranty of
009: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: * GNU General Public License for more details.
011: *
012: * You should have received a copy of the GNU General Public License
013: * along with this program; if not, write to the Free Software
014: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
015: */
016: package net.sf.jftp.net;
017:
018: import java.io.BufferedInputStream;
019: import java.io.BufferedOutputStream;
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileOutputStream;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.io.StreamTokenizer;
026: import java.util.Date;
027: import java.util.Enumeration;
028: import java.util.Vector;
029:
030: import javax.swing.JOptionPane;
031:
032: import net.sf.jftp.config.Settings;
033: import net.sf.jftp.system.StringUtils;
034: import net.sf.jftp.system.logging.Log;
035:
036: import com.jcraft.jsch.Channel;
037: import com.jcraft.jsch.ChannelSftp;
038: import com.jcraft.jsch.JSch;
039: import com.jcraft.jsch.Session;
040: import com.jcraft.jsch.SftpException;
041: import com.jcraft.jsch.UserInfo;
042: import com.jcraft.jsch.ChannelSftp.LsEntry;
043: import com.sshtools.j2ssh.sftp.SftpFile;
044: import com.sshtools.j2ssh.sftp.SftpFileInputStream;
045: import com.sshtools.j2ssh.sftp.SftpFileOutputStream;
046: import com.sshtools.j2ssh.sftp.SftpSubsystemClient;
047:
048: public class Sftp2Connection implements BasicConnection {
049: public static int smbBuffer = 32000;
050: private String path = "";
051: private String pwd = "/";
052: private Vector listeners = new Vector();
053: private String[] files;
054: private String[] size = new String[0];
055: private int[] perms = null;
056: private String user;
057: private String pass;
058: private String host;
059: private String baseFile;
060: private int fileCount;
061: private boolean isDirUpload = false;
062: private boolean shortProgress = false;
063: private int RW = SftpSubsystemClient.OPEN_CREATE
064: | SftpSubsystemClient.OPEN_WRITE;
065: private int W = SftpSubsystemClient.OPEN_CREATE;
066: private int R = SftpSubsystemClient.OPEN_READ;
067: private int port = 22;
068: private boolean connected = false;
069: private String keyfile = null;
070: private Session session;
071: private ChannelSftp channel;
072:
073: public Sftp2Connection(String host, String port, String keyfile) {
074: this .host = host;
075: this .port = Integer.parseInt(port);
076: this .keyfile = keyfile;
077:
078: Log.debug("Using JSch wrapper...");
079: }
080:
081: private boolean login() {
082: try {
083: JSch jsch = new JSch();
084: if (keyfile != null) {
085: jsch.addIdentity(keyfile);
086: }
087: session = jsch.getSession(user, host, this .port);
088: UserInfo ui = new MyUserInfo(pass);
089: session.setUserInfo(ui);
090: session.connect();
091:
092: channel = (ChannelSftp) session.openChannel("sftp");
093: channel.connect();
094:
095: Log.debug("Host: " + host + ":" + port);
096:
097: connected = true;
098: return true;
099: } catch (Exception ex) {
100: ex.printStackTrace();
101: Log.debug("Error: " + ex);
102:
103: return false;
104: }
105: }
106:
107: public int removeFileOrDir(String file) {
108: file = toSFTP(file);
109:
110: try {
111:
112: if (!file.endsWith("/")) {
113: Log.out(">>>>>>>> remove file: " + file);
114: channel.rm(file);
115: } else {
116: Log.out(">>>>>>>> remove dir: " + file);
117: cleanSftpDir(file);
118: channel.rmdir(file);
119: }
120: } catch (Exception ex) {
121: ex.printStackTrace();
122: Log.debug("Removal failed (" + ex + ").");
123: ex.printStackTrace();
124:
125: return -1;
126: }
127:
128: return 1;
129: }
130:
131: private void cleanSftpDir(String dir) throws Exception {
132: Log.out(">>>>>>>> cleanSftpDir: " + dir);
133:
134: Vector v = channel.ls(dir);
135:
136: String[] tmp = new String[v.size()];
137: Enumeration e = v.elements();
138: int x = 0;
139:
140: while (e.hasMoreElements()) {
141: LsEntry entry = ((LsEntry) e.nextElement());
142: tmp[x] = entry.getFilename();
143:
144: //Log.out("sftp delete: " + tmp[x]);
145: if (entry.getAttrs().isDir() && !tmp[x].endsWith("/")) {
146: tmp[x] = tmp[x] + "/";
147: }
148:
149: x++;
150: }
151:
152: if (tmp == null) {
153: return;
154: }
155:
156: for (int i = 0; i < tmp.length; i++) {
157: if (tmp[i].equals("./") || tmp[i].equals("../")) {
158: continue;
159: }
160:
161: Log.out(">>>>>>>> remove file/dir: " + dir + tmp[i]);
162:
163: if (tmp[i].endsWith("/")) {
164: cleanSftpDir(dir + tmp[i]);
165: channel.rmdir(dir + tmp[i]);
166: } else {
167: channel.rm(dir + tmp[i]);
168: }
169: }
170: }
171:
172: public void sendRawCommand(String cmd) {
173: }
174:
175: public void disconnect() {
176: try {
177: channel.disconnect();
178: session.disconnect();
179: } catch (Exception e) {
180: e.printStackTrace();
181: Log.debug("Sftp2Connection.disconnect()" + e);
182: }
183:
184: connected = false;
185: }
186:
187: public boolean isConnected() {
188: return connected;
189: }
190:
191: public String getPWD() {
192: //Log.debug("PWD: " + pwd);
193: return toSFTPDir(pwd);
194: }
195:
196: public boolean mkdir(String dirName) {
197: try {
198: if (!dirName.endsWith("/")) {
199: dirName = dirName + "/";
200: }
201:
202: dirName = toSFTP(dirName);
203:
204: channel.mkdir(dirName);
205:
206: fireDirectoryUpdate();
207:
208: return true;
209: } catch (Exception ex) {
210: Log.debug("Failed to create directory (" + ex + ").");
211:
212: return false;
213: }
214: }
215:
216: public void list() throws IOException {
217: }
218:
219: public boolean chdir(String p) {
220: return chdir(p, true);
221: }
222:
223: public boolean chdir(String p, boolean refresh) {
224: String tmp = toSFTP(p);
225:
226: try {
227: if (!tmp.endsWith("/")) {
228: tmp = tmp + "/";
229: }
230: if (tmp.endsWith("../")) {
231: return cdup();
232: }
233:
234: System.out.println("sftp path: " + tmp + ", chan: "
235: + channel);
236: channel.cd(tmp);
237:
238: pwd = tmp;
239:
240: //Log.debug("chdir: " + getPWD());
241: if (refresh) {
242: fireDirectoryUpdate();
243: }
244:
245: //System.out.println("chdir2: " + getPWD());
246: //Log.debug("Changed path to: " + tmp);
247: return true;
248: } catch (Exception ex) {
249: ex.printStackTrace();
250:
251: //System.out.println(tmp);
252: Log.debug("Could not change directory (" + ex + ").");
253:
254: return false;
255: }
256: }
257:
258: public boolean cdup() {
259: String tmp = pwd;
260:
261: if (pwd.endsWith("/")) {
262: tmp = pwd.substring(0, pwd.lastIndexOf("/"));
263: }
264:
265: return chdir(tmp.substring(0, tmp.lastIndexOf("/") + 1));
266: }
267:
268: public boolean chdirNoRefresh(String p) {
269: return chdir(p, false);
270: }
271:
272: public String getLocalPath() {
273: return path;
274: }
275:
276: public boolean setLocalPath(String p) {
277: if (StringUtils.isRelative(p)) {
278: p = path + p;
279: }
280:
281: p = p.replace('\\', '/');
282:
283: //System.out.println(", local 2:" + p);
284: File f = new File(p);
285:
286: if (f.exists()) {
287: try {
288: path = f.getCanonicalPath();
289: path = path.replace('\\', '/');
290:
291: if (!path.endsWith("/")) {
292: path = path + "/";
293: }
294:
295: //System.out.println("localPath: "+path);
296: } catch (IOException ex) {
297: Log.debug("Error: can not get pathname (local)!");
298:
299: return false;
300: }
301: } else {
302: Log.debug("(local) No such path: \"" + p + "\"");
303:
304: return false;
305: }
306:
307: return true;
308: }
309:
310: public String[] sortLs() {
311: try {
312: System.out.println(pwd);
313: Vector v = channel.ls(pwd);
314:
315: String[] tmp = new String[v.size()];
316: files = new String[tmp.length];
317: size = new String[tmp.length];
318: perms = new int[tmp.length];
319:
320: Enumeration e = v.elements();
321: int x = 0;
322:
323: while (e.hasMoreElements()) {
324: LsEntry entry = ((LsEntry) e.nextElement());
325: tmp[x] = entry.getFilename();
326:
327: size[x] = "" + entry.getAttrs().getSize();
328:
329: //Log.debug("Perms: "+entry.getAttrs().getPermissionsString());
330:
331: /*
332: if(!entry.getAttrs().getPermissionsString())
333: {
334: perms[x] = FtpConnection.DENIED;
335: }
336: else
337: {*/
338: perms[x] = FtpConnection.R;
339: //}
340:
341: //Log.debugRaw(".");
342: if (entry.getAttrs().isDir() && !tmp[x].endsWith("/")) {
343: tmp[x] = tmp[x] + "/";
344: }
345:
346: x++;
347: }
348:
349: for (int i = 0; i < tmp.length; i++) {
350: files[i] = tmp[i];
351: }
352:
353: return files;
354: } catch (Exception ex) {
355: ex.printStackTrace();
356: Log.debug(" Error while listing directory: " + ex);
357: return new String[0];
358: }
359: }
360:
361: public String[] sortSize() {
362: return size;
363: }
364:
365: public int[] getPermissions() {
366: return perms;
367: }
368:
369: public int handleUpload(String f) {
370: if (Settings.getEnableSftpMultiThreading()) {
371:
372: Sftp2Transfer t = new Sftp2Transfer(getLocalPath(),
373: getPWD(), f, user, pass, listeners,
374: Transfer.UPLOAD, keyfile, host, "" + port);
375: } else {
376: upload(f);
377: }
378:
379: return 0;
380: }
381:
382: public int handleDownload(String f) {
383: if (Settings.getEnableSftpMultiThreading()) {
384: Sftp2Transfer t = new Sftp2Transfer(getLocalPath(),
385: getPWD(), f, user, pass, listeners,
386: Transfer.DOWNLOAD, keyfile, host, "" + port);
387: } else {
388: download(f);
389: }
390:
391: return 0;
392: }
393:
394: public int upload(String f) {
395: String file = toSFTP(f);
396:
397: if (file.endsWith("/")) {
398: String out = StringUtils.getDir(file);
399: uploadDir(file, getLocalPath() + out);
400: fireActionFinished(this );
401: } else {
402: String outfile = StringUtils.getFile(file);
403:
404: //System.out.println("transfer: " + file + ", " + getLocalPath() + outfile);
405: work(getLocalPath() + outfile, file, true);
406: fireActionFinished(this );
407: }
408:
409: return 0;
410: }
411:
412: public int download(String f) {
413: String file = toSFTP(f);
414:
415: if (file.endsWith("/")) {
416: String out = StringUtils.getDir(file);
417: downloadDir(file, getLocalPath() + out);
418: fireActionFinished(this );
419: } else {
420: String outfile = StringUtils.getFile(file);
421:
422: //System.out.println("transfer: " + file + ", " + getLocalPath() + outfile);
423: work(file, getLocalPath() + outfile, false);
424: fireActionFinished(this );
425: }
426:
427: return 0;
428: }
429:
430: private void downloadDir(String dir, String out) {
431: try {
432: //System.out.println("downloadDir: " + dir + "," + out);
433: fileCount = 0;
434: shortProgress = true;
435: baseFile = StringUtils.getDir(dir);
436:
437: Vector v = channel.ls(dir);
438:
439: String[] tmp = new String[v.size()];
440: SftpFile[] f = new SftpFile[v.size()];
441: Enumeration e = v.elements();
442: int x = 0;
443:
444: while (e.hasMoreElements()) {
445: LsEntry entry = ((LsEntry) e.nextElement());
446: tmp[x] = entry.getFilename();
447:
448: if (entry.getAttrs().isDir() && !tmp[x].endsWith("/")) {
449: tmp[x] = tmp[x] + "/";
450: }
451:
452: x++;
453: }
454:
455: File fx = new File(out);
456: fx.mkdir();
457:
458: for (int i = 0; i < tmp.length; i++) {
459: if (tmp[i].equals("./") || tmp[i].equals("../")) {
460: continue;
461: }
462:
463: tmp[i] = tmp[i].replace('\\', '/');
464:
465: //System.out.println("1: " + dir+tmp[i] + ", " + out +tmp[i]);
466:
467: if (tmp[i].endsWith("/")) {
468: if (!tmp[i].endsWith("/")) {
469: tmp[i] = tmp[i] + "/";
470: }
471:
472: downloadDir(dir + tmp[i], out + tmp[i]);
473: } else {
474: fileCount++;
475: fireProgressUpdate(baseFile, DataConnection.GETDIR
476: + ":" + fileCount, -1);
477: work(dir + tmp[i], out + tmp[i], false);
478: }
479:
480: }
481:
482: //System.out.println("enddir");
483:
484: fireProgressUpdate(baseFile, DataConnection.DFINISHED + ":"
485: + fileCount, -1);
486: } catch (Exception ex) {
487: ex.printStackTrace();
488: System.out.println(dir + ", " + out);
489: Log.debug("Transfer error: " + ex);
490: fireProgressUpdate(baseFile, DataConnection.FAILED + ":"
491: + fileCount, -1);
492: }
493:
494: shortProgress = false;
495: }
496:
497: private void uploadDir(String dir, String out) {
498: try {
499: //System.out.println("uploadDir: " + dir + "," + out);
500: isDirUpload = true;
501: fileCount = 0;
502: shortProgress = true;
503: baseFile = StringUtils.getDir(dir);
504:
505: File f2 = new File(out);
506: String[] tmp = f2.list();
507:
508: if (tmp == null) {
509: return;
510: }
511:
512: channel.mkdir(dir);
513: //channel.chmod(744, dir);
514:
515: for (int i = 0; i < tmp.length; i++) {
516: if (tmp[i].equals("./") || tmp[i].equals("../")) {
517: continue;
518: }
519:
520: tmp[i] = tmp[i].replace('\\', '/');
521:
522: //System.out.println("1: " + dir+tmp[i] + ", " + out +tmp[i]);
523: File f3 = new File(out + tmp[i]);
524:
525: if (f3.isDirectory()) {
526: if (!tmp[i].endsWith("/")) {
527: tmp[i] = tmp[i] + "/";
528: }
529:
530: uploadDir(dir + tmp[i], out + tmp[i]);
531: } else {
532: fileCount++;
533: fireProgressUpdate(baseFile, DataConnection.PUTDIR
534: + ":" + fileCount, -1);
535: work(out + tmp[i], dir + tmp[i], true);
536: }
537: }
538:
539: fireProgressUpdate(baseFile, DataConnection.DFINISHED + ":"
540: + fileCount, -1);
541: } catch (Exception ex) {
542: ex.printStackTrace();
543: System.out.println(dir + ", " + out);
544: Log.debug("Transfer error: " + ex);
545: fireProgressUpdate(baseFile, DataConnection.FAILED + ":"
546: + fileCount, -1);
547: }
548:
549: isDirUpload = false;
550: shortProgress = true;
551: }
552:
553: private String toSFTP(String f) {
554: String file;
555:
556: if (f.startsWith("/")) {
557: file = f;
558: } else {
559: file = getPWD() + f;
560: }
561:
562: file = file.replace('\\', '/');
563:
564: //System.out.println("file: "+file);
565: return file;
566: }
567:
568: private String toSFTPDir(String f) {
569: String file;
570:
571: if (f.startsWith("/")) {
572: file = f;
573: } else {
574: file = pwd + f;
575: }
576:
577: file = file.replace('\\', '/');
578:
579: if (!file.endsWith("/")) {
580: file = file + "/";
581: }
582:
583: //System.out.println("file: "+file);
584: return file;
585: }
586:
587: private void work(String file, String outfile, boolean up) {
588: BufferedInputStream in = null;
589: BufferedOutputStream out = null;
590:
591: //System.out.println("work");
592:
593: try {
594: boolean outflag = false;
595:
596: if (up) {
597: in = new BufferedInputStream(new FileInputStream(file));
598: } else {
599: in = new BufferedInputStream(channel.get(file));
600: }
601:
602: if (up) {
603: outflag = true;
604:
605: try {
606: channel.rm(outfile);
607: } catch (Exception ex) {
608:
609: }
610: out = new BufferedOutputStream(channel.put(outfile));
611: } else {
612: out = new BufferedOutputStream(new FileOutputStream(
613: outfile));
614: }
615:
616: //System.out.println("out: " + outfile + ", in: " + file);
617: byte[] buf = new byte[smbBuffer];
618: int len = 0;
619: int reallen = 0;
620:
621: //System.out.println(file+":"+getLocalPath()+outfile);
622: while (true) {
623: len = in.read(buf);
624:
625: //System.out.print(".");
626: if (len == StreamTokenizer.TT_EOF) {
627: break;
628: }
629:
630: out.write(buf, 0, len);
631: reallen += len;
632:
633: //System.out.println(file + ":" + StringUtils.getFile(file));
634: if (outflag) {
635: fireProgressUpdate(StringUtils.getFile(outfile),
636: DataConnection.PUT, reallen);
637: } else {
638: fireProgressUpdate(StringUtils.getFile(file),
639: DataConnection.GET, reallen);
640: }
641: }
642:
643: //if(up) {
644: // channel.chmod(744, outfile);
645: //}
646:
647: fireProgressUpdate(file, DataConnection.FINISHED, -1);
648: } catch (IOException ex) {
649: ex.printStackTrace();
650: Log.debug("Error with file IO (" + ex + ")!");
651: fireProgressUpdate(file, DataConnection.FAILED, -1);
652: } catch (SftpException ex) {
653: ex.printStackTrace();
654: Log.debug("Error with SFTP IO (" + ex + ")!");
655: fireProgressUpdate(file, DataConnection.FAILED, -1);
656: } finally {
657: try {
658: out.flush();
659: out.close();
660: in.close();
661: } catch (Exception ex) {
662: ex.printStackTrace();
663: }
664: }
665: }
666:
667: public boolean rename(String oldName, String newName) {
668: try {
669: oldName = toSFTP(oldName);
670: newName = toSFTP(newName);
671:
672: channel.rename(oldName, newName);
673:
674: return true;
675: } catch (Exception ex) {
676: ex.printStackTrace();
677:
678: Log.debug("Could rename file (" + ex + ").");
679:
680: return false;
681: }
682: }
683:
684: private void update(String file, String type, int bytes) {
685: if (listeners == null) {
686: return;
687: } else {
688: for (int i = 0; i < listeners.size(); i++) {
689: ConnectionListener listener = (ConnectionListener) listeners
690: .elementAt(i);
691: listener.updateProgress(file, type, bytes);
692: }
693: }
694: }
695:
696: public void addConnectionListener(ConnectionListener l) {
697: listeners.add(l);
698: }
699:
700: public void setConnectionListeners(Vector l) {
701: listeners = l;
702: }
703:
704: /** remote directory has changed */
705: public void fireDirectoryUpdate() {
706: if (listeners == null) {
707: return;
708: } else {
709: for (int i = 0; i < listeners.size(); i++) {
710: ((ConnectionListener) listeners.elementAt(i))
711: .updateRemoteDirectory(this );
712: }
713: }
714: }
715:
716: public boolean login(String user, String pass) {
717: this .user = user;
718: this .pass = pass;
719:
720: if (!login()) {
721: Log.debug("Login failed.");
722:
723: return false;
724: } else {
725: Log.debug("Authed successfully.");
726:
727: //if(!chdir(getPWD())) chdir("/");
728: }
729:
730: return true;
731: }
732:
733: /** progress update */
734: public void fireProgressUpdate(String file, String type, int bytes) {
735: if (listeners == null) {
736: return;
737: }
738:
739: for (int i = 0; i < listeners.size(); i++) {
740: ConnectionListener listener = (ConnectionListener) listeners
741: .elementAt(i);
742:
743: if (shortProgress && Settings.shortProgress) {
744: if (type.startsWith(DataConnection.DFINISHED)) {
745: listener.updateProgress(baseFile,
746: DataConnection.DFINISHED + ":" + fileCount,
747: bytes);
748: } else if (isDirUpload) {
749: listener.updateProgress(baseFile,
750: DataConnection.PUTDIR + ":" + fileCount,
751: bytes);
752: } else {
753: listener.updateProgress(baseFile,
754: DataConnection.GETDIR + ":" + fileCount,
755: bytes);
756: }
757: } else {
758: listener.updateProgress(file, type, bytes);
759: }
760: }
761: }
762:
763: public void fireActionFinished(Sftp2Connection con) {
764: if (listeners == null) {
765: return;
766: } else {
767: for (int i = 0; i < listeners.size(); i++) {
768: ((ConnectionListener) listeners.elementAt(i))
769: .actionFinished(con);
770: }
771: }
772: }
773:
774: public int upload(String file, InputStream i) {
775: BufferedOutputStream out = null;
776: BufferedInputStream in = null;
777:
778: try {
779: file = toSFTP(file);
780:
781: out = new BufferedOutputStream(channel.put(file));
782: in = new BufferedInputStream(i);
783:
784: //Log.debug(getLocalPath() + ":" + file+ ":"+getPWD());
785: byte[] buf = new byte[smbBuffer];
786: int len = 0;
787: int reallen = 0;
788:
789: while (true) {
790: len = in.read(buf);
791:
792: //System.out.print(".");
793: if (len == StreamTokenizer.TT_EOF) {
794: break;
795: }
796:
797: out.write(buf, 0, len);
798: reallen += len;
799:
800: fireProgressUpdate(StringUtils.getFile(file),
801: DataConnection.PUT, reallen);
802: }
803:
804: //channel.chmod(744, file);
805:
806: fireProgressUpdate(file, DataConnection.FINISHED, -1);
807:
808: return 0;
809: } catch (IOException ex) {
810: ex.printStackTrace();
811: Log.debug("Error with file IO (" + ex + ")!");
812: fireProgressUpdate(file, DataConnection.FAILED, -1);
813:
814: return -1;
815: } catch (SftpException ex) {
816: ex.printStackTrace();
817: Log.debug("Error with file SFTP IO (" + ex + ")!");
818: fireProgressUpdate(file, DataConnection.FAILED, -1);
819:
820: return -1;
821: } finally {
822: try {
823: out.flush();
824: out.close();
825: in.close();
826: } catch (Exception ex) {
827: ex.printStackTrace();
828: }
829: }
830: }
831:
832: public InputStream getDownloadInputStream(String file) {
833: try {
834:
835: return channel.get(file);
836: } catch (SftpException ex) {
837: ex.printStackTrace();
838: Log.debug(ex.toString()
839: + " @Sftp2Connection::getDownloadInputStream");
840:
841: return null;
842: }
843: }
844:
845: public Date[] sortDates() {
846: return null;
847: }
848: }
849:
850: class MyUserInfo implements UserInfo {
851:
852: String password;
853:
854: public MyUserInfo(String pass) {
855: this .password = pass;
856: }
857:
858: public String getPassword() {
859: return password;
860: }
861:
862: public boolean promptYesNo(String str) {
863: /*
864: Object[] options={ "yes", "no" };
865: int foo=JOptionPane.showOptionDialog(null,
866: str,
867: "Warning",
868: JOptionPane.DEFAULT_OPTION,
869: JOptionPane.WARNING_MESSAGE,
870: null, options, options[0]);
871: return foo==0;
872: */
873:
874: return true;
875: }
876:
877: public String getPassphrase() {
878: return password;
879: }
880:
881: public boolean promptPassphrase(String message) {
882: return true;
883: }
884:
885: public boolean promptPassword(String message) {
886: return true;
887: }
888:
889: public void showMessage(String message) {
890: JOptionPane.showMessageDialog(null, message);
891: }
892: }
|