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