1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
16 package net.sf.jftp.net.wrappers;
17 
18 import java.io.BufferedInputStream;
19 import java.io.BufferedOutputStream;
20 import java.io.File;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.StreamTokenizer;
25 import java.util.Date;
26 import java.util.Vector;
27 
28 import net.sf.jftp.config.Settings;
29 import net.sf.jftp.net.BasicConnection;
30 import net.sf.jftp.net.ConnectionListener;
31 import net.sf.jftp.net.DataConnection;
32 import net.sf.jftp.net.FtpConnection;
33 import net.sf.jftp.system.StringUtils;
34 import net.sf.jftp.system.logging.Log;
35 
36 import org.apache.commons.httpclient.HttpException;
37 import org.apache.commons.httpclient.HttpURL;
38 import org.apache.webdav.lib.WebdavFile;
39 import org.apache.webdav.lib.WebdavResource;
40 
41 
42 public class WebdavConnection implements BasicConnection
43 {
44     public static int webdavBuffer = 32000;
45     private String path = "";
46     private String pwd = "";
47     private Vector listeners = new Vector();
48     private String[] files;
49     private String[] size = new String[0];
50     private int[] perms = null;
51     private String baseFile;
52     private int fileCount;
53     private boolean shortProgress = false;
54     private String user;
55     private String pass;
56 
WebdavConnection(String path, String user, String pass, ConnectionListener l)57     public WebdavConnection(String path, String user, String pass,
58                             ConnectionListener l)
59     {
60         this.user = user;
61         this.pass = pass;
62 
63         listeners.add(l);
64         chdir(path);
65     }
66 
removeFileOrDir(String file)67     public int removeFileOrDir(String file)
68     {
69         Log.debug("Feature is not implemented yet");
70 
71         if(true)
72         {
73             return -1;
74         }
75 
76         try
77         {
78             if((file == null) || file.equals(""))
79             {
80                 return -1;
81             }
82 
83             String tmp = file;
84 
85             if(StringUtils.isRelative(file))
86             {
87                 tmp = getPWD() + file;
88             }
89 
90             WebdavFile f = new WebdavFile(getURL(tmp));
91 
92             if(!f.getAbsolutePath().equals(f.getCanonicalPath()))
93             {
94                 //Log.debug("WARNING: Symlink removed");//Skipping symlink, remove failed.");
95                 //Log.debug("This is necessary to prevent possible data loss when removing those symlinks.");
96                 //return -1;
97                 if(!f.delete())
98                 {
99                     return -1;
100                 }
101             }
102 
103             if(f.exists() && f.isDirectory())
104             {
105                 cleanLocalDir(tmp);
106             }
107 
108             //System.out.println(tmp);
109             if(!f.delete())
110             {
111                 Log.debug("Removal failed.");
112 
113                 return -1;
114             }
115         }
116         catch(Exception ex)
117         {
118             Log.debug("Error: " + ex.toString());
119             ex.printStackTrace();
120         }
121 
122         return -1;
123     }
124 
cleanLocalDir(String dir)125     private void cleanLocalDir(String dir)
126     {
127         try
128         {
129             dir = dir.replace('\\', '/');
130 
131             if(!dir.endsWith("/"))
132             {
133                 dir = dir + "/";
134             }
135 
136             //String remoteDir = StringUtils.removeStart(dir,path);
137             //System.out.println(">>> " + dir);
138             WebdavFile f2 = new WebdavFile(getURL(dir));
139             String[] tmp = f2.list();
140 
141             if(tmp == null)
142             {
143                 return;
144             }
145 
146             for(int i = 0; i < tmp.length; i++)
147             {
148                 WebdavFile f3 = new WebdavFile(getURL(dir + tmp[i]));
149 
150                 if(!f3.getAbsolutePath().equals(f3.getCanonicalPath()))
151                 {
152                     //Log.debug("WARNING: Symlink remove");//Skipping symlink, remove may fail.");
153                     f3.delete();
154 
155                     //Log.debug("This is necessary to prevent possible data loss when removing those symlinks.");
156                     //continue;
157                 }
158 
159                 if(f3.isDirectory())
160                 {
161                     //System.out.println(dir);
162                     cleanLocalDir(dir + tmp[i]);
163                     f3.delete();
164                 }
165                 else
166                 {
167                     //System.out.println(dir+tmp[i]);
168                     f3.delete();
169                 }
170             }
171         }
172         catch(Exception ex)
173         {
174             Log.debug("Error: " + ex.toString());
175             ex.printStackTrace();
176         }
177     }
178 
sendRawCommand(String cmd)179     public void sendRawCommand(String cmd)
180     {
181     }
182 
disconnect()183     public void disconnect()
184     {
185     }
186 
isConnected()187     public boolean isConnected()
188     {
189         return true;
190     }
191 
getPWD()192     public String getPWD()
193     {
194         return pwd;
195     }
196 
cdup()197     public boolean cdup()
198     {
199         return chdir(pwd.substring(0, pwd.lastIndexOf("/") + 1));
200     }
201 
mkdir(String dirName)202     public boolean mkdir(String dirName)
203     {
204         Log.debug("Feature is not implemented yet");
205 
206         if(true)
207         {
208             return false;
209         }
210 
211         try
212         {
213             if(StringUtils.isRelative(dirName))
214             {
215                 dirName = getPWD() + dirName;
216             }
217 
218             WebdavFile f = new WebdavFile(getURL(dirName));
219 
220             boolean x = f.mkdir();
221             fireDirectoryUpdate();
222 
223             return x;
224         }
225         catch(Exception ex)
226         {
227             Log.debug("Error: " + ex.toString());
228             ex.printStackTrace();
229 
230             return false;
231         }
232     }
233 
list()234     public void list() throws IOException
235     {
236     }
237 
chdir(String p)238     public boolean chdir(String p)
239     {
240         try
241         {
242             String p2 = processPath(p);
243 
244             if(p2 == null)
245             {
246                 return false;
247             }
248 
249             //WebdavFile f = new WebdavFile(getURL(p2));
250             WebdavResource f = getResource(p2);
251 
252             if(!f.exists() || !f.isCollection()) //!f.isDirectory() || !f.canRead())
253             {
254                 Log.debug("Access denied.");
255 
256                 return false;
257             }
258 
259             pwd = p2;
260 
261             Log.out("PWD: " + pwd);
262 
263             fireDirectoryUpdate();
264 
265             return true;
266         }
267         catch(Exception ex)
268         {
269             Log.debug("Error: " + ex.toString());
270             ex.printStackTrace();
271 
272             return false;
273         }
274     }
275 
chdirNoRefresh(String p)276     public boolean chdirNoRefresh(String p)
277     {
278         String p2 = processPath(p);
279 
280         if(p2 == null)
281         {
282             return false;
283         }
284 
285         //System.out.println(p2);
286         pwd = p2;
287 
288         return true;
289     }
290 
getLocalPath()291     public String getLocalPath()
292     {
293         //System.out.println("local: " + path);
294         return path;
295     }
296 
processPath(String p)297     public String processPath(String p)
298     {
299         try
300         {
301             if(!p.startsWith("http://"))
302             {
303                 p = pwd + p;
304             }
305 
306             if(!p.endsWith("/"))
307             {
308                 p = p + "/";
309             }
310 
311             while(p.endsWith("/../"))
312             {
313                 p = p.substring(0, p.lastIndexOf("/../") - 1);
314                 p = p.substring(0, p.lastIndexOf("/"));
315             }
316 
317             while(p.endsWith("/./"))
318             {
319                 p = p.substring(0, p.lastIndexOf("/./") - 1);
320                 p = p.substring(0, p.lastIndexOf("/"));
321             }
322 
323             //System.out.println(", processPath 2: "+p);
324             //WebdavFile f = new WebdavFile(getURL(p));
325             Log.out("\n\n\nprocessPath URL: " + p);
326 
327             WebdavResource f = getResource(p);
328             String p2 = p;
329 
330             if(f.exists() && f.isCollection())
331             {
332                 try
333                 {
334                     //p2 = f.toURL(); //CanonicalPath();
335                     if(!p2.endsWith("/"))
336                     {
337                         p2 = p2 + "/";
338                     }
339 
340                     //Log.out("processPath parsed URL: " + p);
341                     //Log.out("processPath URL2: " + f.getPath());
342                     return p2;
343                 }
344                 catch(Exception ex)
345                 {
346                     Log.debug("Error: can not get pathname (processPath)!");
347 
348                     return null;
349                 }
350             }
351             else
352             {
353                 Log.debug("(processpPath) No such path: \"" + p + "\"");
354 
355                 return null;
356             }
357         }
358         catch(Exception ex)
359         {
360             Log.debug("Error: " + ex.toString());
361             ex.printStackTrace();
362 
363             return null;
364         }
365     }
366 
setLocalPath(String p)367     public boolean setLocalPath(String p)
368     {
369         try
370         {
371             p = p.replace('\\', '/');
372 
373             //System.out.print("local 1:" + p);
374             if(StringUtils.isRelative(p))
375             {
376                 p = path + p;
377             }
378 
379             p = p.replace('\\', '/');
380 
381             //System.out.println(", local 2:" + p);
382             File f = new File(p);
383 
384             if(f.exists())
385             {
386                 try
387                 {
388                     path = f.getCanonicalPath();
389                     path = path.replace('\\', '/');
390 
391                     if(!path.endsWith("/"))
392                     {
393                         path = path + "/";
394                     }
395 
396                     //System.out.println("localPath: "+path);
397                 }
398                 catch(Exception ex)
399                 {
400                     Log.debug("Error: can not get pathname (local)!");
401 
402                     return false;
403                 }
404             }
405             else
406             {
407                 Log.debug("(local) No such path: \"" + p + "\"");
408 
409                 return false;
410             }
411 
412             return true;
413         }
414         catch(Exception ex)
415         {
416             Log.debug("Error: " + ex.toString());
417             ex.printStackTrace();
418 
419             return false;
420         }
421     }
422 
sortLs()423     public String[] sortLs()
424     {
425         try
426         {
427             Log.out("sortLs PWD: " + pwd);
428 
429             //WebdavFile fl = new WebdavFile(new URL(pwd), user, pass);
430             WebdavResource fp = getResource(pwd);
431 
432             //new WebdavResource(getURL(pwd));
433             //files = f.list();
434             //File[] f = fl.listFiles();
435             WebdavResource[] f = fp.listWebdavResources();
436 
437             //if(files == null) return new String[0];
438             files = new String[f.length];
439             size = new String[f.length];
440             perms = new int[f.length];
441 
442             int accessible = 0;
443 
444             for(int i = 0; i < f.length; i++)
445             {
446                 files[i] = f[i].getName();
447 
448                 /*
449                 while(files[i].indexOf("%20") >= 0)
450                 {
451                         int x = files[i].indexOf("%20");
452                         String tmp = files[i].substring(0,x)+" "+
453                                         files[i].substring(files[i].indexOf("%20")+3);
454                         files[i] = tmp;
455                 }
456                 */
457                 /*
458                 try
459                 {
460                         f[i].exists();
461                 }
462                 catch(Exception ex)
463                 {
464                         Log.debug("ERROR: parsing problem with:" + files[i]);
465                         size[i] = "-1";
466                         perms[i] = FtpConnection.DENIED;
467                         continue;
468                 }
469                 */
470                 Log.out("sortLs files[" + i + "]: " + files[i]);
471 
472                 //size[i] = "" + (int) f[i].length();
473                 size[i] = "" + (int) f[i].getGetContentLength();
474                 perms[i] = FtpConnection.R;
475 
476                 if(f[i].isCollection() && !files[i].endsWith("/"))
477                 {
478                     files[i] = files[i] + "/";
479                 }
480 
481                 /*
482                 if(f[i].canWrite()) accessible = FtpConnection.W;
483                 else if(f[i].canRead()) accessible = FtpConnection.R;
484                 else accessible = FtpConnection.DENIED;
485                 perms[i] = accessible;
486 
487                 Log.out("sortLs files["+i+"]: " + files[i]);
488                 WebdavFile f2 = new WebdavFile(new URL(files[i]), user, pass);
489 
490                 if(!f2.exists()) continue;
491                 if(f2.isDirectory() && !files[i].endsWith("/")) files[i] = files[i] + "/";
492 
493                 size[i] = "" + new WebdavFile(new URL(files[i]), user, pass).length();
494                 */
495             }
496 
497             return files;
498         }
499         catch(Exception ex)
500         {
501             Log.debug("Error: " + ex.toString());
502             ex.printStackTrace();
503 
504             return new String[0];
505         }
506     }
507 
sortSize()508     public String[] sortSize()
509     {
510         return size;
511     }
512 
getPermissions()513     public int[] getPermissions()
514     {
515         return perms;
516     }
517 
handleDownload(String file)518     public int handleDownload(String file)
519     {
520         transfer(file);
521 
522         return 0;
523     }
524 
handleUpload(String file)525     public int handleUpload(String file)
526     {
527         transfer(file, true);
528 
529         return 0;
530     }
531 
download(String file)532     public int download(String file)
533     {
534         transfer(file);
535 
536         return 0;
537     }
538 
upload(String file)539     public int upload(String file)
540     {
541         transfer(file, true);
542 
543         return 0;
544     }
545 
transferDir(String dir, String out)546     private void transferDir(String dir, String out)
547     {
548         try
549         {
550             fileCount = 0;
551             shortProgress = true;
552             baseFile = StringUtils.getDir(dir);
553 
554             WebdavFile f2 = new WebdavFile(getURL(dir));
555             String[] tmp = f2.list();
556 
557             if(tmp == null)
558             {
559                 return;
560             }
561 
562             WebdavFile fx = new WebdavFile(getURL(out));
563 
564             if(!fx.mkdir())
565             {
566                 Log.debug("Can not create directory: " + out +
567                           " - already exist or permission denied?");
568             }
569 
570             for(int i = 0; i < tmp.length; i++)
571             {
572                 tmp[i] = tmp[i].replace('\\', '/');
573 
574                 //System.out.println("1: " + dir+tmp[i] + ", " + out +tmp[i]);
575                 WebdavFile f3 = new WebdavFile(getURL(dir + tmp[i]));
576 
577                 if(f3.isDirectory())
578                 {
579                     if(!tmp[i].endsWith("/"))
580                     {
581                         tmp[i] = tmp[i] + "/";
582                     }
583 
584                     transferDir(dir + tmp[i], out + tmp[i]);
585                 }
586                 else
587                 {
588                     fireProgressUpdate(baseFile,
589                                        DataConnection.GETDIR + ":" + fileCount,
590                                        -1);
591                     work(dir + tmp[i], out + tmp[i]);
592                 }
593             }
594 
595             fireProgressUpdate(baseFile,
596                                DataConnection.DFINISHED + ":" + fileCount, -1);
597             shortProgress = false;
598         }
599         catch(Exception ex)
600         {
601             Log.debug("Error: " + ex.toString());
602             ex.printStackTrace();
603         }
604     }
605 
getURL(String u)606     private HttpURL getURL(String u)
607     {
608         try
609         {
610             HttpURL url = new HttpURL(u);
611 
612             //System.out.println(user + ":"+ pass);
613             url.setUserinfo(user, pass);
614 
615             return url;
616         }
617         catch(Exception ex)
618         {
619             ex.printStackTrace();
620             Log.debug("ERROR: " + ex);
621 
622             return null;
623         }
624     }
625 
getResource(String res)626     private WebdavResource getResource(String res)
627                                 throws HttpException, IOException
628     {
629         return new WebdavResource(getURL(res));
630     }
631 
transfer(String file)632     private void transfer(String file)
633     {
634         transfer(file, false);
635     }
636 
transfer(String file, boolean up)637     private void transfer(String file, boolean up)
638     {
639         String out = StringUtils.getDir(file);
640 
641         if(StringUtils.isRelative(file))
642         {
643             file = getPWD() + file;
644         }
645 
646         file = file.replace('\\', '/');
647         out = out.replace('\\', '/');
648 
649         String outfile = StringUtils.getFile(file);
650 
651         if(file.endsWith("/"))
652         {
653             if(up)
654             {
655                 Log.debug("Directory upload not implemented yet.");
656 
657                 return;
658             }
659 
660             transferDir(file, getLocalPath() + out);
661 
662             return;
663         }
664         else
665         {
666             if(up)
667             {
668                 work(getLocalPath() + outfile, file);
669             }
670             else
671             {
672                 work(file, getLocalPath() + outfile);
673             }
674         }
675     }
676 
work(String file, String outfile)677     private void work(String file, String outfile)
678     {
679         Log.out("transfer started\nfile: " + file + "\noutfile: " + outfile);
680 
681         BufferedInputStream in = null;
682         BufferedOutputStream out = null;
683 
684         try
685         {
686             if(outfile.startsWith("http://"))
687             {
688                 //out = new BufferedOutputStream(new FileOutputStream(new WebdavResource(new HttpURL(file)).getMethodData());
689                 //new WebdavFile(new URL(outfile), user, pass)));
690                 //in = new BufferedInputStream(new FileInputStream(file));
691                 String resPath = outfile.substring(0,
692                                                    outfile.lastIndexOf("/") +
693                                                    1);
694                 String name = outfile.substring(outfile.lastIndexOf("/") + 1);
695 
696                 Log.debug("Uploading " + file + " to " + resPath + " as " +
697                           name);
698 
699                 //HttpURL url = getURL(resPath);
700                 WebdavResource res = getResource(resPath);
701 
702                 //new WebdavResource(url);
703 
704                 /*
705                 if(res.checkinMethod()) Log.debug("Checkin OK");
706                 else Log.debug("Checkin FAILED");
707 
708                 Enumeration e = res.getAllowedMethods();
709                 while(e != null && e.hasMoreElements())
710                 {
711                         Log.debug("Method: " + e.nextElement().toString());
712                 }
713                 */
714                 if(res.putMethod(new File(file)))
715                 {
716                     fireProgressUpdate(file, DataConnection.FINISHED, -1);
717                 }
718                 else
719                 {
720                     Log.debug("Upload failed.");
721                     fireProgressUpdate(file, DataConnection.FAILED, -1);
722                 }
723 
724                 return;
725             }
726 
727             Log.debug("Downloading " + file + " to " + outfile);
728 
729             out = new BufferedOutputStream(new FileOutputStream(outfile));
730             in = new BufferedInputStream(getResource(file).getMethodData());
731 
732             //new WebdavResource(getURL(file)).getMethodData());
733             byte[] buf = new byte[webdavBuffer];
734             int len = 0;
735             int reallen = 0;
736 
737             //System.out.println(file+":"+getLocalPath()+outfile);
738             while(true)
739             {
740                 len = in.read(buf);
741 
742                 //System.out.print(".");
743                 if(len == StreamTokenizer.TT_EOF)
744                 {
745                     break;
746                 }
747 
748                 out.write(buf, 0, len);
749 
750                 reallen += len;
751                 fireProgressUpdate(StringUtils.getFile(file),
752                                    DataConnection.GET, reallen);
753             }
754 
755             fireProgressUpdate(file, DataConnection.FINISHED, -1);
756         }
757         catch(IOException ex)
758         {
759             Log.debug("Error with file IO (" + ex + ")!");
760             ex.printStackTrace();
761             fireProgressUpdate(file, DataConnection.FAILED, -1);
762         }
763         finally
764         {
765             try
766             {
767                 out.flush();
768                 out.close();
769                 in.close();
770             }
771             catch(Exception ex)
772             {
773                 ex.printStackTrace();
774             }
775         }
776     }
777 
upload(String file, InputStream in)778     public int upload(String file, InputStream in)
779     {
780         /*
781            if(StringUtils.isRelative(file)) file = getPWD() + file;
782            file = file.replace('\\','/');
783 
784            try
785            {
786                    work(new BufferedInputStream(in), file, file);
787                    return 0;
788            }
789            catch(Exception ex)
790            {
791                    Log.debug("Error: " + ex.toString());
792                    ex.printStackTrace();
793                    return -1;
794            }
795            */
796         Log.debug("Upload using InputStream is not implemented yet!");
797 
798         return -1;
799     }
800 
801     /*
802     private void work(BufferedInputStream in, String outfile, String file)
803     {
804      Log.out("transfer started, input from stream\noutfile: " + outfile);
805 
806      try
807      {
808              BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outfile));
809         byte buf[] = new byte[webdavBuffer];
810         int len = 0;
811         int reallen = 0;
812 
813         while(true)
814         {
815                 len = in.read(buf);
816                 System.out.print(".");
817                 if(len == StreamTokenizer.TT_EOF) break;
818                 out.write(buf,0,len);
819 
820                 reallen += len;
821                 fireProgressUpdate(StringUtils.getFile(file),DataConnection.GET, reallen);
822         }
823 
824         out.flush();
825         out.close();
826         in.close();
827         fireProgressUpdate(file,DataConnection.FINISHED, -1);
828      }
829      catch(IOException ex)
830      {
831              Log.debug("Error with file IO ("+ex+")!");
832         ex.printStackTrace();
833         fireProgressUpdate(file,DataConnection.FAILED, -1);
834      }
835     }
836     */
getDownloadInputStream(String file)837     public InputStream getDownloadInputStream(String file)
838     {
839         if(StringUtils.isRelative(file))
840         {
841             file = getPWD() + file;
842         }
843 
844         file = file.replace('\\', '/');
845 
846         try
847         {
848             return getResource(file).getMethodData();
849         }
850         catch(Exception ex)
851         {
852             ex.printStackTrace();
853             Log.debug(ex.toString() +
854                       " @WebdavConnection::getDownloadInputStream");
855 
856             return null;
857         }
858     }
859 
addConnectionListener(ConnectionListener l)860     public void addConnectionListener(ConnectionListener l)
861     {
862         listeners.add(l);
863     }
864 
setConnectionListeners(Vector l)865     public void setConnectionListeners(Vector l)
866     {
867         listeners = l;
868     }
869 
870     /** remote directory has changed */
fireDirectoryUpdate()871     public void fireDirectoryUpdate()
872     {
873         if(listeners == null)
874         {
875             return;
876         }
877         else
878         {
879             for(int i = 0; i < listeners.size(); i++)
880             {
881                 ((ConnectionListener) listeners.elementAt(i)).updateRemoteDirectory(this);
882             }
883         }
884     }
885 
login(String user, String pass)886     public boolean login(String user, String pass)
887     {
888         return true;
889     }
890 
fireProgressUpdate(String file, String type, int bytes)891     public void fireProgressUpdate(String file, String type, int bytes)
892     {
893         if(listeners == null)
894         {
895             return;
896         }
897         else
898         {
899             for(int i = 0; i < listeners.size(); i++)
900             {
901                 ConnectionListener listener = (ConnectionListener) listeners.elementAt(i);
902 
903                 if(shortProgress && Settings.shortProgress)
904                 {
905                     if(type.startsWith(DataConnection.DFINISHED))
906                     {
907                         listener.updateProgress(baseFile,
908                                                 DataConnection.DFINISHED + ":" +
909                                                 fileCount, bytes);
910                     }
911 
912                     listener.updateProgress(baseFile,
913                                             DataConnection.GETDIR + ":" +
914                                             fileCount, bytes);
915                 }
916                 else
917                 {
918                     listener.updateProgress(file, type, bytes);
919                 }
920             }
921         }
922     }
923 
sortDates()924     public Date[] sortDates()
925     {
926         return null;
927     }
928 
rename(String from, String to)929     public boolean rename(String from, String to)
930     {
931         Log.debug("Not implemented!");
932 
933         return false;
934     }
935 }
936