Handle hostnames with upper-case letters
[webmin.git] / bacula-backup / TreeChooser.java
1 import java.awt.*;
2 import java.io.*;
3 import java.applet.*;
4 import java.net.*;
5 import java.util.*;
6 import netscape.javascript.JSObject;
7
8 public class TreeChooser extends Applet
9         implements CbButtonCallback, HierarchyCallback
10 {
11         CbButton add_b, remove_b, close_b;
12         Hierarchy tree;
13         BaculaNode root;
14         String volume;
15         String session;
16         String job;
17         Vector added = new Vector();
18
19         public void init()
20         {
21         // Create the root
22         String rpath = getParameter("root");
23         root = new BaculaNode(this, rpath, true, null);
24         volume = getParameter("volume");
25         session = getParameter("session");
26         job = getParameter("job");
27
28         // Build the UI
29         setLayout(new BorderLayout());
30         BorderPanel top = new BorderPanel(2);
31         top.setLayout(new FlowLayout(FlowLayout.LEFT));
32         top.add(add_b = new CbButton("Add", this));
33         top.add(remove_b = new CbButton("Remove", this));
34         top.add(close_b = new CbButton("Close", this));
35         add("North", top);
36         add("Center", tree = new Hierarchy(root, this));
37         }
38
39         Image get_image(String img)
40         {
41         return getImage(getDocumentBase(), "images/"+img);
42         }
43
44         String[] get_text(String url)
45         {
46         Cursor orig = getCursor();
47         try {
48                 Cursor busy = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
49                 setCursor(busy);
50                 long now = System.currentTimeMillis();
51                 if (url.indexOf('?') > 0) url += "&rand="+now;
52                 else url += "?rand="+now;
53                 URL u = new URL(getDocumentBase(), url);
54                 URLConnection uc = u.openConnection();
55                 set_cookie(uc);
56                 String charset = get_charset(uc.getContentType());
57                 BufferedReader is = new BufferedReader(
58                         (charset == null) ?
59                         new InputStreamReader(uc.getInputStream()) :
60                         new InputStreamReader(uc.getInputStream(), charset));
61                 Vector lv = new Vector();
62                 while(true) {
63                         String l = is.readLine();
64                         if (l == null) { break; }
65                         lv.addElement(l);
66                         }
67                 is.close();
68                 String rv[] = new String[lv.size()];
69                 lv.copyInto(rv);
70                 return rv;
71                 }
72         catch(Exception e) {
73                 e.printStackTrace();
74                 //return null;
75                 String err[] = { e.getMessage() };
76                 return err;
77                 }
78         finally {
79                 setCursor(orig);
80                 }
81         }
82
83         void set_cookie(URLConnection conn)
84         {
85         if (session != null)
86                 conn.setRequestProperty("Cookie", session);
87         }
88
89         // Gets charset parameter from Content-Type: header
90         String get_charset(String ct)
91         {
92         if (ct == null)
93                 return null;
94         StringTokenizer st = new StringTokenizer(ct, ";");
95         while (st.hasMoreTokens()) {
96                 String l = st.nextToken().trim().toLowerCase();
97                 if (l.startsWith("charset=")) {
98                         // get the value of charset= param.
99                         return l.substring(8);
100                         }
101                 }
102         return null;
103         }
104
105         public void openNode(Hierarchy h, HierarchyNode n)
106         {
107         // Get the files under this directory, and expand the tree
108         BaculaNode bn = (BaculaNode)n;
109         bn.fill();
110         }
111
112         public void closeNode(Hierarchy h, HierarchyNode n)
113         {
114         // No need to do anything
115         }
116
117         public void clickNode(Hierarchy h, HierarchyNode n)
118         {
119         // Also no need to do anything
120         }
121
122         public void doubleNode(Hierarchy h, HierarchyNode n)
123         {
124         // add or remove a file
125         BaculaNode sel = (BaculaNode)n;
126         if (sel.added) remove_node(sel);
127         else add_node(sel);
128         }
129
130         public void click(CbButton b)
131         {
132         BaculaNode sel = (BaculaNode)tree.selected();
133         if (b == close_b) {
134                 // Close the window, and update the text box
135                 try {
136                         JSObject win = JSObject.getWindow(this);
137                         String params1[] = { "" };
138                         win.call("clear_files", params1);
139                         for(int i=0; i<added.size(); i++) {
140                                 BaculaNode n = (BaculaNode)added.elementAt(i);
141                                 String params2[] = { n.path };
142                                 if (n.isdir && !n.path.equals("/"))
143                                         params2[0] = n.path+"/";
144                                 win.call("add_file", params2);
145                                 }
146                         String params3[] = { "" };
147                         win.call("finished", params3);
148                         }
149                 catch(Exception e) {
150                         e.printStackTrace();
151                         new ErrorWindow("Failed to set files : "+
152                                         e.getMessage());
153                         }
154                 }
155         else if (b == add_b) {
156                 // Flag the selected file as added
157                 if (sel != null) {
158                         add_node(sel);
159                         }
160                 }
161         else if (b == remove_b) {
162                 // Un-flag the selected file
163                 if (sel != null) {
164                         remove_node(sel);
165                         }
166                 }
167         }
168
169         void add_node(BaculaNode n)
170         {
171         if (!n.added) {
172                 n.added = true;
173                 n.set_all_icons();
174                 tree.redraw();
175                 added.addElement(n);
176                 }
177         }
178
179         void remove_node(BaculaNode n)
180         {
181         if (n.added) {
182                 n.added = false;
183                 n.set_all_icons();
184                 tree.redraw();
185                 added.removeElement(n);
186                 }
187         }
188
189         static String urlize(String s)
190         {
191         StringBuffer rv = new StringBuffer();
192         for(int i=0; i<s.length(); i++) {
193                 char c = s.charAt(i);
194                 if (c < 16)
195                         rv.append("%0"+Integer.toString(c, 16));
196                 else if (!Character.isLetterOrDigit(c) && c != '/' &&
197                     c != '.' && c != '_' && c != '-')
198                         rv.append("%"+Integer.toString(c, 16));
199                 else
200                         rv.append(c);
201                 }
202         return rv.toString();
203         }
204 }
205
206 class BaculaNode extends HierarchyNode
207 {
208         TreeChooser parent;
209         String path;
210         boolean isdir;
211         boolean known = false;
212         boolean added = false;
213         BaculaNode dir;
214
215         BaculaNode(TreeChooser parent, String path, boolean isdir, BaculaNode dir)
216         {
217         this.parent = parent;
218         this.path = path;
219         this.isdir = isdir;
220         this.dir = dir;
221         open = false;
222         set_icon();
223         ch = isdir ? new Vector() : null;
224         if (path.equals("/"))
225                 text = "/";
226         else {
227                 String ns = path.endsWith("/") ?
228                                 path.substring(0, path.length() - 1) : path;
229                 int slash = ns.lastIndexOf("/");
230                 text = path.substring(slash+1);
231                 }
232         }
233
234         void set_icon()
235         {
236         String imname = isdir ? "dir.gif" : "rfile.gif";
237         if (selected()) imname = "s"+imname;
238         im = parent.get_image(imname);
239         }
240
241         void set_all_icons()
242         {
243         set_icon();
244         if (ch != null) {
245                 for(int i=0; i<ch.size(); i++) {
246                         BaculaNode c = (BaculaNode)ch.elementAt(i);
247                         c.set_all_icons();
248                         }
249                 }
250         }
251
252         void fill()
253         {
254         if (!known && isdir) {
255                 ch.removeAllElements();
256                 String l[] = parent.get_text("list.cgi?dir="+
257                                              parent.urlize(path)+
258                                              "&volume="+
259                                              parent.urlize(parent.volume)+
260                                              "&job="+
261                                              parent.urlize(parent.job));
262                 if (l[0].length() > 0) {
263                         new ErrorWindow("Failed to get files under "+path+
264                                         " : "+l[0]);
265                         return;
266                         }
267                 for(int i=1; i<l.length; i++) {
268                         if (l[i].endsWith("/")) {
269                                 ch.addElement(
270                                     new BaculaNode(
271                                             parent, l[i].substring(0, l[i].length()-1),
272                                             true, this));
273                                 }
274                         else {
275                                 ch.addElement(
276                                     new BaculaNode(
277                                         parent, l[i], false, this));
278                                 }
279                         }
280                 parent.tree.redraw();
281                 known = true;
282                 }
283         }
284
285         boolean selected()
286         {
287         BaculaNode n = this;
288         while(n != null) {
289                 if (n.added) return true;
290                 n = n.dir;
291                 }
292         return false;
293         }
294 }
295