1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Chora
15: {
16: 17: 18: 19: 20:
21: static public $restricted;
22:
23: 24: 25: 26: 27:
28: static public $rtcache;
29:
30: 31: 32: 33: 34:
35: static public $fdcache;
36:
37: 38: 39: 40: 41: 42: 43: 44: 45:
46: static public function ($where, $onb = null)
47: {
48: $bar = '';
49: $dirs = explode('/', $where);
50: $dir_count = count($dirs) - 1;
51:
52: $path = '';
53: foreach ($dirs as $i => $dir) {
54: if (!empty($path)) {
55: $path .= '/';
56: }
57: $path .= $dir;
58: if (!empty($dir)) {
59: $url = self::url('browsedir', $path . ($i == $dir_count && !$GLOBALS['atdir'] ? '' : '/'));
60: if (!empty($onb)) {
61: $url = $url->add('onb', $onb);
62: }
63: $bar .= '/ <a href="' . $url . '">' . $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($dir, 'space2html', array('encode' => true, 'encode_all' => true)) . '</a> ';
64: }
65: }
66:
67: return $bar;
68: }
69:
70: 71: 72: 73: 74: 75: 76:
77: static public function fatal($message, $code = null)
78: {
79: global $notification, $registry;
80:
81: if (is_a($message, 'Horde_Vcs_Exception')) {
82: $message = $message->getMessage();
83: }
84:
85: if ($code) {
86: header('HTTP/1.0 ' . $code);
87: }
88:
89:
90: $registry->pushApp('chora');
91:
92: $notification->push($message, 'horde.error');
93: require $registry->get('templates', 'horde') . '/common-header.inc';
94: require CHORA_TEMPLATES . '/menu.inc';
95: require $registry->get('templates', 'horde') . '/common-footer.inc';
96: exit;
97: }
98:
99: 100: 101: 102: 103: 104: 105: 106: 107: 108:
109: static public function url($script, $uri = '', $args = array(),
110: $anchor = '')
111: {
112: $arglist = self::_getArgList($GLOBALS['acts'],
113: $GLOBALS['defaultActs'],
114: $args);
115: $script .= '.php';
116:
117: if ($GLOBALS['conf']['options']['urls'] == 'rewrite') {
118: switch ($script) {
119: case 'browsefile.php':
120: case 'browsedir.php':
121: if (substr($uri, 0, 1) == '/') {
122: $script = "browse$uri";
123: } else {
124: $script = "browse/$uri";
125: }
126: $script = urlencode(isset($args['rt']) ? $args['rt'] : $GLOBALS['acts']['rt']) . "/-/$script";
127: unset($arglist['rt']);
128: break;
129:
130: case 'patchsets.php':
131: if (!empty($args['ps'])) {
132: $script = urlencode(isset($args['rt']) ? $args['rt'] : $GLOBALS['acts']['rt']) . '/-/commit/' . $args['ps'];
133: unset($arglist['ps']);
134: } else {
135: $script .= '/' . $uri;
136: }
137: break;
138:
139: default:
140: $script .= '/' . $uri;
141: }
142: } elseif (!empty($uri)) {
143: $arglist['f'] = $uri;
144: }
145:
146: return Horde::url($script)->add($arglist)->setAnchor($anchor);
147: }
148:
149: 150: 151: 152: 153:
154: static public function formInputs()
155: {
156: $arglist = self::_getArgList($GLOBALS['acts'], $GLOBALS['defaultActs'], array());
157:
158: $fields = Horde_Util::formInput();
159: foreach ($arglist as $key => $val) {
160: $fields .= '<input type="hidden" name="' . htmlspecialchars($key) . '" value="' . htmlspecialchars($val) . '" />';
161: }
162:
163: return $fields;
164: }
165:
166: 167: 168:
169: static protected function _getArgList($acts, $defaultActs, $args)
170: {
171: $differing = array();
172:
173: foreach ($acts as $key => $val) {
174: if ($val != $defaultActs[$key]) {
175: $differing[$key] = $val;
176: }
177: }
178:
179: return array_merge($differing, $args);
180: }
181:
182: 183: 184:
185: static public function checkPerms($key)
186: {
187: return (!$GLOBALS['injector']->getInstance('Horde_Perms')->exists('chora:sourceroots:' . $key) ||
188: $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission('chora:sourceroots:' . $key, $GLOBALS['registry']->getAuth(), Horde_Perms::READ | Horde_Perms::SHOW));
189: }
190:
191: 192: 193: 194: 195: 196:
197: static public function sourceroots()
198: {
199: $arr = array();
200:
201: foreach ($GLOBALS['sourceroots'] as $key => $val) {
202: if (self::checkPerms($key)) {
203: $arr[$key] = $val;
204: }
205: }
206:
207: return $arr;
208: }
209:
210: 211: 212: 213: 214: 215:
216: static public function repositories()
217: {
218: $sourceroots = self::sourceroots();
219: $num_repositories = count($sourceroots);
220:
221: if ($num_repositories == 1) {
222: return '';
223: }
224:
225: $arr = array();
226: foreach ($sourceroots as $key => $val) {
227: if ($GLOBALS['sourceroot'] != $key) {
228: $arr[] = '<option value="' . self::url('browsedir', '', array('rt' => $key)) . '">' . $val['name'] . '</option>';
229: }
230: }
231:
232: return '<form action="#" id="repository-picker">' .
233: '<select onchange="location.href=this[this.selectedIndex].value">' .
234: '<option value="">' . _("Change repositories:") . '</option>' .
235: implode('', $arr) . '</select></form>';
236: }
237:
238: 239: 240: 241: 242: 243: 244: 245: 246: 247:
248: static public function pretty($mime_type, $fp)
249: {
250: $lns = '';
251: while ($ln = fread($fp, 8192)) {
252: $lns .= $ln;
253: }
254:
255: $mime = new Horde_Mime_Part();
256: $mime->setType($mime_type);
257: $mime->setContents($lns);
258:
259: return $GLOBALS['injector']->getInstance('Horde_Core_Factory_MimeViewer')->create($mime);
260: }
261:
262: 263: 264: 265: 266: 267: 268:
269: static public function isRestricted($where)
270: {
271:
272: if (!self::checkPerms($GLOBALS['sourceroot'])) {
273: return true;
274: }
275:
276: if (!isset(self::$restricted)) {
277: $restricted = array();
278:
279: if (isset($GLOBALS['conf']['restrictions']) &&
280: is_array($GLOBALS['conf']['restrictions'])) {
281: $restricted = $GLOBALS['conf']['restrictions'];
282: }
283:
284: foreach ($GLOBALS['sourceroots'] as $key => $val) {
285: if (($GLOBALS['sourceroot'] == $key) &&
286: isset($val['restrictions']) &&
287: is_array($val['restrictions'])) {
288: $restricted = array_merge($restricted, $val['restrictions']);
289: break;
290: }
291: }
292:
293: self::$restricted = $restricted;
294: }
295:
296: if (!empty($restricted)) {
297: for ($i = 0; $i < count($restricted); ++$i) {
298: if (preg_match('|' . str_replace('|', '\|', $restricted[$i]) . '|', $where)) {
299: return true;
300: }
301: }
302: }
303:
304: return false;
305: }
306:
307: 308: 309: 310: 311: 312: 313: 314: 315:
316: static public function getFileViews($where, $current)
317: {
318: $views = ($current == 'browsefile')
319: ? array('<em class="widget">' . _("Logs") . '</em>')
320: : array(Horde::widget(self::url('browsefile', $where), _("Logs"), 'widget', '', '', _("_Logs")));
321:
322: if ($GLOBALS['VC']->hasFeature('patchsets')) {
323: $views[] = ($current == 'patchsets')
324: ? '<em class="widget">' . _("Patchsets") . '</em>'
325: : Horde::widget(self::url('patchsets', $where), _("Patchsets"), 'widget', '', '', _("_Patchsets"));
326: }
327:
328: if ($GLOBALS['VC']->hasFeature('branches')) {
329: if (empty($GLOBALS['conf']['paths']['cvsgraph']) ||
330: !($GLOBALS['VC'] instanceof Horde_Vcs_Cvs)) {
331: $views[] = ($current == 'history')
332: ? '<em class="widget">' . _("Branches") . '</em>'
333: : Horde::widget(self::url('history', $where), _("Branches"), 'widget', '', '', _("_Branches"));
334: } else {
335: $views[] = ($current == 'cvsgraph')
336: ? '<em class="widget">' . _("Branches") . '</em>'
337: : Horde::widget(self::url('cvsgraph', $where), _("Branches"), 'widget', '', '', _("_Branches"));
338: }
339: }
340:
341: $views[] = ($current == 'stats')
342: ? '<em class="widget">' . _("Statistics") . '</em>'
343: : Horde::widget(self::url('stats', $where), _("Statistics"), 'widget', '', '', _("_Statistics"));
344:
345: return _("View:") . ' ' . implode(' | ', $views);
346: }
347:
348: 349: 350: 351: 352: 353: 354: 355:
356: static public function getTags($lg, $where)
357: {
358: $tags = array();
359:
360: foreach ($lg->getSymbolicBranches() as $symb => $bra) {
361: $tags[] = self::url('browsefile', $where, array('onb' => $bra))->link() . htmlspecialchars($symb) . '</a>';
362: }
363:
364: foreach ($lg->getTags() as $tag) {
365: $tags[] = htmlspecialchars($tag);
366: }
367:
368: return $tags;
369: }
370:
371: 372: 373: 374: 375: 376: 377: 378: 379:
380: static public function readableTime($date, $long = false)
381: {
382:
383: if (!isset(self::$rtcache)) {
384: $desc = array(
385: 1 => array(_("second"), _("seconds")),
386: 60 => array(_("minute"), _("minutes")),
387: 3600 => array(_("hour"), _("hours")),
388: 86400 => array(_("day"), _("days")),
389: 604800 => array(_("week"), _("weeks")),
390: 2628000 => array(_("month"), _("months")),
391: 31536000 => array(_("year"), _("years"))
392: );
393:
394: self::$rtcache = array(
395: 'breaks' => array_keys($desc),
396: 'desc' => $desc,
397: 'time' => time(),
398: );
399: }
400:
401: $cache = self::$rtcache;
402: $i = count($cache['breaks']);
403: $secs = $cache['time'] - $date;
404:
405: if ($secs < 2) {
406: return _("very little time");
407: }
408:
409: while (--$i && $i && $cache['breaks'][$i] * 2 > $secs);
410:
411: $break = $cache['breaks'][$i];
412:
413: $val = intval($secs / $break);
414: $retval = $val . ' ' . ($val > 1 ? $cache['desc'][$break][1] : $cache['desc'][$break][0]);
415: if ($long && $i > 0) {
416: $rest = $secs % $break;
417: $break = $cache['breaks'][--$i];
418: $rest = (int)($rest / $break);
419: if ($rest > 0) {
420: $retval .= ', ' . $rest . ' ' . ($rest > 1 ? $cache['desc'][$break][1] : $cache['desc'][$break][0]);
421: }
422: }
423:
424: return $retval;
425: }
426:
427: 428: 429: 430: 431: 432: 433:
434: static public function showAuthorName($name, $fullname = false)
435: {
436: try {
437: $users = $GLOBALS['VC']->getUsers($GLOBALS['chora_conf']['cvsusers']);
438: if (isset($users[$name])) {
439: return '<a href="mailto:' . htmlspecialchars($users[$name]['mail']) . '">' .
440: htmlspecialchars($fullname ? $users[$name]['name'] : $name) .
441: '</a>' . ($fullname ? ' <em>' . htmlspecialchars($name) . '</em>' : '');
442: }
443: } catch (Horde_Vcs_Exception $e) {}
444:
445: return htmlspecialchars($name);
446: }
447:
448: static public function getAuthorEmail($name)
449: {
450: try {
451: $users = $GLOBALS['VC']->getUsers($GLOBALS['chora_conf']['cvsusers']);
452: if (isset($users[$name])) {
453: return $users[$name]['mail'];
454: }
455: } catch (Horde_Vcs_Exception $e) {}
456:
457: try {
458: $parser = new Horde_Mail_Rfc822();
459: $results = $parser->parseAddressList($name);
460: if (count($results)) {
461: return $results[0]->mailbox . '@' . $results[0]->host;
462: }
463: } catch (Horde_Mail_Exception $e) {
464: try {
465: if (preg_match('|<(\S+)>|', $name, $matches)) {
466: return self::getAuthorEmail($matches[1]);
467: }
468: } catch (Horde_Mail_Exception $e){}
469: }
470:
471: return $name;
472: }
473:
474:
475: 476: 477: 478: 479: 480: 481:
482: static public function formatDate($date)
483: {
484: if (!isset(self::$fdcache)) {
485: self::$fdcache = $GLOBALS['prefs']->getValue('date_format') .
486: ($GLOBALS['prefs']->getValue('twenty_four')
487: ? ' %H:%M'
488: : ' %I:%M %p');
489: }
490:
491: return strftime(self::$fdcache, $date);
492: }
493:
494: 495: 496: 497: 498: 499: 500:
501: static public function formatLogMessage($log)
502: {
503: $log = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($log, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
504:
505: return (empty($GLOBALS['conf']['tickets']['regexp']) || empty($GLOBALS['conf']['tickets']['replacement']))
506: ? $log
507: : preg_replace($GLOBALS['conf']['tickets']['regexp'], $GLOBALS['conf']['tickets']['replacement'], $log);
508: }
509:
510: }
511: