Rev Author Line No. Line
185 miho 1 <?php
2 # vim:et:ts=3:sts=3:sw=3:fdm=marker:
3  
4 // WebSVN - Subversion repository viewing via the web using PHP
5 // Copyright © 2004-2006 Tim Armes, Matt Sicker
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 //
21 // --
22 //
23 // listing.php
24 //
25 // Show the listing for the given repository/path/revision
26  
27 require_once("include/setup.inc");
28 require_once("include/svnlook.inc");
29 require_once("include/utils.inc");
30 require_once("include/template.inc");
31 require_once("include/bugtraq.inc");
32  
33 function removeURLSeparator($url)
34 {
35 return preg_replace('#(\?|&(amp;)?)$#', '', $url);
36 }
37  
38 function fileLink($path, $file, $returnjoin = false)
39 {
40 global $rep, $passrev, $showchanged, $config;
41  
42 if ($path == "" || $path{0} != "/")
43 $ppath = "/".$path;
44 else
45 $ppath = $path;
46  
47 if ($ppath{strlen($ppath)-1} != "/")
48 $ppath .= "/";
49  
50 if ($file{0} == "/")
51 $pfile = substr($file, 1);
52 else
53 $pfile = $file;
54  
55 if ($returnjoin)
56 return $ppath.$pfile;
57  
58 $isDir = $pfile{strlen($pfile) - 1} == "/";
59  
60 if ($passrev) $passrevstr = "rev=$passrev&amp;"; else $passrevstr = "";
61 if ($showchanged) $showchangedstr = "sc=$showchanged"; else $showchangedstr = "";
62  
63 if ($isDir)
64 {
65 $url = $config->getURL($rep, $ppath.$pfile, "dir");
66  
67 // XHTML doesn't allow slashes in IDs ~J
68 $id = str_replace('/', '_', $ppath.$pfile);
69 $url = "<a id='$id' href=\"${url}$passrevstr$showchangedstr";
70  
71 $url = removeURLSeparator($url);
72 if ($config->treeView) $url .= "#$id";
73 $url .= "\">$pfile</a>";
74 }
75 else
76 {
77 $url = $config->getURL($rep, $ppath.$pfile, "file");
78 $url .= $passrevstr.$showchangedstr;
79 $url = removeURLSeparator($url);
80 $url = "<a href=\"${url}\">$pfile</a>";
81 }
82  
83 return $url;
84 }
85  
86 function showDirFiles($svnrep, $subs, $level, $limit, $rev, $listing, $index, $treeview = true)
87 {
88 global $rep, $passrev, $showchanged, $config, $lang;
89  
90 $path = "";
91  
92 if (!$treeview)
93 $level = $limit;
94  
95 for ($n = 0; $n <= $level; $n++)
96 {
97 $path .= $subs[$n]."/";
98 }
99  
100 $contents = $svnrep->dirContents($path, $rev);
101  
102 // List each file in the current directory
103 $loop = 0;
104 $last_index = 0;
105 $openDir = false;
106 $fullaccess = $rep->hasReadAccess($path, false);
107  
108 foreach($contents as $file)
109 {
110 $isDir = ($file{strlen($file) - 1} == "/"?1:0);
111 $access = false;
112  
113 if ($isDir)
114 {
115 if ($rep->hasReadAccess($path.$file, true))
116 {
117 $access = true;
118 $openDir = (!strcmp($subs[$level+1]."/", $file) || !strcmp($subs[$level+1], $file));
119  
120 if ($openDir)
121 $listing[$index]["filetype"] = "diropen";
122 else
123 $listing[$index]["filetype"] = "dir";
124  
125 if ($rep->isDownloadAllowed($path.$file))
126 {
127 $dlurl = $config->getURL($rep, $path.$file, "dl");
128 $listing[$index]["fileviewdllink"] = "<a href=\"${dlurl}rev=$passrev&amp;isdir=1\">${lang["TARBALL"]}</a>";
129 }
130 else
131 $listing[$index]["fileviewdllink"] = "&nbsp;";
132 }
133 }
134 else
135 {
136 if ($fullaccess)
137 {
138 $access = true;
139 if ($level != $limit)
140 {
141 // List directories only, skip all files
142 continue;
143 }
144  
145 $listing[$index]["fileviewdllink"] = "&nbsp;";
146 $listing[$index]["filetype"] = strrchr($file, ".");
147 }
148 }
149  
150 if ($access)
151 {
152 $listing[$index]["rowparity"] = ($index % 2)?"1":"0";
153  
154 if ($treeview)
155 $listing[$index]["compare_box"] = "<input type=\"checkbox\" name=\"compare[]\" value=\"".fileLink($path, $file, true)."@$passrev\" onclick=\"checkCB(this)\" />";
156 else
157 $listing[$index]["compare_box"] = "";
158  
159 if ($openDir)
160 $listing[$index]["filelink"] = "<b>".fileLink($path, $file)."</b>";
161 else
162 $listing[$index]["filelink"] = fileLink($path, $file);
163  
164 // The history command doesn't return with a trailing slash. We need to remember here if the
165 // file is a directory or not!
166  
167 $listing[$index]["isDir"] = $isDir;
168  
169 if ($treeview)
170 $listing[$index]["level"] = $level;
171 else
172 $listing[$index]["level"] = 0;
173  
174 $listing[$index]["node"] = 0; // t-node
175  
176 $fileurl = $config->getURL($rep, $path.$file, "log");
177 $listing[$index]["fileviewloglink"] = "<a href=\"${fileurl}rev=$passrev&amp;sc=$showchanged&amp;isdir=$isDir\">${lang["VIEWLOG"]}</a>";
178  
179 $rssurl = $config->getURL($rep, $path.$file, "rss");
180 if ($rep->getHideRss())
181 {
182 $listing[$index]["rsslink"] = "<a href=\"${rssurl}rev=$passrev&amp;sc=$showchanged&amp;isdir=$isDir\">${lang["RSSFEED"]}</a>";
183 $listing[$index]["rssanchor"] = "<a href=\"${rssurl}rev=$passrev&amp;sc=$showchanged&amp;isdir=$isDir\">";
184 }
185  
186 $index++;
187 $loop++;
188 $last_index = $index;
189  
190 if (($level != $limit) && ($isDir))
191 {
192 if (!strcmp($subs[$level + 1]."/", $file))
193 {
194 $listing = showDirFiles($svnrep, $subs, $level + 1, $limit, $rev, $listing, $index);
195 $index = count($listing);
196 }
197 }
198  
199 }
200 }
201  
202 if ($last_index != 0 && $treeview)
203 {
204 $listing[$last_index - 1]["node"] = 1; // l-node
205 }
206  
207 return $listing;
208 }
209  
210 function showTreeDir($svnrep, $path, $rev, $listing)
211 {
212 global $vars, $config;
213  
214 $subs = explode("/", $path);
215  
216 // For directory, the last element in the subs is empty.
217 // For file, the last element in the subs is the file name.
218 // Therefore, it is always count($subs) - 2
219 $limit = count($subs) - 2;
220  
221 for ($n = 0; $n < $limit; $n++)
222 {
223 $vars["last_i_node"][$n] = FALSE;
224 }
225  
226 return showDirFiles($svnrep, $subs, 0, $limit, $rev, $listing, 0, $config->treeView);
227  
228 }
229  
230 // Make sure that we have a repository
231 if (!isset($rep))
232 {
233 echo $lang["NOREP"];
234 exit;
235 }
236  
237 $svnrep = new SVNRepository($rep);
238  
239 // Revision info to pass along chain
240 $passrev = $rev;
241  
242 // Get the directory contents of the given revision, or HEAD if not defined
243 $contents = $svnrep->dirContents($path, @$rev);
244  
245 // If there's no revision info, go to the lastest revision for this path
246 $history = $svnrep->getLog($path, "", "", false);
247  
248 if (!empty($history->entries[0]))
249 $youngest = $history->entries[0]->rev;
250 else
251 $youngest = -1;
252  
253 // Unless otherwise specified, we get the log details of the latest change
254 if (empty($rev))
255 $logrev = $youngest;
256 else
257 $logrev = $rev;
258  
259 if ($logrev != $youngest)
260 {
261 $logEntry = $svnrep->getLog($path, $logrev, $logrev, false);
262 $logEntry = $logEntry->entries[0];
263 }
264 else
265 $logEntry = $history->entries[0];
266  
267 $headlog = $svnrep->getLog("/", "", "", true, 1);
268 $headrev = $headlog->entries[0]->rev;
269  
270 // If we're not looking at a specific revision, get the HEAD revision number
271 // (the revision of the rest of the tree display)
272  
273 if (empty($rev))
274 {
275 $rev = $headrev;
276 }
277  
278 if ($path == "" || $path{0} != "/")
279 $ppath = "/".$path;
280 else
281 $ppath = $path;
282  
283 $vars["repname"] = $rep->getDisplayName();
284  
285 $dirurl = $config->getURL($rep, $path, "dir");
286 $logurl = $config->getURL($rep, $path, "log");
287 $rssurl = $config->getURL($rep, $path, "rss");
288 $dlurl = $config->getURL($rep, $path, "dl");
289 $compurl = $config->getURL($rep, "/", "comp");
290  
291 if ($passrev != 0 && $passrev != $headrev && $youngest != -1)
292 $vars["goyoungestlink"] = "<a href=\"${dirurl}opt=dir&amp;sc=1\">${lang["GOYOUNGEST"]}</a>";
293 else
294 $vars["goyoungestlink"] = "";
295  
296 $bugtraq = new Bugtraq($rep, $svnrep, $ppath);
297  
298 $vars["action"] = "";
299 $vars["rev"] = $rev;
300 $vars["path"] = $ppath;
301 $vars["lastchangedrev"] = $logrev;
302 $vars["date"] = $logEntry->date;
303 $vars["author"] = $logEntry->author;
304 $vars["log"] = nl2br($bugtraq->replaceIDs(create_anchors($logEntry->msg)));
305  
306 if (!$showchanged)
307 {
308 $vars["showchangeslink"] = "<a href=\"${dirurl}rev=$passrev&amp;sc=1\">${lang["SHOWCHANGED"]}</a>";
309 $vars["hidechangeslink"] = "";
310  
311 $vars["hidechanges"] = true;
312 $vars["showchanges"] = false;
313 }
314 else
315 {
316 $vars["showchangeslink"] = "";
317  
318 $changes = $logEntry->mods;
319  
320 $firstAdded = true;
321 $firstModded = true;
322 $firstDeleted = true;
323  
324 $vars["newfilesbr"] = "";
325 $vars["newfiles"] = "";
326 $vars["changedfilesbr"] = "";
327 $vars["changedfiles"] = "";
328 $vars["deletedfilesbr"] = "";
329 $vars["deletedfiles"] = "";
330  
331 foreach ($changes as $file)
332 {
333 switch ($file->action)
334 {
335 case "A":
336 if (!$firstAdded) $vars["newfilesbr"] .= "<br />";
337 $firstAdded = false;
338 $vars["newfilesbr"] .= fileLink("", $file->path);
339 $vars["newfiles"] .= " ".fileLink("", $file->path);
340 break;
341  
342 case "M":
343 if (!$firstModded) $vars["changedfilesbr"] .= "<br />";
344 $firstModded = false;
345 $vars["changedfilesbr"] .= fileLink("", $file->path);
346 $vars["changedfiles"] .= " ".fileLink("", $file->path);
347 break;
348  
349 case "D":
350 if (!$firstDeleted) $vars["deletedfilesbr"] .= "<br />";
351 $firstDeleted = false;
352 $vars["deletedfilesbr"] .= $file->path;
353 $vars["deletedfiles"] .= " ".$file->path;
354 break;
355 }
356 }
357  
358 $vars["hidechangeslink"] = "<a href=\"${dirurl}rev=$passrev&amp;sc=0\">${lang["HIDECHANGED"]}</a>";
359  
360 $vars["hidechanges"] = false;
361 $vars["showchanges"] = true;
362 }
363  
364 createDirLinks($rep, $ppath, $passrev, $showchanged);
365 $vars["curdirloglink"] = "<a href=\"${logurl}rev=$passrev&amp;sc=$showchanged&amp;isdir=1\">${lang["VIEWLOG"]}</a>";
366  
367 if ($rev != $headrev)
368 {
369 $history = $svnrep->getLog($path, $rev, "", false);
370 }
371  
372 if (isset($history->entries[1]->rev))
373 {
374 $vars["curdircomplink"] = "<a href=\"${compurl}compare[]=".
375 urlencode($history->entries[1]->path)."@".$history->entries[1]->rev.
376 "&amp;compare[]=".urlencode($history->entries[0]->path)."@".$history->entries[0]->rev.
377 "\">${lang["DIFFPREV"]}</a>";
378 }
379 else
380 {
381 $vars["curdircomplink"] = "";
382 }
383  
384 if ($rep->getHideRss())
385 {
386 $vars["curdirrsslink"] = "<a href=\"${rssurl}rev=$passrev&amp;sc=$showchanged&amp;isdir=1\">${lang["RSSFEED"]}</a>";
387 $vars["curdirrsshref"] = "${rssurl}rev=$passrev&amp;sc=$showchanged&amp;isdir=1";
388 $vars["curdirrssanchor"] = "<a href=\"${rssurl}rev=$passrev&amp;sc=$showchanged&amp;isdir=1\">";
389 }
390  
391 // Set up the tarball link
392  
393 $subs = explode("/", $path);
394 $level = count($subs) - 2;
395 if ($rep->isDownloadAllowed($path))
396 $vars["curdirdllink"] = "<a href=\"${dlurl}rev=$passrev&amp;isdir=1\">${lang["TARBALL"]}</a>";
397 else
398 $vars["curdirdllink"] = "";
399  
400 $url = $config->getURL($rep, "/", "comp");
401  
402 $vars["compare_form"] = "<form action=\"$url\" method=\"post\" name=\"compareform\">";
403 $vars["compare_submit"] = "<input name=\"comparesubmit\" type=\"submit\" value=\"${lang["COMPAREPATHS"]}\" />";
404 $vars["compare_endform"] = "<input type=\"hidden\" name=\"op\" value=\"comp\" /><input type=\"hidden\" name=\"sc\" value=\"$showchanged\" /></form>";
405  
406 $listing = array();
407 $listing = showTreeDir($svnrep, $path, $rev, $listing);
408  
409 $vars["version"] = $version;
410  
411 if (!$rep->hasReadAccess($path, true))
412 $vars["noaccess"] = true;
413  
414 if (!$rep->hasReadAccess($path, false))
415 $vars["restricted"] = true;
416  
417 parseTemplate($rep->getTemplatePath()."header.tmpl", $vars, $listing);
418 parseTemplate($rep->getTemplatePath()."directory.tmpl", $vars, $listing);
419 parseTemplate($rep->getTemplatePath()."footer.tmpl", $vars, $listing);
420  
421 ?>