From a0a9acb9a284910e6b7dd95c847e8226dde7732d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 21 Mar 2010 18:47:43 -0700 Subject: Fix broken assertion --- tests/ActivityParseTests.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ActivityParseTests.php b/tests/ActivityParseTests.php index 9d8fd47af..02d2ed734 100644 --- a/tests/ActivityParseTests.php +++ b/tests/ActivityParseTests.php @@ -207,7 +207,7 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertTrue(is_array($actor->avatarLinks)); $this->assertEquals(1, count($actor->avatarLinks)); $this->assertEquals('http://files.posterous.com/user_profile_pics/480326/2009-08-05-142447.jpg', - $actor->avatarLinks[0]); + $actor->avatarLinks[0]->url); $this->assertNotNull($actor->poco); $this->assertEquals('evanpro', $actor->poco->preferredUsername); $this->assertEquals('Evan Prodromou', $actor->poco->displayName); -- cgit v1.2.3-54-g00ecf From 5697e4edb0fc4bb1d4c9365100501e795b2553de Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 22 Mar 2010 10:35:54 -0700 Subject: Replace the "give up and dump object" attachment view fallback with a client-side redirect to the target URL, which will at least be useful. --- lib/attachmentlist.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 51ceca857..fe38281af 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -306,7 +306,7 @@ class Attachment extends AttachmentListItem function showRepresentation() { if (empty($this->oembed->type)) { if (empty($this->attachment->mimetype)) { - $this->out->element('pre', null, 'oh well... not sure how to handle the following: ' . print_r($this->attachment, true)); + $this->showFallback(); } else { switch ($this->attachment->mimetype) { case 'image/gif': @@ -332,6 +332,8 @@ class Attachment extends AttachmentListItem $this->out->element('param', array('name' => 'autoStart', 'value' => 1)); $this->out->elementEnd('object'); break; + default: + $this->showFallback(); } } } else { @@ -354,9 +356,23 @@ class Attachment extends AttachmentListItem break; default: - $this->out->element('pre', null, 'oh well... not sure how to handle the following oembed: ' . print_r($this->oembed, true)); + $this->showFallback(); } } } + + function showFallback() + { + // If we don't know how to display an attachment inline, we probably + // shouldn't have gotten to this point. + // + // But, here we are... displaying details on a file or remote URL + // either on the main view or in an ajax-loaded lightbox. As a lesser + // of several evils, we'll try redirecting to the actual target via + // client-side JS. + + common_log(LOG_ERR, "Empty or unknown type for file id {$this->attachment->id}; falling back to client-side redirect."); + $this->out->raw(''); + } } -- cgit v1.2.3-54-g00ecf From 3678e7b89bd0cc683c98369e5dec3b940134532b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 22 Mar 2010 15:55:13 -0700 Subject: OStatus remote sending test cases. Doesn't actually run within PHPUnit right now, must be run from command line -- specify base URLs to two StatusNet sites that will be able to communicate with each other. Current test run includes: * register accounts (via web form) * local post * @-mention using path (@domain/path/to/user) Subscriptions, webfinger mentions, various paths to subscription and unsubscription, etc to come. --- plugins/OStatus/tests/remote-tests.php | 392 +++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 plugins/OStatus/tests/remote-tests.php diff --git a/plugins/OStatus/tests/remote-tests.php b/plugins/OStatus/tests/remote-tests.php new file mode 100644 index 000000000..103ca066c --- /dev/null +++ b/plugins/OStatus/tests/remote-tests.php @@ -0,0 +1,392 @@ +a = $a; + $this->b = $b; + + $base = 'test' . mt_rand(1, 1000000); + $this->pub = new SNTestClient($this->a, 'pub' . $base, 'pw-' . mt_rand(1, 1000000)); + $this->sub = new SNTestClient($this->b, 'sub' . $base, 'pw-' . mt_rand(1, 1000000)); + } + + function run() + { + $this->setup(); + $this->testLocalPost(); + $this->testMentionUrl(); + $this->log("DONE!"); + } + + function setup() + { + $this->pub->register(); + $this->pub->assertRegistered(); + + $this->sub->register(); + $this->sub->assertRegistered(); + } + + function testLocalPost() + { + $post = $this->pub->post("Local post, no subscribers yet."); + $this->assertNotEqual('', $post); + + $post = $this->sub->post("Local post, no subscriptions yet."); + $this->assertNotEqual('', $post); + } + + /** + * pub posts: @b/sub + */ + function testMentionUrl() + { + $bits = parse_url($this->b); + $base = $bits['host']; + if (isset($bits['path'])) { + $base .= $bits['path']; + } + $name = $this->sub->username; + + $post = $this->pub->post("@$base/$name should have this in home and replies"); + $this->sub->assertReceived($post); + } +} + +class SNTestClient extends TestBase +{ + function __construct($base, $username, $password) + { + $this->basepath = $base; + $this->username = $username; + $this->password = $password; + + $this->fullname = ucfirst($username) . ' Smith'; + $this->homepage = 'http://example.org/' . $username; + $this->bio = 'Stub account for OStatus tests.'; + $this->location = 'Montreal, QC'; + } + + /** + * Make a low-level web hit to this site, with authentication. + * @param string $path URL fragment for something under the base path + * @param array $params POST parameters to send + * @param boolean $auth whether to include auth data + * @return string + * @throws Exception on low-level error conditions + */ + protected function hit($path, $params=array(), $auth=false, $cookies=array()) + { + $url = $this->basepath . '/' . $path; + + $http = new HTTP_Request2($url, 'POST'); + if ($auth) { + $http->setAuth($this->username, $this->password, HTTP_Request2::AUTH_BASIC); + } + foreach ($cookies as $name => $val) { + $http->addCookie($name, $val); + } + $http->addPostParameter($params); + $response = $http->send(); + + $code = $response->getStatus(); + if ($code < '200' || $code >= '400') { + throw new Exception("Failed API hit to $url: $code\n" . $response->getBody()); + } + + return $response; + } + + /** + * Make a hit to a web form, without authentication but with a session. + * @param string $path URL fragment relative to site base + * @param string $form id of web form to pull initial parameters from + * @param array $params POST parameters, will be merged with defaults in form + */ + protected function web($path, $form, $params=array()) + { + $url = $this->basepath . '/' . $path; + $http = new HTTP_Request2($url, 'GET'); + $response = $http->send(); + + $dom = $this->checkWeb($url, 'GET', $response); + $cookies = array(); + foreach ($response->getCookies() as $cookie) { + // @fixme check for expirations etc + $cookies[$cookie['name']] = $cookie['value']; + } + + $form = $dom->getElementById($form); + if (!$form) { + throw new Exception("Form $form not found on $url"); + } + $inputs = $form->getElementsByTagName('input'); + foreach ($inputs as $item) { + $type = $item->getAttribute('type'); + if ($type != 'check') { + $name = $item->getAttribute('name'); + $val = $item->getAttribute('value'); + if ($name && $val && !isset($params[$name])) { + $params[$name] = $val; + } + } + } + + $response = $this->hit($path, $params, false, $cookies); + $dom = $this->checkWeb($url, 'POST', $response); + + return $dom; + } + + protected function checkWeb($url, $method, $response) + { + $dom = new DOMDocument(); + if (!$dom->loadHTML($response->getBody())) { + throw new Exception("Invalid HTML from $method to $url"); + } + + $xpath = new DOMXPath($dom); + $error = $xpath->query('//p[@class="error"]'); + if ($error && $error->length) { + throw new Exception("Error on $method to $url: " . + $error->item(0)->textContent); + } + + return $dom; + } + + /** + * Make an API hit to this site, with authentication. + * @param string $path URL fragment for something under 'api' folder + * @param string $style one of 'json', 'xml', or 'atom' + * @param array $params POST parameters to send + * @return mixed associative array for JSON, DOMDocument for XML/Atom + * @throws Exception on low-level error conditions + */ + protected function api($path, $style, $params=array()) + { + $response = $this->hit("api/$path.$style", $params, true); + $body = $response->getBody(); + if ($style == 'json') { + $data = json_decode($body, true); + if ($data !== null) { + if (!empty($data['error'])) { + throw new Exception("JSON API returned error: " . $data['error']); + } + return $data; + } else { + throw new Exception("Bogus JSON data from $path:\n$body"); + } + } else if ($style == 'xml' || $style == 'atom') { + $dom = new DOMDocument(); + if ($dom->loadXML($body)) { + return $dom; + } else { + throw new Exception("Bogus XML data from $path:\n$body"); + } + } else { + throw new Exception("API needs to be JSON, XML, or Atom"); + } + } + + /** + * Register the account. + * + * Unfortunately there's not an API method for registering, so we fake it. + */ + function register() + { + $this->log("Registering user %s on %s", + $this->username, + $this->basepath); + $ret = $this->web('main/register', 'form_register', + array('nickname' => $this->username, + 'password' => $this->password, + 'confirm' => $this->password, + 'fullname' => $this->fullname, + 'homepage' => $this->homepage, + 'bio' => $this->bio, + 'license' => 1, + 'submit' => 'Register')); + } + + /** + * Check that the account has been registered and can be used. + * On failure, throws a test failure exception. + */ + function assertRegistered() + { + $this->log("Confirming %s is registered on %s", + $this->username, + $this->basepath); + $data = $this->api('account/verify_credentials', 'json'); + $this->assertEqual($this->username, $data['screen_name']); + $this->assertEqual($this->fullname, $data['name']); + $this->assertEqual($this->homepage, $data['url']); + $this->assertEqual($this->bio, $data['description']); + } + + /** + * Post a given message from this account + * @param string $message + * @return string URL/URI of notice + * @todo reply, location options + */ + function post($message) + { + $this->log("Posting notice as %s on %s: %s", + $this->username, + $this->basepath, + $message); + $data = $this->api('statuses/update', 'json', + array('status' => $message)); + + $url = $this->basepath . '/notice/' . $data['id']; + return $url; + } + + /** + * Check that this account has received the notice. + * @param string $notice_uri URI for the notice to check for + */ + function assertReceived($notice_uri) + { + $timeout = 5; + $tries = 6; + while ($tries) { + $ok = $this->checkReceived($notice_uri); + if ($ok) { + return true; + } + $tries--; + if ($tries) { + $this->log("Didn't see it yet, waiting $timeout seconds"); + sleep($timeout); + } + } + throw new Exception("Message $notice_uri not received by $this->username"); + } + + /** + * Pull the user's home timeline to check if a notice with the given + * source URL has been received recently. + * If we don't see it, we'll try a couple more times up to 10 seconds. + * + * @param string $notice_uri + */ + function checkReceived($notice_uri) + { + $this->log("Checking if %s on %s received notice %s", + $this->username, + $this->basepath, + $notice_uri); + $params = array(); + $dom = $this->api('statuses/home_timeline', 'atom', $params); + + $xml = simplexml_import_dom($dom); + if (!$xml->entry) { + return false; + } + if (is_array($xml->entry)) { + $entries = $xml->entry; + } else { + $entries = array($xml->entry); + } + foreach ($entries as $entry) { + if ($entry->id == $notice_uri) { + $this->log("found it $notice_uri"); + return true; + } + //$this->log("nope... " . $entry->id); + } + return false; + } + + /** + * Check that this account is subscribed to the given profile. + * @param string $profile_uri URI for the profile to check for + */ + function assertHasSubscription($profile_uri) + { + throw new Exception('tbi'); + } + + /** + * Check that this account is subscribed to by the given profile. + * @param string $profile_uri URI for the profile to check for + */ + function assertHasSubscriber($profile_uri) + { + throw new Exception('tbi'); + } + +} + +$args = array_slice($_SERVER['argv'], 1); +if (count($args) < 2) { + print << + url1: base URL of a StatusNet instance + url2: base URL of another StatusNet instance + +This will register user accounts on the two given StatusNet instances +and run some tests to confirm that OStatus subscription and posting +between the two sites works correctly. + +END_HELP; +exit(1); +} + +$a = $args[0]; +$b = $args[1]; + +$tester = new OStatusTester($a, $b); +$tester->run(); + -- cgit v1.2.3-54-g00ecf From b8e97ac7098783f0380c7f8f61c20a100e814dc0 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Mar 2010 18:53:09 -0700 Subject: Some initial media parsing - Activity now returns a list of activity objects - Processing of photo objects --- lib/activity.php | 24 +-- lib/activityobject.php | 20 +++ plugins/OStatus/actions/groupsalmon.php | 3 +- plugins/OStatus/actions/usersalmon.php | 5 +- plugins/OStatus/classes/Ostatus_profile.php | 2 +- scripts/importtwitteratom.php | 2 +- tests/ActivityParseTests.php | 233 ++++++++++++++++++++++++++-- tests/UserFeedParseTest.php | 8 +- 8 files changed, 266 insertions(+), 31 deletions(-) diff --git a/lib/activity.php b/lib/activity.php index bd1d5d56c..f9192c6b8 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -53,6 +53,7 @@ class Activity { const SPEC = 'http://activitystrea.ms/spec/1.0/'; const SCHEMA = 'http://activitystrea.ms/schema/1.0/'; + const MEDIA = 'http://purl.org/syndication/atommedia'; const VERB = 'verb'; const OBJECT = 'object'; @@ -85,7 +86,7 @@ class Activity public $actor; // an ActivityObject public $verb; // a string (the URL) - public $object; // an ActivityObject + public $objects = array(); // an array of ActivityObjects public $target; // an ActivityObject public $context; // an ActivityObject public $time; // Time of the activity @@ -161,12 +162,15 @@ class Activity // XXX: do other implied stuff here } - $objectEl = $this->_child($entry, self::OBJECT); + $objectEls = $entry->getElementsByTagNameNS(self::SPEC, self::OBJECT); - if (!empty($objectEl)) { - $this->object = new ActivityObject($objectEl); + if ($objectEls->length > 0) { + for ($i = 0; $i < $objectEls->length; $i++) { + $objectEl = $objectEls->item($i); + $this->objects[] = new ActivityObject($objectEl); + } } else { - $this->object = new ActivityObject($entry); + $this->objects[] = new ActivityObject($entry); } $actorEl = $this->_child($entry, self::ACTOR); @@ -280,8 +284,8 @@ class Activity } } - $this->object = new ActivityObject($item); - $this->context = new ActivityContext($item); + $this->objects[] = new ActivityObject($item); + $this->context = new ActivityContext($item); } /** @@ -339,8 +343,10 @@ class Activity $xs->element('activity:verb', null, $this->verb); - if ($this->object) { - $xs->raw($this->object->asString()); + if (!empty($this->objects)) { + foreach($this->objects as $object) { + $xs->raw($object->asString()); + } } if ($this->target) { diff --git a/lib/activityobject.php b/lib/activityobject.php index 0a358ccab..34d1b9170 100644 --- a/lib/activityobject.php +++ b/lib/activityobject.php @@ -100,6 +100,13 @@ class ActivityObject public $poco; public $displayName; + // @todo move this stuff to it's own PHOTO activity object + const MEDIA_DESCRIPTION = 'description'; + + public $thumbnail; + public $largerImage; + public $description; + /** * Constructor * @@ -150,6 +157,19 @@ class ActivityObject $this->poco = new PoCo($element); } + + if ($this->type == self::PHOTO) { + + $this->thumbnail = ActivityUtils::getLink($element, 'preview'); + $this->largerImage = ActivityUtils::getLink($element, 'enclosure'); + + $this->description = ActivityUtils::childContent( + $element, + ActivityObject::MEDIA_DESCRIPTION, + Activity::MEDIA + ); + + } } private function _fromAuthor($element) diff --git a/plugins/OStatus/actions/groupsalmon.php b/plugins/OStatus/actions/groupsalmon.php index 29377b5fa..d60725a71 100644 --- a/plugins/OStatus/actions/groupsalmon.php +++ b/plugins/OStatus/actions/groupsalmon.php @@ -60,7 +60,8 @@ class GroupsalmonAction extends SalmonAction function handlePost() { - switch ($this->act->object->type) { + // @fixme process all objects? + switch ($this->act->objects[0]->type) { case ActivityObject::ARTICLE: case ActivityObject::BLOGENTRY: case ActivityObject::NOTE: diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 15e8c1869..ecdcfa193 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -55,9 +55,10 @@ class UsersalmonAction extends SalmonAction */ function handlePost() { - common_log(LOG_INFO, "Received post of '{$this->act->object->id}' from '{$this->act->actor->id}'"); + common_log(LOG_INFO, "Received post of '{$this->act->objects[0]->id}' from '{$this->act->actor->id}'"); - switch ($this->act->object->type) { + // @fixme: process all activity objects? + switch ($this->act->objects[0]->type) { case ActivityObject::ARTICLE: case ActivityObject::BLOGENTRY: case ActivityObject::NOTE: diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 0eb5b8b82..df937643b 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -494,7 +494,7 @@ class Ostatus_profile extends Memcached_DataObject // It's not always an ActivityObject::NOTE, but... let's just say it is. - $note = $activity->object; + $note = $activity->objects[0]; // The id URI will be used as a unique identifier for for the notice, // protecting against duplicate saves. It isn't required to be a URL; diff --git a/scripts/importtwitteratom.php b/scripts/importtwitteratom.php index 7316f2108..c12e3b91a 100644 --- a/scripts/importtwitteratom.php +++ b/scripts/importtwitteratom.php @@ -102,7 +102,7 @@ function importActivityStream($user, $doc) for ($i = $entries->length - 1; $i >= 0; $i--) { $entry = $entries->item($i); $activity = new Activity($entry, $feed); - $object = $activity->object; + $object = $activity->objects[0]; if (!have_option('q', 'quiet')) { print $activity->content . "\n"; } diff --git a/tests/ActivityParseTests.php b/tests/ActivityParseTests.php index 02d2ed734..fec8829eb 100644 --- a/tests/ActivityParseTests.php +++ b/tests/ActivityParseTests.php @@ -25,11 +25,11 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertEquals($act->time, 1243860840); $this->assertEquals($act->verb, ActivityVerb::POST); - $this->assertFalse(empty($act->object)); - $this->assertEquals($act->object->title, 'Punctuation Changeset'); - $this->assertEquals($act->object->type, 'http://versioncentral.example.org/activity/changeset'); - $this->assertEquals($act->object->summary, 'Fixing punctuation because it makes it more readable.'); - $this->assertEquals($act->object->id, 'tag:versioncentral.example.org,2009:/change/1643245'); + $this->assertFalse(empty($act->objects[0])); + $this->assertEquals($act->objects[0]->title, 'Punctuation Changeset'); + $this->assertEquals($act->objects[0]->type, 'http://versioncentral.example.org/activity/changeset'); + $this->assertEquals($act->objects[0]->summary, 'Fixing punctuation because it makes it more readable.'); + $this->assertEquals($act->objects[0]->id, 'tag:versioncentral.example.org,2009:/change/1643245'); } public function testExample3() @@ -56,12 +56,12 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertEquals($act->actor->title, 'John Doe'); $this->assertEquals($act->actor->id, 'mailto:johndoe@example.com'); - $this->assertFalse(empty($act->object)); - $this->assertEquals($act->object->type, ActivityObject::NOTE); - $this->assertEquals($act->object->id, 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a'); - $this->assertEquals($act->object->title, 'Atom-Powered Robots Run Amok'); - $this->assertEquals($act->object->summary, 'Some text.'); - $this->assertEquals($act->object->link, 'http://example.org/2003/12/13/atom03.html'); + $this->assertFalse(empty($act->objects[0])); + $this->assertEquals($act->objects[0]->type, ActivityObject::NOTE); + $this->assertEquals($act->objects[0]->id, 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a'); + $this->assertEquals($act->objects[0]->title, 'Atom-Powered Robots Run Amok'); + $this->assertEquals($act->objects[0]->summary, 'Some text.'); + $this->assertEquals($act->objects[0]->link, 'http://example.org/2003/12/13/atom03.html'); $this->assertFalse(empty($act->context)); @@ -90,8 +90,8 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertEquals('http://example.net/conversation/11', $act->context->conversation); $this->assertEquals(array('http://example.net/user/1'), $act->context->attention); - $this->assertFalse(empty($act->object)); - $this->assertEquals($act->object->content, + $this->assertFalse(empty($act->objects[0])); + $this->assertEquals($act->objects[0]->content, '@evan now is the time for all good men to come to the aid of their country. #'); $this->assertFalse(empty($act->actor)); @@ -215,6 +215,96 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertNull($actor->poco->address); $this->assertEquals(0, count($actor->poco->urls)); } + + // Media test - cliqset + public function testExample8() + { + global $_example8; + $dom = DOMDocument::loadXML($_example8); + + $feed = $dom->documentElement; + + $entries = $feed->getElementsByTagName('entry'); + + $entry = $entries->item(0); + + $act = new Activity($entry, $feed); + + $this->assertFalse(empty($act)); + $this->assertEquals($act->time, 1269221753); + $this->assertEquals($act->verb, ActivityVerb::POST); + $this->assertEquals($act->summary, 'zcopley posted 5 photos on Flickr'); + + $this->assertFalse(empty($act->objects)); + $this->assertEquals(sizeof($act->objects), 5); + + $this->assertEquals($act->objects[0]->type, ActivityObject::PHOTO); + $this->assertEquals($act->objects[0]->title, 'IMG_1368'); + $this->assertNull($act->objects[0]->description); + $this->assertEquals( + $act->objects[0]->thumbnail, + 'http://media.cliqset.com/6f6fbee9d7dfbffc73b6ef626275eb5f_thumb.jpg' + ); + $this->assertEquals( + $act->objects[0]->link, + 'http://www.flickr.com/photos/zcopley/4452933806/' + ); + + $this->assertEquals($act->objects[1]->type, ActivityObject::PHOTO); + $this->assertEquals($act->objects[1]->title, 'IMG_1365'); + $this->assertNull($act->objects[1]->description); + $this->assertEquals( + $act->objects[1]->thumbnail, + 'http://media.cliqset.com/b8f3932cd0bba1b27f7c8b3ef986915e_thumb.jpg' + ); + $this->assertEquals( + $act->objects[1]->link, + 'http://www.flickr.com/photos/zcopley/4442630390/' + ); + + $this->assertEquals($act->objects[2]->type, ActivityObject::PHOTO); + $this->assertEquals($act->objects[2]->title, 'Classic'); + $this->assertEquals( + $act->objects[2]->description, + '-Powered by pikchur.com/n0u' + ); + $this->assertEquals( + $act->objects[2]->thumbnail, + 'http://media.cliqset.com/fc54c15f850b7a9a8efa644087a48c91_thumb.jpg' + ); + $this->assertEquals( + $act->objects[2]->link, + 'http://www.flickr.com/photos/zcopley/4430754103/' + ); + + $this->assertEquals($act->objects[3]->type, ActivityObject::PHOTO); + $this->assertEquals($act->objects[3]->title, 'IMG_1363'); + $this->assertNull($act->objects[3]->description); + + $this->assertEquals( + $act->objects[3]->thumbnail, + 'http://media.cliqset.com/4b1d307c9217e2114391a8b229d612cb_thumb.jpg' + ); + $this->assertEquals( + $act->objects[3]->link, + 'http://www.flickr.com/photos/zcopley/4416969717/' + ); + + $this->assertEquals($act->objects[4]->type, ActivityObject::PHOTO); + $this->assertEquals($act->objects[4]->title, 'IMG_1361'); + $this->assertNull($act->objects[4]->description); + + $this->assertEquals( + $act->objects[4]->thumbnail, + 'http://media.cliqset.com/23d9b4b96b286e0347d36052f22f6e60_thumb.jpg' + ); + $this->assertEquals( + $act->objects[4]->link, + 'http://www.flickr.com/photos/zcopley/4417734232/' + ); + + } + } $_example1 = << EXAMPLE7; + +$_example8 = << + + + Activity Stream for: zcopley + http://cliqset.com/feed/atom?uid=zcopley + + 0 + http://activitystrea.ms/schema/1.0/post + 2010-03-22T01:35:53.000Z + + flickr + http://flickr.com + http://cliqset-services.s3.amazonaws.com/flickr.png + + + http://activitystrea.ms/schema/1.0/photo + IMG_1368 + + + + + http://activitystrea.ms/schema/1.0/photo + IMG_1365 + + + + + http://activitystrea.ms/schema/1.0/photo + Classic + + + -Powered by pikchur.com/n0u + + + http://activitystrea.ms/schema/1.0/photo + IMG_1363 + + + + + http://activitystrea.ms/schema/1.0/photo + IMG_1361 + + + + zcopley posted some photos on Flickr + zcopley posted 5 photos on Flickr + + 2010-03-22T20:46:42.778Z + tag:cliqset.com,2010-03-22:/user/zcopley/SVgAZubGhtAnSAee + + + zcopley + http://cliqset.com/user/zcopley + + + http://activitystrea.ms/schema/1.0/person + zcopley + + Zach + Copley + + + + + + + +EXAMPLE8; + +$_example9 = << + + + + Google Buzz + 2010-03-22T01:55:53.596Z + tag:google.com,2009:buzz-feed/public/posted/117848251937215158042 + Google - Google Buzz + + Buzz by Zach Copley from Flickr + IMG_1366 + 2010-03-18T04:29:23.000Z + 2010-03-18T05:14:03.325Z + tag:google.com,2009:buzz/z12zwdhxowq2d13q204cjr04kzu0cns5gh0 + + + Zach Copley + http://www.google.com/profiles/zcopley + + <div>IMG_1366</div> + + + IMG_1366 + + + + + IMG_1365 + + + http://activitystrea.ms/schema/1.0/post + + http://activitystrea.ms/schema/1.0/photo + tag:google.com,2009:buzz/z12zwdhxowq2d13q204cjr04kzu0cns5gh0 + Buzz by Zach Copley from Flickr + <div>IMG_1366</div> + + + + + 0 + + +EXAMPLE9; diff --git a/tests/UserFeedParseTest.php b/tests/UserFeedParseTest.php index b3f9a6417..208e71be6 100644 --- a/tests/UserFeedParseTest.php +++ b/tests/UserFeedParseTest.php @@ -66,11 +66,11 @@ class UserFeedParseTests extends PHPUnit_Framework_TestCase // test the post //var_export($act1); - $this->assertEquals($act1->object->type, 'http://activitystrea.ms/schema/1.0/note'); - $this->assertEquals($act1->object->title, 'And now for something completely insane...'); + $this->assertEquals($act1->objects[0]->type, 'http://activitystrea.ms/schema/1.0/note'); + $this->assertEquals($act1->objects[0]->title, 'And now for something completely insane...'); - $this->assertEquals($act1->object->content, 'And now for something completely insane...'); - $this->assertEquals($act1->object->id, 'http://localhost/statusnet/notice/3'); + $this->assertEquals($act1->objects[0]->content, 'And now for something completely insane...'); + $this->assertEquals($act1->objects[0]->id, 'http://localhost/statusnet/notice/3'); } -- cgit v1.2.3-54-g00ecf From 5b0b6097e0e47c84c2e47c8a14421a58be1fac19 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Mar 2010 21:48:21 -0700 Subject: Fix reference. Look at the first ActivityObject in the list. --- plugins/OStatus/classes/Ostatus_profile.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index df937643b..c7e3b0509 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -442,7 +442,8 @@ class Ostatus_profile extends Memcached_DataObject { $activity = new Activity($entry, $feed); - switch ($activity->object->type) { + // @todo process all activity objects + switch ($activity->objects[0]->type) { case ActivityObject::ARTICLE: case ActivityObject::BLOGENTRY: case ActivityObject::NOTE: -- cgit v1.2.3-54-g00ecf From fcdbf421ab2bbbe4d1b601a8c80d4612c91f62fe Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Mar 2010 11:36:02 -0400 Subject: reformat OpenIDPlugin for PHPCS --- plugins/OpenID/OpenIDPlugin.php | 228 +++++++++++++++++++++++++++++++--------- 1 file changed, 179 insertions(+), 49 deletions(-) diff --git a/plugins/OpenID/OpenIDPlugin.php b/plugins/OpenID/OpenIDPlugin.php index 6b35ec3e1..1724b5f7b 100644 --- a/plugins/OpenID/OpenIDPlugin.php +++ b/plugins/OpenID/OpenIDPlugin.php @@ -59,6 +59,8 @@ class OpenIDPlugin extends Plugin * * Hook for RouterInitialized event. * + * @param Net_URL_Mapper $m URL mapper + * * @return boolean hook return */ @@ -67,54 +69,87 @@ class OpenIDPlugin extends Plugin $m->connect('main/openid', array('action' => 'openidlogin')); $m->connect('main/openidtrust', array('action' => 'openidtrust')); $m->connect('settings/openid', array('action' => 'openidsettings')); - $m->connect('index.php?action=finishopenidlogin', array('action' => 'finishopenidlogin')); - $m->connect('index.php?action=finishaddopenid', array('action' => 'finishaddopenid')); + $m->connect('index.php?action=finishopenidlogin', + array('action' => 'finishopenidlogin')); + $m->connect('index.php?action=finishaddopenid', + array('action' => 'finishaddopenid')); $m->connect('main/openidserver', array('action' => 'openidserver')); return true; } + /** + * Public XRDS output hook + * + * Puts the bits of code needed by some OpenID providers to show + * we're good citizens. + * + * @param Action $action Action being executed + * @param XMLOutputter &$xrdsOutputter Output channel + * + * @return boolean hook return + */ + function onEndPublicXRDS($action, &$xrdsOutputter) { $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', - 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', - 'version' => '2.0')); + 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', + 'version' => '2.0')); $xrdsOutputter->element('Type', null, 'xri://$xrds*simple'); //consumer foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) { $xrdsOutputter->showXrdsService(Auth_OpenID_RP_RETURN_TO_URL_TYPE, - common_local_url($finish)); + common_local_url($finish)); } //provider $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/server', - common_local_url('openidserver'), - null, - null, - 'http://specs.openid.net/auth/2.0/identifier_select'); + common_local_url('openidserver'), + null, + null, + 'http://specs.openid.net/auth/2.0/identifier_select'); $xrdsOutputter->elementEnd('XRD'); } + /** + * User XRDS output hook + * + * Puts the bits of code needed to discover OpenID endpoints. + * + * @param Action $action Action being executed + * @param XMLOutputter &$xrdsOutputter Output channel + * + * @return boolean hook return + */ + function onEndUserXRDS($action, &$xrdsOutputter) { $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', - 'xml:id' => 'openid', - 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', - 'version' => '2.0')); + 'xml:id' => 'openid', + 'xmlns:simple' => 'http://xrds-simple.net/core/1.0', + 'version' => '2.0')); $xrdsOutputter->element('Type', null, 'xri://$xrds*simple'); //consumer $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/return_to', - common_local_url('finishopenidlogin')); + common_local_url('finishopenidlogin')); //provider $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/signon', - common_local_url('openidserver'), - null, - null, - common_profile_url($action->user->nickname)); + common_local_url('openidserver'), + null, + null, + common_profile_url($action->user->nickname)); $xrdsOutputter->elementEnd('XRD'); } + /** + * Menu item for login + * + * @param Action &$action Action being executed + * + * @return boolean hook return + */ + function onEndLoginGroupNav(&$action) { $action_name = $action->trimmed('action'); @@ -127,6 +162,14 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Menu item for OpenID admin + * + * @param Action &$action Action being executed + * + * @return boolean hook return + */ + function onEndAccountSettingsNav(&$action) { $action_name = $action->trimmed('action'); @@ -139,68 +182,102 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Autoloader + * + * Loads our classes if they're requested. + * + * @param string $cls Class requested + * + * @return boolean hook return + */ + function onAutoload($cls) { switch ($cls) { - case 'OpenidloginAction': - case 'FinishopenidloginAction': - case 'FinishaddopenidAction': - case 'XrdsAction': - case 'PublicxrdsAction': - case 'OpenidsettingsAction': - case 'OpenidserverAction': - case 'OpenidtrustAction': - require_once(INSTALLDIR.'/plugins/OpenID/' . strtolower(mb_substr($cls, 0, -6)) . '.php'); + case 'OpenidloginAction': + case 'FinishopenidloginAction': + case 'FinishaddopenidAction': + case 'XrdsAction': + case 'PublicxrdsAction': + case 'OpenidsettingsAction': + case 'OpenidserverAction': + case 'OpenidtrustAction': + require_once INSTALLDIR.'/plugins/OpenID/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; - case 'User_openid': - require_once(INSTALLDIR.'/plugins/OpenID/User_openid.php'); + case 'User_openid': + require_once INSTALLDIR.'/plugins/OpenID/User_openid.php'; return false; - case 'User_openid_trustroot': - require_once(INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php'); + case 'User_openid_trustroot': + require_once INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php'; return false; - default: + default: return true; } } + /** + * Sensitive actions + * + * These actions should use https when SSL support is 'sometimes' + * + * @param Action $action Action to form an URL for + * @param boolean &$ssl Whether to mark it for SSL + * + * @return boolean hook return + */ + function onSensitiveAction($action, &$ssl) { switch ($action) { - case 'finishopenidlogin': - case 'finishaddopenid': + case 'finishopenidlogin': + case 'finishaddopenid': $ssl = true; return false; - default: + default: return true; } } + /** + * Login actions + * + * These actions should be visible even when the site is marked private + * + * @param Action $action Action to show + * @param boolean &$login Whether it's a login action + * + * @return boolean hook return + */ + function onLoginAction($action, &$login) { switch ($action) { - case 'openidlogin': - case 'finishopenidlogin': - case 'openidserver': + case 'openidlogin': + case 'finishopenidlogin': + case 'openidserver': $login = true; return false; - default: + default: return true; } } /** - * We include a element linking to the publicxrds page, for OpenID + * We include a element linking to the userxrds page, for OpenID * client-side authentication. * + * @param Action $action Action being shown + * * @return void */ function onEndShowHeadElements($action) { - if($action instanceof ShowstreamAction){ + if ($action instanceof ShowstreamAction) { $action->element('link', array('rel' => 'openid2.provider', 'href' => common_local_url('openidserver'))); $action->element('link', array('rel' => 'openid2.local_id', @@ -216,6 +293,9 @@ class OpenIDPlugin extends Plugin /** * Redirect to OpenID login if they have an OpenID * + * @param Action $action Action being executed + * @param User $user User doing the action + * * @return boolean whether to continue */ @@ -228,13 +308,21 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Show some extra instructions for using OpenID + * + * @param Action $action Action being executed + * + * @return boolean hook value + */ + function onEndShowPageNotice($action) { $name = $action->trimmed('action'); switch ($name) { - case 'register': + case 'register': if (common_logged_in()) { $instr = '(Have an [OpenID](http://openid.net/)? ' . '[Add an OpenID to your account](%%action.openidsettings%%)!'; @@ -244,12 +332,12 @@ class OpenIDPlugin extends Plugin '(%%action.openidlogin%%)!)'; } break; - case 'login': + case 'login': $instr = '(Have an [OpenID](http://openid.net/)? ' . 'Try our [OpenID login]'. '(%%action.openidlogin%%)!)'; break; - default: + default: return true; } @@ -258,13 +346,21 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Load our document if requested + * + * @param string &$title Title to fetch + * @param string &$output HTML to output + * + * @return boolean hook value + */ + function onStartLoadDoc(&$title, &$output) { - if ($title == 'openid') - { + if ($title == 'openid') { $filename = INSTALLDIR.'/plugins/OpenID/doc-src/openid'; - $c = file_get_contents($filename); + $c = file_get_contents($filename); $output = common_markup_to_html($c); return false; // success! } @@ -272,10 +368,18 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Add our document to the global menu + * + * @param string $title Title being fetched + * @param string &$output HTML being output + * + * @return boolean hook value + */ + function onEndLoadDoc($title, &$output) { - if ($title == 'help') - { + if ($title == 'help') { $menuitem = '* [OpenID](%%doc.openid%%) - what OpenID is and how to use it with this service'; $output .= common_markup_to_html($menuitem); @@ -284,7 +388,16 @@ class OpenIDPlugin extends Plugin return true; } - function onCheckSchema() { + /** + * Data definitions + * + * Assure that our data objects are available in the DB + * + * @return boolean hook value + */ + + function onCheckSchema() + { $schema = Schema::get(); $schema->ensureTable('user_openid', array(new ColumnDef('canonical', 'varchar', @@ -307,6 +420,15 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Add our tables to be deleted when a user is deleted + * + * @param User $user User being deleted + * @param array &$tables Array of table names + * + * @return boolean hook value + */ + function onUserDeleteRelated($user, &$tables) { $tables[] = 'User_openid'; @@ -314,6 +436,14 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Add our version information to output + * + * @param array &$versions Array of version-data arrays + * + * @return boolean hook value + */ + function onPluginVersion(&$versions) { $versions[] = array('name' => 'OpenID', -- cgit v1.2.3-54-g00ecf From 2d79455a1fb7627a23a6ca77fbab060193f6c43a Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 09:50:01 -0700 Subject: Don't add PHPSESSID parameter onto notice and conversation URIs if we save a notice during a session override. This was being triggered by welcomebot messages created at account creation time, then propagated through replies. --- classes/Conversation.php | 3 ++- lib/util.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/classes/Conversation.php b/classes/Conversation.php index ea8bd87b5..f540004ef 100755 --- a/classes/Conversation.php +++ b/classes/Conversation.php @@ -63,7 +63,8 @@ class Conversation extends Memcached_DataObject } $orig = clone($conv); - $orig->uri = common_local_url('conversation', array('id' => $id)); + $orig->uri = common_local_url('conversation', array('id' => $id), + null, null, false); $result = $orig->update($conv); if (empty($result)) { diff --git a/lib/util.php b/lib/util.php index a30d69100..795997868 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1529,7 +1529,8 @@ function common_user_uri(&$user) function common_notice_uri(&$notice) { return common_local_url('shownotice', - array('notice' => $notice->id)); + array('notice' => $notice->id), + null, null, false); } // 36 alphanums - lookalikes (0, O, 1, I) = 32 chars = 5 bits -- cgit v1.2.3-54-g00ecf From 80b16c8499d0cfdb4deb442ba18345befed4e29d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 09:50:01 -0700 Subject: Don't add PHPSESSID parameter onto notice and conversation URIs if we save a notice during a session override. This was being triggered by welcomebot messages created at account creation time, then propagated through replies. --- classes/Conversation.php | 3 ++- lib/util.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/classes/Conversation.php b/classes/Conversation.php index ea8bd87b5..f540004ef 100755 --- a/classes/Conversation.php +++ b/classes/Conversation.php @@ -63,7 +63,8 @@ class Conversation extends Memcached_DataObject } $orig = clone($conv); - $orig->uri = common_local_url('conversation', array('id' => $id)); + $orig->uri = common_local_url('conversation', array('id' => $id), + null, null, false); $result = $orig->update($conv); if (empty($result)) { diff --git a/lib/util.php b/lib/util.php index 44ccc0def..3d4ed087f 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1521,7 +1521,8 @@ function common_user_uri(&$user) function common_notice_uri(&$notice) { return common_local_url('shownotice', - array('notice' => $notice->id)); + array('notice' => $notice->id), + null, null, false); } // 36 alphanums - lookalikes (0, O, 1, I) = 32 chars = 5 bits -- cgit v1.2.3-54-g00ecf From 533a3bf6a3180237cfffb8baf29ea3a3f7ec34f8 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 11:06:37 -0700 Subject: Consistently send Profiles into Fave::addNew() --- actions/apifavoritecreate.php | 2 +- classes/Fave.php | 10 +++++++++- lib/command.php | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/actions/apifavoritecreate.php b/actions/apifavoritecreate.php index 3618f9401..00b6349b0 100644 --- a/actions/apifavoritecreate.php +++ b/actions/apifavoritecreate.php @@ -123,7 +123,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction return; } - $fave = Fave::addNew($this->user, $this->notice); + $fave = Fave::addNew($this->user->getProfile(), $this->notice); if (empty($fave)) { $this->clientError( diff --git a/classes/Fave.php b/classes/Fave.php index a04f15e9c..7ca9ade7f 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -21,7 +21,15 @@ class Fave extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - static function addNew($profile, $notice) { + /** + * Save a favorite record. + * @fixme post-author notification should be moved here + * + * @param Profile $profile the local or remote user who likes + * @param Notice $notice the notice that is liked + * @return mixed false on failure, or Fave record on success + */ + static function addNew(Profile $profile, Notice $notice) { $fave = null; diff --git a/lib/command.php b/lib/command.php index f7421269d..216f9e649 100644 --- a/lib/command.php +++ b/lib/command.php @@ -273,7 +273,7 @@ class FavCommand extends Command function handle($channel) { $notice = $this->getNotice($this->other); - $fave = Fave::addNew($this->user, $notice); + $fave = Fave::addNew($this->user->getProfile(), $notice); if (!$fave) { $channel->error($this->user, _('Could not create favorite.')); -- cgit v1.2.3-54-g00ecf From 44caa3a93f452777c795006edb52ef4c5c2c4997 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 11:06:37 -0700 Subject: Consistently send Profiles into Fave::addNew() --- actions/apifavoritecreate.php | 2 +- classes/Fave.php | 10 +++++++++- lib/command.php | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/actions/apifavoritecreate.php b/actions/apifavoritecreate.php index 3618f9401..00b6349b0 100644 --- a/actions/apifavoritecreate.php +++ b/actions/apifavoritecreate.php @@ -123,7 +123,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction return; } - $fave = Fave::addNew($this->user, $this->notice); + $fave = Fave::addNew($this->user->getProfile(), $this->notice); if (empty($fave)) { $this->clientError( diff --git a/classes/Fave.php b/classes/Fave.php index a04f15e9c..7ca9ade7f 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -21,7 +21,15 @@ class Fave extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - static function addNew($profile, $notice) { + /** + * Save a favorite record. + * @fixme post-author notification should be moved here + * + * @param Profile $profile the local or remote user who likes + * @param Notice $notice the notice that is liked + * @return mixed false on failure, or Fave record on success + */ + static function addNew(Profile $profile, Notice $notice) { $fave = null; diff --git a/lib/command.php b/lib/command.php index 9d550550f..8080fb8bc 100644 --- a/lib/command.php +++ b/lib/command.php @@ -273,7 +273,7 @@ class FavCommand extends Command function handle($channel) { $notice = $this->getNotice($this->other); - $fave = Fave::addNew($this->user, $notice); + $fave = Fave::addNew($this->user->getProfile(), $notice); if (!$fave) { $channel->error($this->user, _('Could not create favorite.')); -- cgit v1.2.3-54-g00ecf From 16fa03212bc6cabe2f47e93d06c0def10d46b353 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 11:25:36 -0700 Subject: Ticket 2188: add a daily average post count to profile statistics sidebar. When we have more detailed history stats, this'd be a good place to link to details/graphs. --- lib/profileaction.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/profileaction.php b/lib/profileaction.php index 029c21845..072c024c7 100644 --- a/lib/profileaction.php +++ b/lib/profileaction.php @@ -169,6 +169,12 @@ class ProfileAction extends OwnerDesignAction $subbed_count = $this->profile->subscriberCount(); $notice_count = $this->profile->noticeCount(); $group_count = $this->user->getGroups()->N; + $age_days = (time() - strtotime($this->profile->created)) / 86400; + if ($age_days < 1) { + // Rather than extrapolating out to a bajillion... + $age_days = 1; + } + $daily_count = round($notice_count / $age_days); $this->elementStart('div', array('id' => 'entity_statistics', 'class' => 'section')); @@ -219,6 +225,12 @@ class ProfileAction extends OwnerDesignAction $this->element('dd', null, $notice_count); $this->elementEnd('dl'); + $this->elementStart('dl', 'entity_daily_notices'); + // TRANS: Average count of posts made per day since account registration + $this->element('dt', null, _('Daily average')); + $this->element('dd', null, $daily_count); + $this->elementEnd('dl'); + $this->elementEnd('div'); } -- cgit v1.2.3-54-g00ecf From 7dc24b4ca7dffda85338d35da3618ec50ce0dbf7 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 13:10:23 -0700 Subject: FOAF was missing OStatus remote subscriptions, now fixed. --- actions/foaf.php | 68 +++++++++++++++++++------------------------------------- 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/actions/foaf.php b/actions/foaf.php index fc2ec9b12..fc56e19b4 100644 --- a/actions/foaf.php +++ b/actions/foaf.php @@ -162,40 +162,29 @@ class FoafAction extends Action if ($sub->find()) { while ($sub->fetch()) { - if ($sub->token) { - $other = Remote_profile::staticGet('id', $sub->subscriber); - $profile = Profile::staticGet('id', $sub->subscriber); - } else { - $other = User::staticGet('id', $sub->subscriber); - $profile = Profile::staticGet('id', $sub->subscriber); - } - if (!$other) { + $profile = Profile::staticGet('id', $sub->subscriber); + if (empty($profile)) { common_debug('Got a bad subscription: '.print_r($sub,true)); continue; } - if (array_key_exists($other->uri, $person)) { - $person[$other->uri][0] = BOTH; + $user = $profile->getUser(); + $other_uri = $profile->getUri(); + if (array_key_exists($other_uri, $person)) { + $person[$other_uri][0] = BOTH; } else { - $person[$other->uri] = array(LISTENER, - $other->id, - $profile->nickname, - (empty($sub->token)) ? 'User' : 'Remote_profile'); + $person[$other_uri] = array(LISTENER, + $profile->id, + $profile->nickname, + $user ? 'local' : 'remote'); } - $other->free(); - $other = null; - unset($other); - $profile->free(); - $profile = null; unset($profile); } } - $sub->free(); - $sub = null; unset($sub); foreach ($person as $uri => $p) { - list($type, $id, $nickname, $cls) = $p; + list($type, $id, $nickname, $local) = $p; if ($type == BOTH) { $this->element('knows', array('rdf:resource' => $uri)); } @@ -206,8 +195,8 @@ class FoafAction extends Action foreach ($person as $uri => $p) { $foaf_url = null; - list($type, $id, $nickname, $cls) = $p; - if ($cls == 'User') { + list($type, $id, $nickname, $local) = $p; + if ($local == 'local') { $foaf_url = common_local_url('foaf', array('nickname' => $nickname)); } $profile = Profile::staticGet($id); @@ -216,7 +205,7 @@ class FoafAction extends Action $this->element('knows', array('rdf:resource' => $this->user->uri)); } $this->showMicrobloggingAccount($profile, - ($cls == 'User') ? common_root_url() : null, + ($local == 'local') ? common_root_url() : null, $uri, true); if ($foaf_url) { @@ -275,33 +264,22 @@ class FoafAction extends Action if ($sub->find()) { while ($sub->fetch()) { - if (!empty($sub->token)) { - $other = Remote_profile::staticGet('id', $sub->subscribed); - $profile = Profile::staticGet('id', $sub->subscribed); - } else { - $other = User::staticGet('id', $sub->subscribed); - $profile = Profile::staticGet('id', $sub->subscribed); - } - if (empty($other)) { + $profile = Profile::staticGet('id', $sub->subscribed); + if (empty($profile)) { common_debug('Got a bad subscription: '.print_r($sub,true)); continue; } - $this->element('sioc:follows', array('rdf:resource' => $other->uri.'#acct')); - $person[$other->uri] = array(LISTENEE, - $other->id, - $profile->nickname, - (empty($sub->token)) ? 'User' : 'Remote_profile'); - $other->free(); - $other = null; - unset($other); - $profile->free(); - $profile = null; + $user = $profile->getUser(); + $other_uri = $profile->getUri(); + $this->element('sioc:follows', array('rdf:resource' => $other_uri.'#acct')); + $person[$other_uri] = array(LISTENEE, + $profile->id, + $profile->nickname, + $user ? 'local' : 'remote'); unset($profile); } } - $sub->free(); - $sub = null; unset($sub); } -- cgit v1.2.3-54-g00ecf From 80ed39132890a78c9bade22c43b25781fe7c12c8 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Tue, 23 Mar 2010 21:15:20 +0100 Subject: Localisation updates for !StatusNet from !translatewiki.net !sntrans Signed-off-by: Siebrand Mazeland --- locale/ar/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/arz/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/bg/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/br/LC_MESSAGES/statusnet.po | 147 ++++++++++++---------- locale/ca/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/cs/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/de/LC_MESSAGES/statusnet.po | 113 +++++++++-------- locale/el/LC_MESSAGES/statusnet.po | 109 +++++++++------- locale/en_GB/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/es/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/fa/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/fi/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/fr/LC_MESSAGES/statusnet.po | 113 +++++++++-------- locale/ga/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/he/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/hsb/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/ia/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/is/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/it/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/ja/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/ko/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/mk/LC_MESSAGES/statusnet.po | 113 +++++++++-------- locale/nb/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/nl/LC_MESSAGES/statusnet.po | 113 +++++++++-------- locale/nn/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/pl/LC_MESSAGES/statusnet.po | 113 +++++++++-------- locale/pt/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/pt_BR/LC_MESSAGES/statusnet.po | 229 ++++++++++++++++------------------ locale/ru/LC_MESSAGES/statusnet.po | 113 +++++++++-------- locale/statusnet.po | 105 +++++++++------- locale/sv/LC_MESSAGES/statusnet.po | 113 +++++++++-------- locale/te/LC_MESSAGES/statusnet.po | 111 +++++++++------- locale/tr/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/uk/LC_MESSAGES/statusnet.po | 114 +++++++++-------- locale/vi/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/zh_CN/LC_MESSAGES/statusnet.po | 110 +++++++++------- locale/zh_TW/LC_MESSAGES/statusnet.po | 109 +++++++++------- 37 files changed, 2378 insertions(+), 1875 deletions(-) diff --git a/locale/ar/LC_MESSAGES/statusnet.po b/locale/ar/LC_MESSAGES/statusnet.po index 16ea19752..e4142e9b1 100644 --- a/locale/ar/LC_MESSAGES/statusnet.po +++ b/locale/ar/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:39:53+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:08+0000\n" "Language-Team: Arabic\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: ar\n" "X-Message-Group: out-statusnet\n" @@ -751,23 +751,28 @@ msgstr "ارفع" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "لا ملف شخصي مُحدّد." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "رُفع الأفتار." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "فشل تحديث الأفتار." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "حُذف الأفتار." @@ -902,7 +907,7 @@ msgid "Conversation" msgstr "محادثة" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "الإشعارات" @@ -1700,7 +1705,7 @@ msgstr "مسار %s الزمني" msgid "Updates from members of %1$s on %2$s!" msgstr "" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "مجموعات" @@ -3240,7 +3245,7 @@ msgid "Description" msgstr "الوصف" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "إحصاءات" @@ -3402,7 +3407,7 @@ msgid "Members" msgstr "الأعضاء" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(لا شيء)" @@ -3574,7 +3579,8 @@ msgid "Unknown language \"%s\"." msgstr "لغة غير معروفة \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "حد النص الأدنى هو 140 حرفًا." #: actions/siteadminpanel.php:171 @@ -3838,8 +3844,7 @@ msgstr "اذف إعدادت الموقع" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "تعذّر حفظ الاشتراك." @@ -4378,36 +4383,36 @@ msgstr "مشكلة أثناء حفظ الإشعار." msgid "RT @%1$s %2$s" msgstr "آر تي @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "مُشترك أصلا!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "لقد منعك المستخدم." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "غير مشترك!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "لم يمكن حذف اشتراك ذاتي." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "تعذّر حذف الاشتراك." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "تعذّر حذف الاشتراك." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "أهلا بكم في %1$s يا @%2$s!" @@ -4694,22 +4699,22 @@ msgstr "بعد" msgid "Before" msgstr "قبل" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5227,19 +5232,19 @@ msgstr "" "tracks - لم يطبق بعد.\n" "tracking - لم يطبق بعد.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "اذهب إلى المُثبّت." @@ -5413,40 +5418,40 @@ msgstr "وسوم في إشعارات المجموعة %s" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "هذا الملف كبير جدًا. إن أقصى حجم للملفات هو %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "نوع ملف غير معروف" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "ميجابايت" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "كيلوبايت" @@ -5911,7 +5916,7 @@ msgstr "وسوم في إشعارات %s" msgid "Unknown" msgstr "غير معروفة" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "الاشتراكات" @@ -5919,7 +5924,7 @@ msgstr "الاشتراكات" msgid "All subscriptions" msgstr "جميع الاشتراكات" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "المشتركون" @@ -5927,15 +5932,20 @@ msgstr "المشتركون" msgid "All subscribers" msgstr "جميع المشتركين" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "هوية المستخدم" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "عضو منذ" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "كل المجموعات" @@ -6106,6 +6116,11 @@ msgstr "ألغِ الاشتراك مع هذا المستخدم" msgid "Unsubscribe" msgstr "ألغِ الاشتراك" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "ليس للمستخدم ملف شخصي." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "عدّل الأفتار" diff --git a/locale/arz/LC_MESSAGES/statusnet.po b/locale/arz/LC_MESSAGES/statusnet.po index 1426c4d04..77e246f82 100644 --- a/locale/arz/LC_MESSAGES/statusnet.po +++ b/locale/arz/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:39:57+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:11+0000\n" "Language-Team: Egyptian Spoken Arabic\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: arz\n" "X-Message-Group: out-statusnet\n" @@ -757,23 +757,28 @@ msgstr "ارفع" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "لا ملف شخصى مُحدّد." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "رُفع الأفتار." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "فشل تحديث الأفتار." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "حُذف الأفتار." @@ -908,7 +913,7 @@ msgid "Conversation" msgstr "محادثة" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "الإشعارات" @@ -1712,7 +1717,7 @@ msgstr "مسار %s الزمني" msgid "Updates from members of %1$s on %2$s!" msgstr "" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "مجموعات" @@ -3250,7 +3255,7 @@ msgid "Description" msgstr "الوصف" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "إحصاءات" @@ -3412,7 +3417,7 @@ msgid "Members" msgstr "الأعضاء" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(لا شيء)" @@ -3572,7 +3577,8 @@ msgid "Unknown language \"%s\"." msgstr "لغه مش معروفه \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "حد النص الأدنى هو 140 حرفًا." #: actions/siteadminpanel.php:171 @@ -3841,8 +3847,7 @@ msgstr "اذف إعدادت الموقع" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "تعذّر حفظ الاشتراك." @@ -4382,36 +4387,36 @@ msgstr "مشكله أثناء حفظ الإشعار." msgid "RT @%1$s %2$s" msgstr "آر تى @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "مُشترك أصلا!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "لقد منعك المستخدم." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "غير مشترك!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "ما نفعش يمسح الاشتراك الشخصى." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "تعذّر حذف الاشتراك." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "تعذّر حذف الاشتراك." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "أهلا بكم فى %1$s يا @%2$s!" @@ -4714,22 +4719,22 @@ msgstr "بعد" msgid "Before" msgstr "قبل" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5215,19 +5220,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "اذهب إلى المُثبّت." @@ -5401,40 +5406,40 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "هذا الملف كبير جدًا. إن أقصى حجم للملفات هو %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "نوع ملف غير معروف" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "ميجابايت" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "كيلوبايت" @@ -5878,7 +5883,7 @@ msgstr "" msgid "Unknown" msgstr "مش معروف" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "الاشتراكات" @@ -5886,7 +5891,7 @@ msgstr "الاشتراكات" msgid "All subscriptions" msgstr "جميع الاشتراكات" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "المشتركون" @@ -5894,15 +5899,20 @@ msgstr "المشتركون" msgid "All subscribers" msgstr "جميع المشتركين" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "هويه المستخدم" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "عضو منذ" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "كل المجموعات" @@ -6073,6 +6083,11 @@ msgstr "ألغِ الاشتراك مع هذا المستخدم" msgid "Unsubscribe" msgstr "ألغِ الاشتراك" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "ليس للمستخدم ملف شخصى." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "عدّل الأفتار" diff --git a/locale/bg/LC_MESSAGES/statusnet.po b/locale/bg/LC_MESSAGES/statusnet.po index 83acdaab6..c1f83849a 100644 --- a/locale/bg/LC_MESSAGES/statusnet.po +++ b/locale/bg/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:00+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:15+0000\n" "Language-Team: Bulgarian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: bg\n" "X-Message-Group: out-statusnet\n" @@ -766,23 +766,28 @@ msgstr "Качване" msgid "Crop" msgstr "Изрязване" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Не е указан профил." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Изберете квадратна област от изображението за аватар" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Аватарът е обновен." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Неуспешно обновяване на аватара." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Аватарът е изтрит." @@ -919,7 +924,7 @@ msgid "Conversation" msgstr "Разговор" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Бележки" @@ -1762,7 +1767,7 @@ msgstr "Поток на %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Бележки от %1$s в %2$s." -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Групи" @@ -3399,7 +3404,7 @@ msgid "Description" msgstr "Описание" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Статистики" @@ -3558,7 +3563,7 @@ msgid "Members" msgstr "Членове" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3719,7 +3724,8 @@ msgid "Unknown language \"%s\"." msgstr "Непознат език \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Минималното ограничение на текста е 140 знака." #: actions/siteadminpanel.php:171 @@ -3998,8 +4004,7 @@ msgstr "Запазване настройките на сайта" msgid "You are not subscribed to that profile." msgstr "Не сте абонирани за този профил" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "Грешка при създаване на нов абонамент." @@ -4572,39 +4577,39 @@ msgstr "Проблем при записване на бележката." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 #, fuzzy msgid "You have been banned from subscribing." msgstr "Потребителят е забранил да се абонирате за него." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Потребителят ви е блокирал." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Не сте абонирани!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Грешка при изтриване на абонамента." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Грешка при изтриване на абонамента." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Грешка при изтриване на абонамента." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Добре дошли в %1$s, @%2$s!" @@ -4911,22 +4916,22 @@ msgstr "След" msgid "Before" msgstr "Преди" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5415,19 +5420,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Не е открит файл с настройки. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 #, fuzzy msgid "Go to the installer." msgstr "Влизане в сайта" @@ -5607,41 +5612,41 @@ msgstr "Етикети в бележките към групата %s" msgid "This page is not available in a media type you accept" msgstr "Страницата не е достъпна във вида медия, който приемате" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Форматът на файла с изображението не се поддържа." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Може да качите лого за групата ви." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Частично качване на файла." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Системна грешка при качване на файл." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Файлът не е изображение или е повреден." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "Няма такава бележка." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Неподдържан вид файл" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6100,7 +6105,7 @@ msgstr "Етикети в бележките на %s" msgid "Unknown" msgstr "Непознато действие" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Абонаменти" @@ -6108,7 +6113,7 @@ msgstr "Абонаменти" msgid "All subscriptions" msgstr "Всички абонаменти" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Абонати" @@ -6116,16 +6121,21 @@ msgstr "Абонати" msgid "All subscribers" msgstr "Всички абонати" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 #, fuzzy msgid "User ID" msgstr "Потребител" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Участник от" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Всички групи" @@ -6303,6 +6313,11 @@ msgstr "Отписване от този потребител" msgid "Unsubscribe" msgstr "Отписване" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Потребителят няма профил." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Редактиране на аватара" diff --git a/locale/br/LC_MESSAGES/statusnet.po b/locale/br/LC_MESSAGES/statusnet.po index 6e241f553..8316ecc15 100644 --- a/locale/br/LC_MESSAGES/statusnet.po +++ b/locale/br/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:14+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:18+0000\n" "Language-Team: Dutch\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: br\n" "X-Message-Group: out-statusnet\n" @@ -750,23 +750,28 @@ msgstr "Enporzhiañ" msgid "Crop" msgstr "Adframmañ" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "N'eo bet resisaet profil ebet" + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Kollet eo bet roadennoù." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Hizivaet eo bet an avatar." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Ur gudenn 'zo bet e-pad hizivadenn an avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Dilammet eo bet an Avatar." @@ -902,7 +907,7 @@ msgid "Conversation" msgstr "Kaozeadenn" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Ali" @@ -1697,7 +1702,7 @@ msgstr "Oberezhioù %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Hizivadenn izili %1$s e %2$s !" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Strolladoù" @@ -3238,7 +3243,7 @@ msgid "Description" msgstr "" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Stadegoù" @@ -3395,7 +3400,7 @@ msgid "Members" msgstr "Izili" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(hini ebet)" @@ -3555,7 +3560,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -3607,9 +3612,8 @@ msgid "Default timezone for the site; usually UTC." msgstr "" #: actions/siteadminpanel.php:262 -#, fuzzy msgid "Default language" -msgstr "Yezh d'ober ganti da gentañ" +msgstr "Yezh dre ziouer" #: actions/siteadminpanel.php:263 msgid "Site language when autodetection from browser settings is not available" @@ -3663,9 +3667,8 @@ msgid "Site-wide notice text (255 chars max; HTML okay)" msgstr "" #: actions/sitenoticeadminpanel.php:198 -#, fuzzy msgid "Save site notice" -msgstr "Dilemel un ali" +msgstr "Enrollañ ali ul lec'hienn" #: actions/smssettings.php:58 msgid "SMS settings" @@ -3822,8 +3825,7 @@ msgstr "Enrollañ an arventennoù moned" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "" @@ -4359,36 +4361,36 @@ msgstr "" msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "" -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Diposubl eo dilemel ar postel kadarnadur." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4667,22 +4669,22 @@ msgstr "War-lerc'h" msgid "Before" msgstr "Kent" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -4757,9 +4759,8 @@ msgstr "" #. TRANS: Menu item title/tooltip #: lib/adminpanelaction.php:396 -#, fuzzy msgid "Edit site notice" -msgstr "Eilañ an ali" +msgstr "Kemmañ ali al lec'hienn" #. TRANS: Menu item title/tooltip #: lib/adminpanelaction.php:404 @@ -4818,7 +4819,7 @@ msgstr "Merdeer" #: lib/applicationeditform.php:274 msgid "Desktop" -msgstr "" +msgstr "Burev" #: lib/applicationeditform.php:275 msgid "Type of application, browser or desktop" @@ -4826,11 +4827,11 @@ msgstr "" #: lib/applicationeditform.php:297 msgid "Read-only" -msgstr "" +msgstr "Lenn hepken" #: lib/applicationeditform.php:315 msgid "Read-write" -msgstr "" +msgstr "Lenn-skrivañ" #: lib/applicationeditform.php:316 msgid "Default access for this application: read-only, or read-write" @@ -4842,7 +4843,7 @@ msgstr "" #: lib/attachmentlist.php:87 msgid "Attachments" -msgstr "" +msgstr "Pezhioù stag" #: lib/attachmentlist.php:263 msgid "Author" @@ -4909,7 +4910,7 @@ msgstr "" #: lib/command.php:228 #, php-format msgid "Nudge sent to %s" -msgstr "" +msgstr "Blinkadenn kaset da %s" #: lib/command.php:254 #, php-format @@ -4955,12 +4956,12 @@ msgstr "Anv klok : %s" #: lib/command.php:404 lib/mail.php:258 #, php-format msgid "Location: %s" -msgstr "" +msgstr "Lec'hiadur : %s" #: lib/command.php:407 lib/mail.php:260 #, php-format msgid "Homepage: %s" -msgstr "" +msgstr "Lec'hienn Web : %s" #: lib/command.php:410 #, php-format @@ -5013,7 +5014,7 @@ msgstr "" #: lib/command.php:545 #, php-format msgid "Reply to %s sent" -msgstr "" +msgstr "Respont kaset da %s" #: lib/command.php:547 msgid "Error saving notice." @@ -5150,19 +5151,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5336,40 +5337,40 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "Mo" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "Ko" @@ -5665,7 +5666,7 @@ msgstr "" #: lib/messageform.php:178 lib/noticeform.php:236 msgctxt "Send button for sending notice" msgid "Send" -msgstr "" +msgstr "Kas" #: lib/noticeform.php:160 msgid "Send a notice" @@ -5729,7 +5730,7 @@ msgstr "" #: lib/noticelist.php:604 msgid "Repeated by" -msgstr "" +msgstr "Adkemeret gant" #: lib/noticelist.php:631 msgid "Reply to this notice" @@ -5812,7 +5813,7 @@ msgstr "" msgid "Unknown" msgstr "Dianav" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Koumanantoù" @@ -5820,7 +5821,7 @@ msgstr "Koumanantoù" msgid "All subscriptions" msgstr "" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Ar re koumanantet" @@ -5828,15 +5829,20 @@ msgstr "Ar re koumanantet" msgid "All subscribers" msgstr "An holl re koumanantet" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID an implijer" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Ezel abaoe" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "An holl strolladoù" @@ -6007,6 +6013,11 @@ msgstr "" msgid "Unsubscribe" msgstr "" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "An implijer-mañ n'eus profil ebet dezhañ." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Kemmañ an Avatar" @@ -6045,16 +6056,14 @@ msgid "User role" msgstr "Strolladoù implijerien" #: lib/userprofile.php:366 -#, fuzzy msgctxt "role" msgid "Administrator" -msgstr "Merourien" +msgstr "Merour" #: lib/userprofile.php:367 -#, fuzzy msgctxt "role" msgid "Moderator" -msgstr "Habaskaat" +msgstr "Habasker" #: lib/util.php:1046 msgid "a few seconds ago" @@ -6103,7 +6112,7 @@ msgstr "bloaz zo well-wazh" #: lib/webcolor.php:82 #, php-format msgid "%s is not a valid color!" -msgstr "" +msgstr "n'eo ket %s ul liv reizh !" #: lib/webcolor.php:123 #, php-format diff --git a/locale/ca/LC_MESSAGES/statusnet.po b/locale/ca/LC_MESSAGES/statusnet.po index 3ed2516c9..aaaa9f557 100644 --- a/locale/ca/LC_MESSAGES/statusnet.po +++ b/locale/ca/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:17+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:21+0000\n" "Language-Team: Catalan\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: ca\n" "X-Message-Group: out-statusnet\n" @@ -784,25 +784,30 @@ msgstr "Puja" msgid "Crop" msgstr "Retalla" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "No s'ha especificat perfil." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" "Selecciona un quadrat de l'àrea de la imatge que vols que sigui el teu " "avatar." -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "S'ha perdut el nostre fitxer de dades." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar actualitzat." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Error en actualitzar avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "S'ha suprimit l'avatar." @@ -939,7 +944,7 @@ msgid "Conversation" msgstr "Conversa" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Avisos" @@ -1781,7 +1786,7 @@ msgstr "%s línia temporal" msgid "Updates from members of %1$s on %2$s!" msgstr "Actualitzacions dels membres de %1$s el %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grups" @@ -3450,7 +3455,7 @@ msgid "Description" msgstr "Descripció" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Estadístiques" @@ -3609,7 +3614,7 @@ msgid "Members" msgstr "Membres" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Cap)" @@ -3777,7 +3782,7 @@ msgid "Unknown language \"%s\"." msgstr "Llengua desconeguda «%s»" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4059,8 +4064,7 @@ msgstr "Desa els paràmetres del lloc" msgid "You are not subscribed to that profile." msgstr "No estàs subscrit a aquest perfil." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "No s'ha pogut guardar la subscripció." @@ -4637,38 +4641,38 @@ msgstr "Problema en guardar l'avís." msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Se us ha banejat la subscripció." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Ja hi esteu subscrit!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Un usuari t'ha bloquejat." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "No estàs subscrit!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "No s'ha pogut eliminar la subscripció." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "No s'ha pogut eliminar la subscripció." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "No s'ha pogut eliminar la subscripció." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Us donem la benvinguda a %1$s, @%2$s!" @@ -4972,22 +4976,22 @@ msgstr "Posteriors" msgid "Before" msgstr "Anteriors" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5476,19 +5480,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "No s'ha trobat cap fitxer de configuració. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Podeu voler executar l'instal·lador per a corregir-ho." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Vés a l'instal·lador." @@ -5664,40 +5668,40 @@ msgstr "Etiquetes en les notificacions del grup %s" msgid "This page is not available in a media type you accept" msgstr "Aquesta pàgina no està disponible en un tipus de mèdia que acceptis." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Format d'imatge no suportat." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Pots pujar una imatge de logo per al grup." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Càrrega parcial." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Error del sistema en pujar el fitxer." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "No és una imatge o és un fitxer corrupte." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Hem perdut el nostre arxiu." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Tipus de fitxer desconegut" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6164,7 +6168,7 @@ msgstr "Etiquetes en les notificacions de %s's" msgid "Unknown" msgstr "Acció desconeguda" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Subscripcions" @@ -6172,7 +6176,7 @@ msgstr "Subscripcions" msgid "All subscriptions" msgstr "Totes les subscripcions" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Subscriptors" @@ -6180,15 +6184,20 @@ msgstr "Subscriptors" msgid "All subscribers" msgstr "Tots els subscriptors" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID de l'usuari" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Membre des de" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Tots els grups" @@ -6364,6 +6373,11 @@ msgstr "Deixar d'estar subscrit des d'aquest usuari" msgid "Unsubscribe" msgstr "Cancel·lar subscripció" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "L'usuari no té perfil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Edita l'avatar" diff --git a/locale/cs/LC_MESSAGES/statusnet.po b/locale/cs/LC_MESSAGES/statusnet.po index 4790caf6c..d9669c2d6 100644 --- a/locale/cs/LC_MESSAGES/statusnet.po +++ b/locale/cs/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:20+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:24+0000\n" "Language-Team: Czech\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: cs\n" "X-Message-Group: out-statusnet\n" @@ -782,23 +782,28 @@ msgstr "Upload" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Částečné náhrání." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Obrázek nahrán" -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Nahrávání obrázku selhalo." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar smazán." @@ -941,7 +946,7 @@ msgid "Conversation" msgstr "Umístění" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Sdělení" @@ -1788,7 +1793,7 @@ msgstr "" msgid "Updates from members of %1$s on %2$s!" msgstr "Mikroblog od %s" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Skupiny" @@ -3403,7 +3408,7 @@ msgid "Description" msgstr "Odběry" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistiky" @@ -3562,7 +3567,7 @@ msgid "Members" msgstr "Členem od" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3725,7 +3730,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4000,8 +4005,7 @@ msgstr "Nastavení" msgid "You are not subscribed to that profile." msgstr "Neodeslal jste nám profil" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "Nelze vytvořit odebírat" @@ -4576,39 +4580,39 @@ msgstr "Problém při ukládání sdělení" msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 #, fuzzy msgid "User has blocked you." msgstr "Uživatel nemá profil." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Nepřihlášen!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Nelze smazat odebírání" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Nelze smazat odebírání" -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Nelze smazat odebírání" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4916,22 +4920,22 @@ msgstr "« Novější" msgid "Before" msgstr "Starší »" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5426,20 +5430,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Žádný potvrzující kód." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5621,41 +5625,41 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "Tato stránka není k dispozici v typu média která přijímáte." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Nepodporovaný formát obrázku." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Je to příliš dlouhé. Maximální sdělení délka je 140 znaků" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Částečné náhrání." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Chyba systému při nahrávání souboru" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Není obrázkem, nebo jde o poškozený soubor." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "Žádné takové oznámení." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6119,7 +6123,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Odběry" @@ -6127,7 +6131,7 @@ msgstr "Odběry" msgid "All subscriptions" msgstr "Všechny odběry" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Odběratelé" @@ -6135,15 +6139,20 @@ msgstr "Odběratelé" msgid "All subscribers" msgstr "Všichni odběratelé" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Členem od" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "" @@ -6325,6 +6334,11 @@ msgstr "" msgid "Unsubscribe" msgstr "Odhlásit" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Uživatel nemá profil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Upravit avatar" diff --git a/locale/de/LC_MESSAGES/statusnet.po b/locale/de/LC_MESSAGES/statusnet.po index 014c75565..60835cf96 100644 --- a/locale/de/LC_MESSAGES/statusnet.po +++ b/locale/de/LC_MESSAGES/statusnet.po @@ -15,12 +15,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:23+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:27+0000\n" "Language-Team: German\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: de\n" "X-Message-Group: out-statusnet\n" @@ -781,24 +781,29 @@ msgstr "Hochladen" msgid "Crop" msgstr "Zuschneiden" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Kein Profil angegeben." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" "Wähle eine quadratische Fläche aus dem Bild, um dein Avatar zu speichern" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Daten verloren." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar aktualisiert." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Aktualisierung des Avatars fehlgeschlagen." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar gelöscht." @@ -936,7 +941,7 @@ msgid "Conversation" msgstr "Unterhaltung" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Nachrichten" @@ -1763,7 +1768,7 @@ msgstr "%s Zeitleiste" msgid "Updates from members of %1$s on %2$s!" msgstr "Aktualisierungen von %1$s auf %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Gruppen" @@ -3439,7 +3444,7 @@ msgid "Description" msgstr "Beschreibung" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistiken" @@ -3601,7 +3606,7 @@ msgid "Members" msgstr "Mitglieder" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Kein)" @@ -3773,7 +3778,8 @@ msgid "Unknown language \"%s\"." msgstr "Unbekannte Sprache „%s“" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Minimale Textlänge ist 140 Zeichen." #: actions/siteadminpanel.php:171 @@ -4050,8 +4056,7 @@ msgstr "Site-Einstellungen speichern" msgid "You are not subscribed to that profile." msgstr "Du hast dieses Profil nicht abonniert." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Konnte Abonnement nicht erstellen." @@ -4628,36 +4633,36 @@ msgstr "Problem bei Speichern der Nachricht." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Dieser Benutzer erlaubt dir nicht ihn zu abonnieren." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Bereits abonniert!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Dieser Benutzer hat dich blockiert." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Nicht abonniert!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Konnte Abonnement nicht löschen." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Konnte OMB-Abonnement nicht löschen." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Konnte Abonnement nicht löschen." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Herzlich willkommen bei %1$s, @%2$s!" @@ -4945,22 +4950,22 @@ msgstr "Später" msgid "Before" msgstr "Vorher" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Fremdinhalt kann noch nicht eingebunden werden." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Kann eingebundenen XML Inhalt nicht verarbeiten." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Eingebundener Base64 Inhalt kann noch nicht verarbeitet werden." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5470,19 +5475,19 @@ msgstr "" "tracks - not yet implemented.\n" "tracking - not yet implemented.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Keine Konfigurationsdatei gefunden." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Ich habe an folgenden Stellen nach Konfigurationsdateien gesucht: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Bitte die Installation erneut starten um das Problem zu beheben." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Zur Installation gehen." @@ -5661,40 +5666,40 @@ msgstr "Stichworte in den Nachrichten der Gruppe %s" msgid "This page is not available in a media type you accept" msgstr "Dies Seite liegt in keinem von dir akzeptierten Mediatype vor." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Bildformat wird nicht unterstützt." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Du kannst ein Logo für Deine Gruppe hochladen." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Unvollständiges Hochladen." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Systemfehler beim hochladen der Datei." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Kein Bild oder defekte Datei." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Daten verloren." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Unbekannter Dateityp" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6216,7 +6221,7 @@ msgstr "Stichworte in %ss Nachrichten" msgid "Unknown" msgstr "Unbekannter Befehl" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Abonnements" @@ -6224,7 +6229,7 @@ msgstr "Abonnements" msgid "All subscriptions" msgstr "Alle Abonnements" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Abonnenten" @@ -6232,15 +6237,20 @@ msgstr "Abonnenten" msgid "All subscribers" msgstr "Alle Abonnenten" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "Nutzer ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Mitglied seit" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Alle Gruppen" @@ -6412,6 +6422,11 @@ msgstr "Lösche dein Abonnement von diesem Benutzer" msgid "Unsubscribe" msgstr "Abbestellen" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Benutzer hat kein Profil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Avatar bearbeiten" @@ -6422,7 +6437,7 @@ msgstr "Benutzeraktionen" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Löschung des Nutzers in Arbeit..." #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/el/LC_MESSAGES/statusnet.po b/locale/el/LC_MESSAGES/statusnet.po index d2552a088..b001bc7af 100644 --- a/locale/el/LC_MESSAGES/statusnet.po +++ b/locale/el/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:26+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:30+0000\n" "Language-Team: Greek\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: el\n" "X-Message-Group: out-statusnet\n" @@ -767,23 +767,27 @@ msgstr "" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +msgid "No file uploaded." +msgstr "" + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "" -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "Ρυθμίσεις OpenID" @@ -923,7 +927,7 @@ msgid "Conversation" msgstr "Συζήτηση" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "" @@ -1759,7 +1763,7 @@ msgstr "χρονοδιάγραμμα του χρήστη %s" msgid "Updates from members of %1$s on %2$s!" msgstr "" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "" @@ -3358,7 +3362,7 @@ msgid "Description" msgstr "Περιγραφή" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "" @@ -3517,7 +3521,7 @@ msgid "Members" msgstr "Μέλη" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3678,7 +3682,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -3951,8 +3955,7 @@ msgstr "Ρυθμίσεις OpenID" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "Αδύνατη η αποθήκευση των νέων πληροφοριών του προφίλ" @@ -4502,38 +4505,38 @@ msgstr "" msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "" -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Απέτυχε η συνδρομή." -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Απέτυχε η διαγραφή συνδρομής." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Απέτυχε η διαγραφή συνδρομής." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Απέτυχε η διαγραφή συνδρομής." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4830,22 +4833,22 @@ msgstr "" msgid "Before" msgstr "" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5326,20 +5329,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Ο κωδικός επιβεβαίωσης δεν βρέθηκε." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5515,41 +5518,41 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "Αδύνατη η αποθήκευση του προφίλ." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -5999,7 +6002,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "" @@ -6007,7 +6010,7 @@ msgstr "" msgid "All subscriptions" msgstr "Όλες οι συνδρομές" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "" @@ -6015,15 +6018,20 @@ msgstr "" msgid "All subscribers" msgstr "" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Μέλος από" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "" @@ -6200,6 +6208,11 @@ msgstr "" msgid "Unsubscribe" msgstr "" +#: lib/usernoprofileexception.php:58 +#, php-format +msgid "User %s (%d) has no profile record." +msgstr "" + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "" diff --git a/locale/en_GB/LC_MESSAGES/statusnet.po b/locale/en_GB/LC_MESSAGES/statusnet.po index 361270cbb..d1f9ea3f3 100644 --- a/locale/en_GB/LC_MESSAGES/statusnet.po +++ b/locale/en_GB/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:29+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:33+0000\n" "Language-Team: British English\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: en-gb\n" "X-Message-Group: out-statusnet\n" @@ -768,23 +768,28 @@ msgstr "Upload" msgid "Crop" msgstr "Crop" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "No profile specified." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Pick a square area of the image to be your avatar" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Lost our file data." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar updated." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Failed updating avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar deleted." @@ -922,7 +927,7 @@ msgid "Conversation" msgstr "Conversation" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Notices" @@ -1744,7 +1749,7 @@ msgstr "%s timeline" msgid "Updates from members of %1$s on %2$s!" msgstr "Updates from members of %1$s on %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Groups" @@ -3372,7 +3377,7 @@ msgid "Description" msgstr "Description" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistics" @@ -3536,7 +3541,7 @@ msgid "Members" msgstr "Members" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(None)" @@ -3710,7 +3715,8 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Minimum text limit is 140 characters." #: actions/siteadminpanel.php:171 @@ -3986,8 +3992,7 @@ msgstr "Save site settings" msgid "You are not subscribed to that profile." msgstr "You are not subscribed to that profile." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Could not save subscription." @@ -4552,37 +4557,37 @@ msgstr "Problem saving group inbox." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "You have been banned from subscribing." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "User has blocked you." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Not subscribed!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Couldn't delete self-subscription." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Couldn't delete subscription." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Couldn't delete subscription." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Welcome to %1$s, @%2$s!" @@ -4883,22 +4888,22 @@ msgstr "After" msgid "Before" msgstr "Before" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5367,19 +5372,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "No configuration file found" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Go to the installer." @@ -5555,40 +5560,40 @@ msgstr "Tags in %s group's notices" msgid "This page is not available in a media type you accept" msgstr "This page is not available in a media type you accept" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Unsupported image file format." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "That file is too big. The maximum file size is %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Partial upload." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "System error uploading file." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Not an image or corrupt file." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Lost our file." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Unknown file type" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6049,7 +6054,7 @@ msgstr "Tags in %s's notices" msgid "Unknown" msgstr "Unknown" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Subscriptions" @@ -6057,7 +6062,7 @@ msgstr "Subscriptions" msgid "All subscriptions" msgstr "All subscriptions" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Subscribers" @@ -6065,15 +6070,20 @@ msgstr "Subscribers" msgid "All subscribers" msgstr "All subscribers" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "User ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Member since" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "All groups" @@ -6244,6 +6254,11 @@ msgstr "Unsubscribe from this user" msgid "Unsubscribe" msgstr "Unsubscribe" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "User has no profile." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Edit Avatar" diff --git a/locale/es/LC_MESSAGES/statusnet.po b/locale/es/LC_MESSAGES/statusnet.po index 9b21560f9..e3d3ac2e6 100644 --- a/locale/es/LC_MESSAGES/statusnet.po +++ b/locale/es/LC_MESSAGES/statusnet.po @@ -13,12 +13,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:32+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:37+0000\n" "Language-Team: Spanish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: es\n" "X-Message-Group: out-statusnet\n" @@ -775,23 +775,28 @@ msgstr "Cargar" msgid "Crop" msgstr "Cortar" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "No se especificó perfil." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Elige un área cuadrada de la imagen para que sea tu avatar" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Se perdió nuestros datos de archivo." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar actualizado" -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Error al actualizar avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar borrado." @@ -930,7 +935,7 @@ msgid "Conversation" msgstr "Conversación" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Avisos" @@ -1757,7 +1762,7 @@ msgstr "línea temporal de %s" msgid "Updates from members of %1$s on %2$s!" msgstr "¡Actualizaciones de miembros de %1$s en %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grupos" @@ -3413,7 +3418,7 @@ msgid "Description" msgstr "Descripción" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Estadísticas" @@ -3571,7 +3576,7 @@ msgid "Members" msgstr "Miembros" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Ninguno)" @@ -3739,7 +3744,7 @@ msgid "Unknown language \"%s\"." msgstr "Idioma desconocido \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4018,8 +4023,7 @@ msgstr "Guardar la configuración del sitio" msgid "You are not subscribed to that profile." msgstr "No te has suscrito a ese perfil." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "No se ha podido guardar la suscripción." @@ -4588,38 +4592,38 @@ msgstr "Hubo un problema al guardar el aviso." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Se te ha prohibido la suscripción." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "El usuario te ha bloqueado." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "¡No estás suscrito!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "No se pudo eliminar la suscripción." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "No se pudo eliminar la suscripción." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "No se pudo eliminar la suscripción." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Bienvenido a %1$s, @%2$s!" @@ -4925,22 +4929,22 @@ msgstr "Después" msgid "Before" msgstr "Antes" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5423,19 +5427,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Ningún archivo de configuración encontrado. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Ir al instalador." @@ -5615,40 +5619,40 @@ msgstr "Tags en avisos del grupo %s" msgid "This page is not available in a media type you accept" msgstr "Esta página no está disponible en el tipo de medio que aceptas." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Formato de imagen no soportado." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Puedes cargar una imagen de logo para tu grupo." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Carga parcial." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Error del sistema al cargar el archivo." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "No es una imagen o es un fichero corrupto." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Se perdió nuestro archivo." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Tipo de archivo desconocido" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6116,7 +6120,7 @@ msgstr "Tags en avisos de %s" msgid "Unknown" msgstr "Acción desconocida" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Suscripciones" @@ -6124,7 +6128,7 @@ msgstr "Suscripciones" msgid "All subscriptions" msgstr "Todas las suscripciones" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Suscriptores" @@ -6133,15 +6137,20 @@ msgstr "Suscriptores" msgid "All subscribers" msgstr "Todos los suscriptores" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID de usuario" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Miembro desde" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Todos los grupos" @@ -6322,6 +6331,11 @@ msgstr "Desuscribirse de este usuario" msgid "Unsubscribe" msgstr "Cancelar suscripción" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "El usuario no tiene un perfil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "editar avatar" diff --git a/locale/fa/LC_MESSAGES/statusnet.po b/locale/fa/LC_MESSAGES/statusnet.po index 7d948015a..23fa734de 100644 --- a/locale/fa/LC_MESSAGES/statusnet.po +++ b/locale/fa/LC_MESSAGES/statusnet.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:38+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:43+0000\n" "Last-Translator: Ahmad Sufi Mahmudi\n" "Language-Team: Persian\n" "MIME-Version: 1.0\n" @@ -20,7 +20,7 @@ msgstr "" "X-Language-Code: fa\n" "X-Message-Group: out-statusnet\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" #. TRANS: Page title @@ -770,23 +770,28 @@ msgstr "پایین‌گذاری" msgid "Crop" msgstr "برش" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "کاربری مشخص نشده است." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "یک مربع از عکس خود را انتخاب کنید تا چهره‌ی شما باشد." -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "فایل اطلاعات خود را گم کرده ایم." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "چهره به روز رسانی شد." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "به روز رسانی چهره موفقیت آمیر نبود." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "چهره پاک شد." @@ -926,7 +931,7 @@ msgid "Conversation" msgstr "مکالمه" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "پیام‌ها" @@ -1759,7 +1764,7 @@ msgstr "خط زمانی %s" msgid "Updates from members of %1$s on %2$s!" msgstr "به روز رسانی کابران %1$s در %2$s" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "گروه‌ها" @@ -3359,7 +3364,7 @@ msgid "Description" msgstr "" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "آمار" @@ -3518,7 +3523,7 @@ msgid "Members" msgstr "اعضا" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "هیچ" @@ -3683,7 +3688,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -3958,8 +3963,7 @@ msgstr "تنظیمات چهره" msgid "You are not subscribed to that profile." msgstr "شما به این پروفيل متعهد نشدید" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "" @@ -4507,36 +4511,36 @@ msgstr "مشکل در ذخیره کردن آگهی." msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "قبلا تایید شده !" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "" -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "تایید نشده!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "نمی‌توان تصدیق پست الکترونیک را پاک کرد." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "خوش امدید به %1$s , @%2$s!" @@ -4833,22 +4837,22 @@ msgstr "بعد از" msgid "Before" msgstr "قبل از" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5329,19 +5333,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "شما ممکن است بخواهید نصاب را اجرا کنید تا این را تعمیر کند." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "برو به نصاب." @@ -5516,41 +5520,41 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "فرمت(فایل) عکس پشتیبانی نشده." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" "است . این فایل بسیار یزرگ است %s بیشترین مقدار قابل قبول برای اندازه ی فایل." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "خطای سیستم ارسال فایل." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "تصویر یا فایل خرابی نیست" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "فایلمان گم شده" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "نوع فایل پشتیبانی نشده" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "مگابایت" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "کیلوبایت" @@ -6004,7 +6008,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "اشتراک‌ها" @@ -6012,7 +6016,7 @@ msgstr "اشتراک‌ها" msgid "All subscriptions" msgstr "تمام اشتراک‌ها" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "مشترک‌ها" @@ -6020,15 +6024,20 @@ msgstr "مشترک‌ها" msgid "All subscribers" msgstr "تمام مشترک‌ها" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "شناسه کاربر" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "عضو شده از" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "تمام گروه‌ها" @@ -6200,6 +6209,11 @@ msgstr "" msgid "Unsubscribe" msgstr "" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "کاربر هیچ شناس‌نامه‌ای ندارد." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "ویرایش اواتور" diff --git a/locale/fi/LC_MESSAGES/statusnet.po b/locale/fi/LC_MESSAGES/statusnet.po index 7892ef932..035d69816 100644 --- a/locale/fi/LC_MESSAGES/statusnet.po +++ b/locale/fi/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:35+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:40+0000\n" "Language-Team: Finnish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: fi\n" "X-Message-Group: out-statusnet\n" @@ -787,23 +787,28 @@ msgstr "Lataa" msgid "Crop" msgstr "Rajaa" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Profiilia ei ole määritelty." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Valitse neliön muotoinen alue kuvasta profiilikuvaksi" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Tiedoston data hävisi." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Kuva päivitetty." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Profiilikuvan päivittäminen epäonnistui." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Kuva poistettu." @@ -941,7 +946,7 @@ msgid "Conversation" msgstr "Keskustelu" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Päivitykset" @@ -1791,7 +1796,7 @@ msgstr "%s aikajana" msgid "Updates from members of %1$s on %2$s!" msgstr "Ryhmän %1$s käyttäjien päivitykset palvelussa %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Ryhmät" @@ -3485,7 +3490,7 @@ msgid "Description" msgstr "Kuvaus" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Tilastot" @@ -3643,7 +3648,7 @@ msgid "Members" msgstr "Jäsenet" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Tyhjä)" @@ -3814,7 +3819,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4096,8 +4101,7 @@ msgstr "Profiilikuva-asetukset" msgid "You are not subscribed to that profile." msgstr "Et ole tilannut tämän käyttäjän päivityksiä." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Tilausta ei onnistuttu tallentamaan." @@ -4678,39 +4682,39 @@ msgstr "Ongelma päivityksen tallentamisessa." msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 #, fuzzy msgid "You have been banned from subscribing." msgstr "Käyttäjä on estänyt sinua tilaamasta päivityksiä." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Käyttäjä on asettanut eston sinulle." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Ei ole tilattu!." -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Ei voitu poistaa tilausta." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Ei voitu poistaa tilausta." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Ei voitu poistaa tilausta." -#: classes/User.php:378 +#: classes/User.php:363 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Viesti käyttäjälle %1$s, %2$s" @@ -5016,22 +5020,22 @@ msgstr "Myöhemmin" msgid "Before" msgstr "Aiemmin" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 #, fuzzy @@ -5527,20 +5531,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Varmistuskoodia ei ole annettu." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 #, fuzzy msgid "Go to the installer." msgstr "Kirjaudu sisään palveluun" @@ -5723,40 +5727,40 @@ msgstr "Tagit ryhmän %s päivityksissä" msgid "This page is not available in a media type you accept" msgstr "Tämä sivu ei ole saatavilla sinulle sopivassa mediatyypissä." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Kuvatiedoston formaattia ei ole tuettu." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Voit ladata ryhmälle logon." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Osittain ladattu palvelimelle." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Tiedoston lähetyksessä tapahtui järjestelmävirhe." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Tuo ei ole kelvollinen kuva tai tiedosto on rikkoutunut." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Tiedosto hävisi." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Tunnistamaton tiedoston tyyppi" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6230,7 +6234,7 @@ msgstr "Tagit käyttäjän %s päivityksissä" msgid "Unknown" msgstr "Tuntematon toiminto" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Tilaukset" @@ -6238,7 +6242,7 @@ msgstr "Tilaukset" msgid "All subscriptions" msgstr "Kaikki tilaukset" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Tilaajat" @@ -6246,16 +6250,21 @@ msgstr "Tilaajat" msgid "All subscribers" msgstr "Kaikki tilaajat" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 #, fuzzy msgid "User ID" msgstr "Käyttäjä" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Käyttäjänä alkaen" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Kaikki ryhmät" @@ -6437,6 +6446,11 @@ msgstr "Peruuta tämän käyttäjän tilaus" msgid "Unsubscribe" msgstr "Peruuta tilaus" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Käyttäjällä ei ole profiilia." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/fr/LC_MESSAGES/statusnet.po b/locale/fr/LC_MESSAGES/statusnet.po index 70155e450..76d83ea6c 100644 --- a/locale/fr/LC_MESSAGES/statusnet.po +++ b/locale/fr/LC_MESSAGES/statusnet.po @@ -14,12 +14,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:41+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:47+0000\n" "Language-Team: French\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: fr\n" "X-Message-Group: out-statusnet\n" @@ -785,23 +785,28 @@ msgstr "Transfert" msgid "Crop" msgstr "Recadrer" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Aucun profil n’a été spécifié." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Sélectionnez une zone de forme carrée pour définir votre avatar" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Données perdues." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar mis à jour." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "La mise à jour de l’avatar a échoué." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar supprimé." @@ -939,7 +944,7 @@ msgid "Conversation" msgstr "Conversation" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Avis" @@ -1763,7 +1768,7 @@ msgstr "Activité de %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Mises à jour des membres de %1$s dans %2$s !" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Groupes" @@ -3449,7 +3454,7 @@ msgid "Description" msgstr "Description" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistiques" @@ -3616,7 +3621,7 @@ msgid "Members" msgstr "Membres" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(aucun)" @@ -3800,7 +3805,8 @@ msgid "Unknown language \"%s\"." msgstr "Langue « %s » inconnue." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "La limite minimale de texte est de 140 caractères." #: actions/siteadminpanel.php:171 @@ -4077,8 +4083,7 @@ msgstr "Sauvegarder les paramètres des instantanés" msgid "You are not subscribed to that profile." msgstr "Vous n’êtes pas abonné(e) à ce profil." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Impossible d’enregistrer l’abonnement." @@ -4667,35 +4672,35 @@ msgstr "Problème lors de l’enregistrement de la boîte de réception du group msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Il vous avez été interdit de vous abonner." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Déjà abonné !" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Cet utilisateur vous a bloqué." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Pas abonné !" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Impossible de supprimer l’abonnement à soi-même." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Impossible de supprimer le jeton OMB de l'abonnement ." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Impossible de cesser l’abonnement" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Bienvenue à %1$s, @%2$s !" @@ -4983,22 +4988,22 @@ msgstr "Après" msgid "Before" msgstr "Avant" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "Attendait un élément racine mais a reçu tout un document XML." + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Impossible de gérer le contenu distant pour le moment." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Impossible de gérer le contenu XML embarqué pour le moment." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Impossible de gérer le contenu en Base64 embarqué pour le moment." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5518,20 +5523,20 @@ msgstr "" "tracks - pas encore implémenté.\n" "tracking - pas encore implémenté.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Aucun fichier de configuration n’a été trouvé. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" "J’ai cherché des fichiers de configuration dans les emplacements suivants : " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Vous pouvez essayer de lancer l’installeur pour régler ce problème." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Aller au programme d’installation" @@ -5712,40 +5717,40 @@ msgid "This page is not available in a media type you accept" msgstr "" "Cette page n’est pas disponible dans un des formats que vous avez autorisés." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Format de fichier d’image non supporté." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Ce fichier est trop grand. La taille maximale est %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Transfert partiel." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Erreur système lors du transfert du fichier." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Ceci n’est pas une image, ou c’est un fichier corrompu." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Fichier perdu." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Type de fichier inconnu" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "Mo" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "Ko" @@ -6280,7 +6285,7 @@ msgstr "Marques dans les avis de %s" msgid "Unknown" msgstr "Inconnu" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Abonnements" @@ -6288,7 +6293,7 @@ msgstr "Abonnements" msgid "All subscriptions" msgstr "Tous les abonnements" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Abonnés" @@ -6296,15 +6301,20 @@ msgstr "Abonnés" msgid "All subscribers" msgstr "Tous les abonnés" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID de l’utilisateur" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Membre depuis" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Tous les groupes" @@ -6475,6 +6485,11 @@ msgstr "Ne plus suivre cet utilisateur" msgid "Unsubscribe" msgstr "Désabonnement" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Aucun profil ne correspond à cet utilisateur." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Modifier l’avatar" @@ -6485,7 +6500,7 @@ msgstr "Actions de l’utilisateur" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Suppression de l'utilisateur en cours..." #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/ga/LC_MESSAGES/statusnet.po b/locale/ga/LC_MESSAGES/statusnet.po index 9d7775580..6e5d0d232 100644 --- a/locale/ga/LC_MESSAGES/statusnet.po +++ b/locale/ga/LC_MESSAGES/statusnet.po @@ -8,12 +8,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:44+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:50+0000\n" "Language-Team: Irish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: ga\n" "X-Message-Group: out-statusnet\n" @@ -788,23 +788,28 @@ msgstr "Subir" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Non se especificou ningún perfil." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar actualizado." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Acounteceu un fallo ó actualizar o avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "Avatar actualizado." @@ -952,7 +957,7 @@ msgid "Conversation" msgstr "Código de confirmación." #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Chíos" @@ -1825,7 +1830,7 @@ msgstr "Liña de tempo de %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Actualizacións dende %1$s en %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "" @@ -3521,7 +3526,7 @@ msgid "Description" msgstr "Subscricións" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Estatísticas" @@ -3683,7 +3688,7 @@ msgid "Members" msgstr "Membro dende" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 #, fuzzy msgid "(None)" @@ -3864,7 +3869,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4147,8 +4152,7 @@ msgstr "Configuracións de Twitter" msgid "You are not subscribed to that profile." msgstr "Non estás suscrito a ese perfil" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Non se pode gardar a subscrición." @@ -4734,39 +4738,39 @@ msgstr "Aconteceu un erro ó gardar o chío." msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 #, fuzzy msgid "You have been banned from subscribing." msgstr "Este usuario non che permite suscribirte a el." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "O usuario bloqueoute." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Non está suscrito!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Non se pode eliminar a subscrición." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Non se pode eliminar a subscrición." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Non se pode eliminar a subscrición." -#: classes/User.php:378 +#: classes/User.php:363 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Mensaxe de %1$s en %2$s" @@ -5077,22 +5081,22 @@ msgstr "« Despois" msgid "Before" msgstr "Antes »" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 #, fuzzy @@ -5628,20 +5632,20 @@ msgstr "" "tracks - non implementado por agora.\n" "tracking - non implementado por agora.\n" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Sen código de confirmación." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5826,42 +5830,42 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "Esta páxina non está dispoñíbel no tipo de medio que aceptas" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Formato de ficheiro de imaxe non soportado." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Podes actualizar a túa información do perfil persoal aquí" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Carga parcial." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Aconteceu un erro no sistema namentras se estaba cargando o ficheiro." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Non é unha imaxe ou está corrupta." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "Bloqueo de usuario fallido." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 #, fuzzy msgid "Unknown file type" msgstr "tipo de ficheiro non soportado" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6389,7 +6393,7 @@ msgstr "O usuario non ten último chio." msgid "Unknown" msgstr "Acción descoñecida" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Subscricións" @@ -6397,7 +6401,7 @@ msgstr "Subscricións" msgid "All subscriptions" msgstr "Tódalas subscricións" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Subscritores" @@ -6406,16 +6410,21 @@ msgstr "Subscritores" msgid "All subscribers" msgstr "Subscritores" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 #, fuzzy msgid "User ID" msgstr "Usuario" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Membro dende" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 #, fuzzy msgid "All groups" msgstr "Tódalas etiquetas" @@ -6604,6 +6613,11 @@ msgstr "Desuscribir de %s" msgid "Unsubscribe" msgstr "Eliminar subscrición" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "O usuario non ten perfil." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/he/LC_MESSAGES/statusnet.po b/locale/he/LC_MESSAGES/statusnet.po index 27c7af90f..f1fd35346 100644 --- a/locale/he/LC_MESSAGES/statusnet.po +++ b/locale/he/LC_MESSAGES/statusnet.po @@ -7,12 +7,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:47+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:53+0000\n" "Language-Team: Hebrew\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: he\n" "X-Message-Group: out-statusnet\n" @@ -780,23 +780,28 @@ msgstr "ההעלה" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "העלאה חלקית." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "התמונה עודכנה." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "עדכון התמונה נכשל." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "התמונה עודכנה." @@ -941,7 +946,7 @@ msgid "Conversation" msgstr "מיקום" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "הודעות" @@ -1796,7 +1801,7 @@ msgstr "" msgid "Updates from members of %1$s on %2$s!" msgstr "מיקרובלוג מאת %s" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "קבוצות" @@ -3406,7 +3411,7 @@ msgid "Description" msgstr "הרשמות" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "סטטיסטיקה" @@ -3566,7 +3571,7 @@ msgid "Members" msgstr "חבר מאז" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3728,7 +3733,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4002,8 +4007,7 @@ msgstr "הגדרות" msgid "You are not subscribed to that profile." msgstr "לא שלחנו אלינו את הפרופיל הזה" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "יצירת המנוי נכשלה." @@ -4578,39 +4582,39 @@ msgstr "בעיה בשמירת ההודעה." msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 #, fuzzy msgid "User has blocked you." msgstr "למשתמש אין פרופיל." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "לא מנוי!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "מחיקת המנוי לא הצליחה." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "מחיקת המנוי לא הצליחה." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "מחיקת המנוי לא הצליחה." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4918,22 +4922,22 @@ msgstr "<< אחרי" msgid "Before" msgstr "לפני >>" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5425,20 +5429,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "אין קוד אישור." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5621,41 +5625,41 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "עמוד זה אינו זמין בסוג מדיה שאתה יכול לקבל" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "פורמט התמונה אינו נתמך." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "זה ארוך מידי. אורך מירבי להודעה הוא 140 אותיות." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "העלאה חלקית." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "שגיאת מערכת בהעלאת הקובץ." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "זהו לא קובץ תמונה, או שחל בו שיבוש." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "אין הודעה כזו." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6119,7 +6123,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "הרשמות" @@ -6127,7 +6131,7 @@ msgstr "הרשמות" msgid "All subscriptions" msgstr "כל המנויים" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "מנויים" @@ -6136,16 +6140,21 @@ msgstr "מנויים" msgid "All subscribers" msgstr "מנויים" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 #, fuzzy msgid "User ID" msgstr "מתשמש" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "חבר מאז" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "" @@ -6328,6 +6337,11 @@ msgstr "" msgid "Unsubscribe" msgstr "בטל מנוי" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "למשתמש אין פרופיל." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/hsb/LC_MESSAGES/statusnet.po b/locale/hsb/LC_MESSAGES/statusnet.po index f61fb0a82..1411d983f 100644 --- a/locale/hsb/LC_MESSAGES/statusnet.po +++ b/locale/hsb/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:50+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:56+0000\n" "Language-Team: Dutch\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: hsb\n" "X-Message-Group: out-statusnet\n" @@ -749,23 +749,28 @@ msgstr "Nahrać" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Žadyn profil podaty." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Awatar zaktualizowany." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Awatar zničeny." @@ -900,7 +905,7 @@ msgid "Conversation" msgstr "Konwersacija" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Zdźělenki" @@ -1698,7 +1703,7 @@ msgstr "" msgid "Updates from members of %1$s on %2$s!" msgstr "" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Skupiny" @@ -3227,7 +3232,7 @@ msgid "Description" msgstr "Wopisanje" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistika" @@ -3384,7 +3389,7 @@ msgid "Members" msgstr "Čłonojo" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Žadyn)" @@ -3543,7 +3548,7 @@ msgid "Unknown language \"%s\"." msgstr "Njeznata rěč \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -3804,8 +3809,7 @@ msgstr "Nastajenja wobrazowkoweho fota składować" msgid "You are not subscribed to that profile." msgstr "Njejsy tón profil abonował." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "" @@ -4341,35 +4345,35 @@ msgstr "" msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Hižo abonowany!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Wužiwar je će zablokował." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Njeje abonowany!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Sebjeabonement njeje so dał zničić." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Znamjo OMB-abonementa njeda so zhašeć." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Abonoment njeje so dał zničić." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4648,22 +4652,22 @@ msgstr "" msgid "Before" msgstr "" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5133,19 +5137,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Žana konfiguraciska dataja namakana. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5319,40 +5323,40 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Dźělne nahraće." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Naša dataja je so zhubiła." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Njeznaty datajowy typ" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "KB" @@ -5795,7 +5799,7 @@ msgstr "" msgid "Unknown" msgstr "Njeznaty" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Abonementy" @@ -5803,7 +5807,7 @@ msgstr "Abonementy" msgid "All subscriptions" msgstr "Wšě abonementy" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Abonenća" @@ -5811,15 +5815,20 @@ msgstr "Abonenća" msgid "All subscribers" msgstr "Wšitcy abonenća" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "Wužiwarski ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Čłon wot" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Wšě skupiny" @@ -5990,6 +5999,11 @@ msgstr "Tutoho wužiwarja wotskazać" msgid "Unsubscribe" msgstr "Wotskazać" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Wužiwar nima profil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Awatar wobdźěłać" diff --git a/locale/ia/LC_MESSAGES/statusnet.po b/locale/ia/LC_MESSAGES/statusnet.po index b31fc0d2d..c8aa5e616 100644 --- a/locale/ia/LC_MESSAGES/statusnet.po +++ b/locale/ia/LC_MESSAGES/statusnet.po @@ -8,12 +8,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:53+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:09:59+0000\n" "Language-Team: Interlingua\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: ia\n" "X-Message-Group: out-statusnet\n" @@ -771,23 +771,28 @@ msgstr "Incargar" msgid "Crop" msgstr "Taliar" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Nulle profilo specificate." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Selige un area quadrate del imagine pro facer lo tu avatar" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Datos del file perdite." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar actualisate." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Actualisation del avatar fallite." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar delite." @@ -925,7 +930,7 @@ msgid "Conversation" msgstr "Conversation" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Notas" @@ -1747,7 +1752,7 @@ msgstr "Chronologia de %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Actualisationes de membros de %1$s in %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Gruppos" @@ -3408,7 +3413,7 @@ msgid "Description" msgstr "Description" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statisticas" @@ -3575,7 +3580,7 @@ msgid "Members" msgstr "Membros" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Nulle)" @@ -3756,7 +3761,8 @@ msgid "Unknown language \"%s\"." msgstr "Lingua \"%s\" incognite." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Le limite minimal del texto es 140 characteres." #: actions/siteadminpanel.php:171 @@ -4029,8 +4035,7 @@ msgstr "Salveguardar configuration de instantaneos" msgid "You are not subscribed to that profile." msgstr "Tu non es subscribite a iste profilo." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Non poteva salveguardar le subscription." @@ -4612,35 +4617,35 @@ msgstr "Problema salveguardar le cassa de entrata del gruppo." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Tu ha essite blocate del subscription." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Ja subscribite!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Le usator te ha blocate." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Non subscribite!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Non poteva deler auto-subscription." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Non poteva deler le indicio OMB del subscription." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Non poteva deler subscription." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Benvenite a %1$s, @%2$s!" @@ -4925,22 +4930,22 @@ msgstr "Post" msgid "Before" msgstr "Ante" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Non pote ancora tractar contento remote." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Non pote ancora tractar contento XML incastrate." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Non pote ancora tractar contento Base64 incastrate." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5455,19 +5460,19 @@ msgstr "" "tracks - non ancora implementate.\n" "tracking - non ancora implementate.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Nulle file de configuration trovate. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Io cercava files de configuration in le sequente locos: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Considera executar le installator pro reparar isto." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Ir al installator." @@ -5645,40 +5650,40 @@ msgstr "Etiquettas in le notas del gruppo %s" msgid "This page is not available in a media type you accept" msgstr "Iste pagina non es disponibile in un formato que tu accepta" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Formato de file de imagine non supportate." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Iste file es troppo grande. Le dimension maximal es %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Incargamento partial." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Error de systema durante le incargamento del file." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Le file non es un imagine o es defectuose." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "File perdite." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Typo de file incognite" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "KB" @@ -6213,7 +6218,7 @@ msgstr "Etiquettas in le notas de %s" msgid "Unknown" msgstr "Incognite" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Subscriptiones" @@ -6221,7 +6226,7 @@ msgstr "Subscriptiones" msgid "All subscriptions" msgstr "Tote le subscriptiones" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Subscriptores" @@ -6229,15 +6234,20 @@ msgstr "Subscriptores" msgid "All subscribers" msgstr "Tote le subscriptores" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID del usator" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Membro depost" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Tote le gruppos" @@ -6408,6 +6418,11 @@ msgstr "Cancellar subscription a iste usator" msgid "Unsubscribe" msgstr "Cancellar subscription" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Le usator non ha un profilo." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Modificar avatar" diff --git a/locale/is/LC_MESSAGES/statusnet.po b/locale/is/LC_MESSAGES/statusnet.po index 595431e9a..ca72d54a3 100644 --- a/locale/is/LC_MESSAGES/statusnet.po +++ b/locale/is/LC_MESSAGES/statusnet.po @@ -8,12 +8,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:56+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:10+0000\n" "Language-Team: Icelandic\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: is\n" "X-Message-Group: out-statusnet\n" @@ -777,24 +777,29 @@ msgstr "Hlaða upp" msgid "Crop" msgstr "Skera af" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Engin persónuleg síða tilgreind" + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" "Veldu ferningslaga svæði á upphaflegu myndinni sem einkennismyndina þína" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Týndum skráargögnunum okkar" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Mynd hefur verið uppfærð." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Mistókst að uppfæra mynd" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "" @@ -934,7 +939,7 @@ msgid "Conversation" msgstr "" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Babl" @@ -1778,7 +1783,7 @@ msgstr "Rás %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Færslur frá %1$s á %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Hópar" @@ -3450,7 +3455,7 @@ msgid "Description" msgstr "Lýsing" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Tölfræði" @@ -3608,7 +3613,7 @@ msgid "Members" msgstr "Meðlimir" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Ekkert)" @@ -3770,7 +3775,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4050,8 +4055,7 @@ msgstr "Stillingar fyrir mynd" msgid "You are not subscribed to that profile." msgstr "Þú ert ekki áskrifandi." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Gat ekki vistað áskrift." @@ -4627,39 +4631,39 @@ msgstr "Vandamál komu upp við að vista babl." msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 #, fuzzy msgid "You have been banned from subscribing." msgstr "Þessi notandi hefur bannað þér að gerast áskrifandi" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Notandinn hefur lokað á þig." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Ekki í áskrift!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Gat ekki eytt áskrift." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Gat ekki eytt áskrift." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Gat ekki eytt áskrift." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4965,22 +4969,22 @@ msgstr "Eftir" msgid "Before" msgstr "Áður" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 #, fuzzy @@ -5474,20 +5478,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Enginn staðfestingarlykill." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 #, fuzzy msgid "Go to the installer." msgstr "Skrá þig inn á síðuna" @@ -5667,40 +5671,40 @@ msgid "This page is not available in a media type you accept" msgstr "" "Þessi síða er ekki aðgengileg í margmiðlunargerðinni sem þú tekur á móti" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Skráarsnið myndar ekki stutt." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Þetta er of langt. Hámarkslengd babls er 140 tákn." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Upphal að hluta til." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Kerfisvilla kom upp við upphal skráar." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Annaðhvort ekki mynd eða þá að skráin er gölluð." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Týndum skránni okkar" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Óþekkt skráargerð" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6163,7 +6167,7 @@ msgstr "Merki í babli %s" msgid "Unknown" msgstr "Óþekkt aðgerð" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Áskriftir" @@ -6171,7 +6175,7 @@ msgstr "Áskriftir" msgid "All subscriptions" msgstr "Allar áskriftir" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Áskrifendur" @@ -6179,15 +6183,20 @@ msgstr "Áskrifendur" msgid "All subscribers" msgstr "Allir áskrifendur" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Meðlimur síðan" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Allir hópar" @@ -6367,6 +6376,11 @@ msgstr "Hætta sem áskrifandi að þessum notanda" msgid "Unsubscribe" msgstr "Fara úr áskrift" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Notandi hefur enga persónulega síðu." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "" diff --git a/locale/it/LC_MESSAGES/statusnet.po b/locale/it/LC_MESSAGES/statusnet.po index d4d6fc3ef..681f60f0a 100644 --- a/locale/it/LC_MESSAGES/statusnet.po +++ b/locale/it/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:40:59+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:13+0000\n" "Language-Team: Italian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: it\n" "X-Message-Group: out-statusnet\n" @@ -772,23 +772,28 @@ msgstr "Carica" msgid "Crop" msgstr "Ritaglia" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Nessun profilo specificato." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Scegli un'area quadrata per la tua immagine personale" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Perso il nostro file di dati." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Immagine aggiornata." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Aggiornamento dell'immagine non riuscito." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Immagine eliminata." @@ -926,7 +931,7 @@ msgid "Conversation" msgstr "Conversazione" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Messaggi" @@ -1751,7 +1756,7 @@ msgstr "Attività di %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Messaggi dai membri di %1$s su %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Gruppi" @@ -3408,7 +3413,7 @@ msgid "Description" msgstr "Descrizione" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistiche" @@ -3574,7 +3579,7 @@ msgid "Members" msgstr "Membri" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(nessuno)" @@ -3754,7 +3759,8 @@ msgid "Unknown language \"%s\"." msgstr "Lingua \"%s\" sconosciuta." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Il limite minimo del testo è di 140 caratteri." #: actions/siteadminpanel.php:171 @@ -4026,8 +4032,7 @@ msgstr "Salva impostazioni snapshot" msgid "You are not subscribed to that profile." msgstr "Non hai una abbonamento a quel profilo." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Impossibile salvare l'abbonamento." @@ -4612,35 +4617,35 @@ msgstr "Problema nel salvare la casella della posta del gruppo." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Non ti è possibile abbonarti." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Hai già l'abbonamento!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "L'utente non ti consente di seguirlo." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Non hai l'abbonamento!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Impossibile eliminare l'auto-abbonamento." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Impossibile eliminare il token di abbonamento OMB." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Impossibile eliminare l'abbonamento." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Benvenuti su %1$s, @%2$s!" @@ -4927,22 +4932,22 @@ msgstr "Successivi" msgid "Before" msgstr "Precedenti" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Impossibile gestire contenuti remoti." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Impossibile gestire contenuti XML incorporati." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Impossibile gestire contenuti Base64." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5458,21 +5463,21 @@ msgstr "" "tracks - non ancora implementato\n" "tracking - non ancora implementato\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Non è stato trovato alcun file di configurazione. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "I file di configurazione sono stati cercati in questi posti: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" "Potrebbe essere necessario lanciare il programma d'installazione per " "correggere il problema." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Vai al programma d'installazione." @@ -5649,40 +5654,40 @@ msgstr "Etichette nei messaggi del gruppo %s" msgid "This page is not available in a media type you accept" msgstr "Questa pagina non è disponibile in un tipo di supporto che tu accetti" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Formato file immagine non supportato." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Quel file è troppo grande. La dimensione massima è %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Caricamento parziale." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Errore di sistema nel caricare il file." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Non è un'immagine o il file è danneggiato." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Perso il nostro file." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Tipo di file sconosciuto" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6216,7 +6221,7 @@ msgstr "Etichette nei messaggi di %s" msgid "Unknown" msgstr "Sconosciuto" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Abbonamenti" @@ -6224,7 +6229,7 @@ msgstr "Abbonamenti" msgid "All subscriptions" msgstr "Tutti gli abbonamenti" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Abbonati" @@ -6232,15 +6237,20 @@ msgstr "Abbonati" msgid "All subscribers" msgstr "Tutti gli abbonati" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID utente" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Membro dal" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Tutti i gruppi" @@ -6411,6 +6421,11 @@ msgstr "Annulla l'abbonamento da questo utente" msgid "Unsubscribe" msgstr "Disabbonati" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "L'utente non ha un profilo." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Modifica immagine" diff --git a/locale/ja/LC_MESSAGES/statusnet.po b/locale/ja/LC_MESSAGES/statusnet.po index 85b83bfe9..a50da36c4 100644 --- a/locale/ja/LC_MESSAGES/statusnet.po +++ b/locale/ja/LC_MESSAGES/statusnet.po @@ -11,12 +11,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:02+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:29+0000\n" "Language-Team: Japanese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: ja\n" "X-Message-Group: out-statusnet\n" @@ -766,23 +766,28 @@ msgstr "アップロード" msgid "Crop" msgstr "切り取り" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "プロファイル記述がありません。" + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "あなたのアバターとなるイメージを正方形で指定" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "ファイルデータを紛失しました。" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "アバターが更新されました。" -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "アバターの更新に失敗しました。" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "アバターが削除されました。" @@ -921,7 +926,7 @@ msgid "Conversation" msgstr "会話" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "つぶやき" @@ -1749,7 +1754,7 @@ msgstr "%s のタイムライン" msgid "Updates from members of %1$s on %2$s!" msgstr "%2$s 上の %1$s のメンバーから更新する" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "グループ" @@ -3404,7 +3409,7 @@ msgid "Description" msgstr "概要" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "統計データ" @@ -3572,7 +3577,7 @@ msgid "Members" msgstr "メンバー" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(なし)" @@ -3753,7 +3758,8 @@ msgid "Unknown language \"%s\"." msgstr "不明な言語 \"%s\"" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "最小のテキスト制限は140字です。" #: actions/siteadminpanel.php:171 @@ -4035,8 +4041,7 @@ msgstr "サイト設定の保存" msgid "You are not subscribed to that profile." msgstr "あなたはそのプロファイルにフォローされていません。" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "フォローを保存できません。" @@ -4612,36 +4617,36 @@ msgstr "グループ受信箱を保存する際に問題が発生しました。 msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "あなたはフォローが禁止されました。" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "すでにフォローしています!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "ユーザはあなたをブロックしました。" -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "フォローしていません!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "自己フォローを削除できません。" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "フォローを削除できません" -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "フォローを削除できません" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "ようこそ %1$s、@%2$s!" @@ -4944,22 +4949,22 @@ msgstr "<<後" msgid "Before" msgstr "前>>" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5432,21 +5437,21 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "コンフィギュレーションファイルがありません。 " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "私は以下の場所でコンフィギュレーションファイルを探しました: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" "あなたは、これを修理するためにインストーラを動かしたがっているかもしれませ" "ん。" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "インストーラへ。" @@ -5622,40 +5627,40 @@ msgstr "%s グループのつぶやきにあるタグ" msgid "This page is not available in a media type you accept" msgstr "このページはあなたが承認したメディアタイプでは利用できません。" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "サポート外の画像形式です。" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "ファイルが大きすぎます。最大ファイルサイズは %s 。" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "不完全なアップロード。" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "ファイルのアップロードでシステムエラー" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "画像ではないかファイルが破損しています。" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "ファイルを紛失。" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "不明なファイルタイプ" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6196,7 +6201,7 @@ msgstr "%s のつぶやきのタグ" msgid "Unknown" msgstr "不明" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "フォロー" @@ -6204,7 +6209,7 @@ msgstr "フォロー" msgid "All subscriptions" msgstr "すべてのフォロー" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "フォローされている" @@ -6212,15 +6217,20 @@ msgstr "フォローされている" msgid "All subscribers" msgstr "すべてのフォローされている" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ユーザID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "利用開始日" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "全てのグループ" @@ -6391,6 +6401,11 @@ msgstr "この利用者からのフォローを解除する" msgid "Unsubscribe" msgstr "フォロー解除" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "ユーザはプロフィールをもっていません。" + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "アバターを編集する" diff --git a/locale/ko/LC_MESSAGES/statusnet.po b/locale/ko/LC_MESSAGES/statusnet.po index 41533a426..d62e6ac5b 100644 --- a/locale/ko/LC_MESSAGES/statusnet.po +++ b/locale/ko/LC_MESSAGES/statusnet.po @@ -7,12 +7,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:05+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:33+0000\n" "Language-Team: Korean\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: ko\n" "X-Message-Group: out-statusnet\n" @@ -782,23 +782,28 @@ msgstr "올리기" msgid "Crop" msgstr "자르기" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "프로필을 지정하지 않았습니다." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "당신의 아바타가 될 이미지영역을 지정하세요." -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "파일 데이터를 잃어버렸습니다." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "아바타가 업데이트 되었습니다." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "아바타 업데이트 실패" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "아바타가 업데이트 되었습니다." @@ -941,7 +946,7 @@ msgid "Conversation" msgstr "인증 코드" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "통지" @@ -1807,7 +1812,7 @@ msgstr "%s 타임라인" msgid "Updates from members of %1$s on %2$s!" msgstr "%2$s에 있는 %1$s의 업데이트!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "그룹" @@ -3466,7 +3471,7 @@ msgid "Description" msgstr "설명" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "통계" @@ -3624,7 +3629,7 @@ msgid "Members" msgstr "회원" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(없습니다.)" @@ -3793,7 +3798,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4074,8 +4079,7 @@ msgstr "아바타 설정" msgid "You are not subscribed to that profile." msgstr "당신은 이 프로필에 구독되지 않고있습니다." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "구독을 저장할 수 없습니다." @@ -4652,39 +4656,39 @@ msgstr "통지를 저장하는데 문제가 발생했습니다." msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 #, fuzzy msgid "You have been banned from subscribing." msgstr "이 회원은 구독으로부터 당신을 차단해왔다." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "회원이 당신을 차단해왔습니다." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "구독하고 있지 않습니다!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "예약 구독을 삭제 할 수 없습니다." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "예약 구독을 삭제 할 수 없습니다." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "예약 구독을 삭제 할 수 없습니다." -#: classes/User.php:378 +#: classes/User.php:363 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "%2$s에서 %1$s까지 메시지" @@ -4990,22 +4994,22 @@ msgstr "뒷 페이지" msgid "Before" msgstr "앞 페이지" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 #, fuzzy @@ -5498,20 +5502,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "확인 코드가 없습니다." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 #, fuzzy msgid "Go to the installer." msgstr "이 사이트 로그인" @@ -5692,40 +5696,40 @@ msgstr "%s 그룹 게시글의 태그" msgid "This page is not available in a media type you accept" msgstr "이 페이지는 귀하가 승인한 미디어 타입에서는 이용할 수 없습니다." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "지원하지 않는 그림 파일 형식입니다." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "당신그룹의 로고 이미지를 업로드할 수 있습니다." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "불완전한 업로드." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "파일을 올리는데 시스템 오류 발생" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "그림 파일이 아니거나 손상된 파일 입니다." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "파일을 잃어버렸습니다." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "알 수 없는 종류의 파일입니다" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6187,7 +6191,7 @@ msgstr "%s의 게시글의 태그" msgid "Unknown" msgstr "알려지지 않은 행동" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "구독" @@ -6195,7 +6199,7 @@ msgstr "구독" msgid "All subscriptions" msgstr "모든 예약 구독" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "구독자" @@ -6203,16 +6207,21 @@ msgstr "구독자" msgid "All subscribers" msgstr "모든 구독자" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 #, fuzzy msgid "User ID" msgstr "이용자" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "가입한 때" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "모든 그룹" @@ -6394,6 +6403,11 @@ msgstr "이 사용자로부터 구독취소합니다." msgid "Unsubscribe" msgstr "구독 해제" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "이용자가 프로필을 가지고 있지 않습니다." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/mk/LC_MESSAGES/statusnet.po b/locale/mk/LC_MESSAGES/statusnet.po index 764a91b15..1be316859 100644 --- a/locale/mk/LC_MESSAGES/statusnet.po +++ b/locale/mk/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:08+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:37+0000\n" "Language-Team: Macedonian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: mk\n" "X-Message-Group: out-statusnet\n" @@ -774,23 +774,28 @@ msgstr "Подигни" msgid "Crop" msgstr "Отсечи" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Нема назначено профил." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Одберете квадратна површина од сликата за аватар" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Податоците за податотеката се изгубени." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Аватарот е подновен." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Подновата на аватарот не успеа." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Аватарот е избришан." @@ -929,7 +934,7 @@ msgid "Conversation" msgstr "Разговор" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Забелешки" @@ -1756,7 +1761,7 @@ msgstr "Историја на %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Подновувања од членови на %1$s на %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Групи" @@ -3423,7 +3428,7 @@ msgid "Description" msgstr "Опис" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Статистики" @@ -3592,7 +3597,7 @@ msgid "Members" msgstr "Членови" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Нема)" @@ -3773,7 +3778,8 @@ msgid "Unknown language \"%s\"." msgstr "Непознат јазик „%s“" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Минималното ограничување на текстот изнесува 140 знаци." #: actions/siteadminpanel.php:171 @@ -4049,8 +4055,7 @@ msgstr "Зачувај поставки за снимки" msgid "You are not subscribed to that profile." msgstr "Не сте претплатени на тој профил." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Не можев да ја зачувам претплатата." @@ -4634,36 +4639,36 @@ msgstr "Проблем при зачувувањето на групното п msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Блокирани сте од претплаќање." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Веќе претплатено!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Корисникот Ве има блокирано." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Не сте претплатени!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Не можам да ја избришам самопретплатата." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Не можете да го избришете OMB-жетонот за претплата." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Претплата не може да се избрише." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Добредојдовте на %1$s, @%2$s!" @@ -4951,22 +4956,22 @@ msgstr "По" msgid "Before" msgstr "Пред" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "Се очекува коренски каналски елемент, но добив цел XML документ." + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Сè уште не е поддржана обработката на далечинска содржина." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Сè уште не е поддржана обработката на XML содржина." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Сè уште не е достапна обработката на вметната Base64 содржина." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5478,19 +5483,19 @@ msgstr "" "tracks - сè уште не е имплементирано.\n" "tracking - сè уште не е имплементирано.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Нема пронајдено конфигурациска податотека. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Побарав конфигурациони податотеки на следниве места: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Препорачуваме да го пуштите инсталатерот за да го поправите ова." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Оди на инсталаторот." @@ -5668,40 +5673,40 @@ msgstr "Ознаки во забелешките на групата %s" msgid "This page is not available in a media type you accept" msgstr "Оваа страница не е достапна во форматот кој Вие го прифаќате." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Неподдржан фомрат на слики." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Ова е предолго. Максималната должина е 140 знаци." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Делумно подигање." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Системска грешка при подигањето на податотеката." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Не е слика или податотеката е пореметена." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Податотеката е изгубена." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Непознат тип на податотека" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "МБ" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "кб" @@ -6240,7 +6245,7 @@ msgstr "Ознаки во забелешките на %s" msgid "Unknown" msgstr "Непознато" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Претплати" @@ -6248,7 +6253,7 @@ msgstr "Претплати" msgid "All subscriptions" msgstr "Сите претплати" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Претплатници" @@ -6256,15 +6261,20 @@ msgstr "Претплатници" msgid "All subscribers" msgstr "Сите претплатници" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "Кориснички ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Член од" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Сите групи" @@ -6435,6 +6445,11 @@ msgstr "Откажи претплата од овој корсиник" msgid "Unsubscribe" msgstr "Откажи ја претплатата" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Корисникот нема профил." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Уреди аватар" @@ -6445,7 +6460,7 @@ msgstr "Кориснички дејства" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Бришењето на корисникот е во тек..." #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/nb/LC_MESSAGES/statusnet.po b/locale/nb/LC_MESSAGES/statusnet.po index 617280c33..63e45a273 100644 --- a/locale/nb/LC_MESSAGES/statusnet.po +++ b/locale/nb/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:11+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:40+0000\n" "Language-Team: Norwegian (bokmål)‬\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: no\n" "X-Message-Group: out-statusnet\n" @@ -763,23 +763,28 @@ msgstr "Last opp" msgid "Crop" msgstr "Beskjær" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Ingen profil oppgitt." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Velg et kvadratisk utsnitt av bildet som din avatar." -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Mistet våre fildata." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Brukerbildet har blitt oppdatert." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Oppdatering av avatar mislyktes." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar slettet." @@ -917,7 +922,7 @@ msgid "Conversation" msgstr "Samtale" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Notiser" @@ -1727,7 +1732,7 @@ msgstr "%s tidslinje" msgid "Updates from members of %1$s on %2$s!" msgstr "Oppdateringer fra medlemmer av %1$s på %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grupper" @@ -3326,7 +3331,7 @@ msgid "Description" msgstr "Beskrivelse" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistikk" @@ -3484,7 +3489,7 @@ msgid "Members" msgstr "Medlemmer" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Ingen)" @@ -3665,7 +3670,7 @@ msgid "Unknown language \"%s\"." msgstr "Ukjent språk «%s»." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -3936,8 +3941,7 @@ msgstr "Innstillinger for IM" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "Klarte ikke å lagre avatar-informasjonen" @@ -4486,38 +4490,38 @@ msgstr "" msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Bruker har blokkert deg." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Alle abonnementer" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Klarte ikke å lagre avatar-informasjonen" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Klarte ikke å lagre avatar-informasjonen" -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Velkommen til %1$s, @%2$s." @@ -4800,22 +4804,22 @@ msgstr "Etter" msgid "Before" msgstr "Før" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5290,20 +5294,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Fant ikke bekreftelseskode." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5483,40 +5487,40 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "Denne siden er ikke tilgjengelig i en mediatype du aksepterer" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Bildefilformatet støttes ikke." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Filen er for stor. Maks filstørrelse er %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Delvis opplasting." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Systemfeil ved opplasting av fil." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Ikke et bilde eller en korrupt fil." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Mistet filen vår." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Ukjent filtype" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6046,7 +6050,7 @@ msgstr "" msgid "Unknown" msgstr "Ukjent" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Abonnement" @@ -6054,7 +6058,7 @@ msgstr "Abonnement" msgid "All subscriptions" msgstr "Alle abonnementer" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Abonnenter" @@ -6062,15 +6066,20 @@ msgstr "Abonnenter" msgid "All subscribers" msgstr "Alle abonnenter" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "Bruker-ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Medlem siden" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Alle grupper" @@ -6246,6 +6255,11 @@ msgstr "" msgid "Unsubscribe" msgstr "" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Brukeren har ingen profil." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/nl/LC_MESSAGES/statusnet.po b/locale/nl/LC_MESSAGES/statusnet.po index 745e666c2..6d3148c18 100644 --- a/locale/nl/LC_MESSAGES/statusnet.po +++ b/locale/nl/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:17+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:46+0000\n" "Language-Team: Dutch\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: nl\n" "X-Message-Group: out-statusnet\n" @@ -783,24 +783,29 @@ msgstr "Uploaden" msgid "Crop" msgstr "Uitsnijden" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Er is geen profiel opgegeven." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" "Selecteer een vierkant in de afbeelding om deze als uw avatar in te stellen" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Ons bestand is verloren gegaan." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "De avatar is bijgewerkt." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Het bijwerken van de avatar is mislukt." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "De avatar is verwijderd." @@ -938,7 +943,7 @@ msgid "Conversation" msgstr "Dialoog" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Mededelingen" @@ -1770,7 +1775,7 @@ msgstr "%s tijdlijn" msgid "Updates from members of %1$s on %2$s!" msgstr "Updates voor leden van %1$s op %2$s." -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Groepen" @@ -3444,7 +3449,7 @@ msgid "Description" msgstr "Beschrijving" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistieken" @@ -3613,7 +3618,7 @@ msgid "Members" msgstr "Leden" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(geen)" @@ -3796,7 +3801,8 @@ msgid "Unknown language \"%s\"." msgstr "De taal \"%s\" is niet bekend." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "De minimale tekstlimiet is 140 tekens." #: actions/siteadminpanel.php:171 @@ -4075,8 +4081,7 @@ msgstr "Snapshotinstellingen opslaan" msgid "You are not subscribed to that profile." msgstr "U bent niet geabonneerd op dat profiel." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Het was niet mogelijk het abonnement op te slaan." @@ -4672,36 +4677,36 @@ msgstr "" msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "U mag zich niet abonneren." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "U bent al gebonneerd!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Deze gebruiker negeert u." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Niet geabonneerd!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Het was niet mogelijk het abonnement op uzelf te verwijderen." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "" "Het was niet mogelijk om het OMB-token voor het abonnement te verwijderen." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Kon abonnement niet verwijderen." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Welkom bij %1$s, @%2$s!" @@ -4989,22 +4994,22 @@ msgstr "Later" msgid "Before" msgstr "Eerder" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "Verwachtte een root-feed element maar kreeg een heel XML-document." + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Het is nog niet mogelijk inhoud uit andere omgevingen te verwerken." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Het is nog niet mogelijk ingebedde XML-inhoud te verwerken" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Het is nog niet mogelijk ingebedde Base64-inhoud te verwerken" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5524,20 +5529,20 @@ msgstr "" "tracks - nog niet beschikbaar\n" "tracking - nog niet beschikbaar\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Er is geen instellingenbestand aangetroffen. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Er is gezocht naar instellingenbestanden op de volgende plaatsen: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" "U kunt proberen de installer uit te voeren om dit probleem op te lossen." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Naar het installatieprogramma gaan." @@ -5715,40 +5720,40 @@ msgstr "Labels in de groepsmededelingen van %s" msgid "This page is not available in a media type you accept" msgstr "Deze pagina is niet beschikbaar in een mediatype dat u accepteert" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Niet ondersteund beeldbestandsformaat." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Dat bestand is te groot. De maximale bestandsgrootte is %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Gedeeltelijke upload." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Er is een systeemfout opgetreden tijdens het uploaden van het bestand." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Het bestand is geen afbeelding of het bestand is beschadigd." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Het bestand is zoekgeraakt." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Onbekend bestandstype" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6287,7 +6292,7 @@ msgstr "Labels in de mededelingen van %s" msgid "Unknown" msgstr "Onbekend" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Abonnementen" @@ -6295,7 +6300,7 @@ msgstr "Abonnementen" msgid "All subscriptions" msgstr "Alle abonnementen" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Abonnees" @@ -6303,15 +6308,20 @@ msgstr "Abonnees" msgid "All subscribers" msgstr "Alle abonnees" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "Gebruikers-ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Lid sinds" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Alle groepen" @@ -6482,6 +6492,11 @@ msgstr "Uitschrijven van deze gebruiker" msgid "Unsubscribe" msgstr "Abonnement opheffen" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Deze gebruiker heeft geen profiel." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Avatar bewerken" @@ -6492,7 +6507,7 @@ msgstr "Gebruikershandelingen" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Bezig met het verwijderen van de gebruiker..." #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/nn/LC_MESSAGES/statusnet.po b/locale/nn/LC_MESSAGES/statusnet.po index 4b1110eae..30f1adc0f 100644 --- a/locale/nn/LC_MESSAGES/statusnet.po +++ b/locale/nn/LC_MESSAGES/statusnet.po @@ -7,12 +7,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:14+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:43+0000\n" "Language-Team: Norwegian Nynorsk\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: nn\n" "X-Message-Group: out-statusnet\n" @@ -780,23 +780,28 @@ msgstr "Last opp" msgid "Crop" msgstr "Skaler" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Ingen vald profil." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Velg eit utvalg av bildet som vil blir din avatar." -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Fant ikkje igjen fil data." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Lasta opp brukarbilete." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Feil ved oppdatering av brukarbilete." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "Lasta opp brukarbilete." @@ -939,7 +944,7 @@ msgid "Conversation" msgstr "Stadfestingskode" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Notisar" @@ -1807,7 +1812,7 @@ msgstr "%s tidsline" msgid "Updates from members of %1$s on %2$s!" msgstr "Oppdateringar frå %1$s på %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grupper" @@ -3479,7 +3484,7 @@ msgid "Description" msgstr "Beskriving" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistikk" @@ -3637,7 +3642,7 @@ msgid "Members" msgstr "Medlemmar" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Ingen)" @@ -3806,7 +3811,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4088,8 +4093,7 @@ msgstr "Avatar-innstillingar" msgid "You are not subscribed to that profile." msgstr "Du tingar ikkje oppdateringar til den profilen." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Kunne ikkje lagra abonnement." @@ -4669,39 +4673,39 @@ msgstr "Eit problem oppstod ved lagring av notis." msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 #, fuzzy msgid "You have been banned from subscribing." msgstr "Brukaren tillet deg ikkje å tinga meldingane sine." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Brukar har blokkert deg." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Ikkje tinga." -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Kan ikkje sletta tinging." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Kan ikkje sletta tinging." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Kan ikkje sletta tinging." -#: classes/User.php:378 +#: classes/User.php:363 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Melding til %1$s på %2$s" @@ -5007,22 +5011,22 @@ msgstr "« Etter" msgid "Before" msgstr "Før »" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 #, fuzzy @@ -5518,20 +5522,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Ingen stadfestingskode." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 #, fuzzy msgid "Go to the installer." msgstr "Logg inn or sida" @@ -5712,40 +5716,40 @@ msgstr "Merkelappar i %s gruppa sine notisar" msgid "This page is not available in a media type you accept" msgstr "Denne sida er ikkje tilgjengeleg i nokon mediatype du aksepterer." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Støttar ikkje bileteformatet." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Du kan lasta opp ein logo for gruppa." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Hallvegs opplasta." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Systemfeil ved opplasting av fil." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Korrupt bilete." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Mista fila vår." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Ukjend fil type" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6214,7 +6218,7 @@ msgstr "Merkelappar i %s sine notisar" msgid "Unknown" msgstr "Uventa handling." -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Tingingar" @@ -6222,7 +6226,7 @@ msgstr "Tingingar" msgid "All subscriptions" msgstr "Alle tingingar" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Tingarar" @@ -6230,16 +6234,21 @@ msgstr "Tingarar" msgid "All subscribers" msgstr "Tingarar" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 #, fuzzy msgid "User ID" msgstr "Brukar" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Medlem sidan" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Alle gruppar" @@ -6421,6 +6430,11 @@ msgstr "Fjern tinging fra denne brukaren" msgid "Unsubscribe" msgstr "Fjern tinging" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Brukaren har inga profil." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/pl/LC_MESSAGES/statusnet.po b/locale/pl/LC_MESSAGES/statusnet.po index 816eb6e85..e2656b003 100644 --- a/locale/pl/LC_MESSAGES/statusnet.po +++ b/locale/pl/LC_MESSAGES/statusnet.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:20+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:49+0000\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" @@ -19,7 +19,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: pl\n" "X-Message-Group: out-statusnet\n" @@ -770,23 +770,28 @@ msgstr "Wyślij" msgid "Crop" msgstr "Przytnij" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Nie podano profilu." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Wybierz kwadratowy obszar obrazu do awatara" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Utracono dane pliku." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Zaktualizowano awatar." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Zaktualizowanie awatara nie powiodło się." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Usunięto awatar." @@ -924,7 +929,7 @@ msgid "Conversation" msgstr "Rozmowa" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Wpisy" @@ -1740,7 +1745,7 @@ msgstr "Oś czasu użytkownika %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Aktualizacje od członków %1$s na %2$s." -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grupy" @@ -3396,7 +3401,7 @@ msgid "Description" msgstr "Opis" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statystyki" @@ -3563,7 +3568,7 @@ msgid "Members" msgstr "Członkowie" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Brak)" @@ -3745,7 +3750,8 @@ msgid "Unknown language \"%s\"." msgstr "Nieznany język \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Maksymalne ograniczenie tekstu to 14 znaków." #: actions/siteadminpanel.php:171 @@ -4018,8 +4024,7 @@ msgstr "Zapisz ustawienia migawki" msgid "You are not subscribed to that profile." msgstr "Nie jesteś subskrybowany do tego profilu." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Nie można zapisać subskrypcji." @@ -4605,35 +4610,35 @@ msgstr "Problem podczas zapisywania skrzynki odbiorczej grupy." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Zablokowano subskrybowanie." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Już subskrybowane." -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Użytkownik zablokował cię." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Niesubskrybowane." -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Nie można usunąć autosubskrypcji." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Nie można usunąć tokenu subskrypcji OMB." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Nie można usunąć subskrypcji." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Witaj w %1$s, @%2$s." @@ -4921,22 +4926,22 @@ msgstr "Później" msgid "Before" msgstr "Wcześniej" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "Oczekiwano elementu kanału roota, ale otrzymano cały dokument XML." + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Nie można jeszcze obsługiwać zdalnej treści." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Nie można jeszcze obsługiwać zagnieżdżonej treści XML." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Nie można jeszcze obsługiwać zagnieżdżonej treści Base64." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5455,19 +5460,19 @@ msgstr "" "tracks - jeszcze nie zaimplementowano\n" "tracking - jeszcze nie zaimplementowano\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Nie odnaleziono pliku konfiguracji." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Szukano plików konfiguracji w następujących miejscach: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Należy uruchomić instalator, aby to naprawić." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Przejdź do instalatora." @@ -5645,40 +5650,40 @@ msgstr "Znaczniki we wpisach grupy %s" msgid "This page is not available in a media type you accept" msgstr "Ta strona jest niedostępna dla akceptowanego typu medium" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Nieobsługiwany format pliku obrazu." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Ten plik jest za duży. Maksymalny rozmiar pliku to %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Częściowo wysłano." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Błąd systemu podczas wysyłania pliku." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "To nie jest obraz lub lub plik jest uszkodzony." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Utracono plik." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Nieznany typ pliku" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "KB" @@ -6211,7 +6216,7 @@ msgstr "Znaczniki we wpisach użytkownika %s" msgid "Unknown" msgstr "Nieznane" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Subskrypcje" @@ -6219,7 +6224,7 @@ msgstr "Subskrypcje" msgid "All subscriptions" msgstr "Wszystkie subskrypcje" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Subskrybenci" @@ -6227,15 +6232,20 @@ msgstr "Subskrybenci" msgid "All subscribers" msgstr "Wszyscy subskrybenci" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "Identyfikator użytkownika" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Członek od" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Wszystkie grupy" @@ -6407,6 +6417,11 @@ msgstr "Zrezygnuj z subskrypcji tego użytkownika" msgid "Unsubscribe" msgstr "Zrezygnuj z subskrypcji" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Użytkownik nie posiada profilu." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Zmodyfikuj awatar" @@ -6417,7 +6432,7 @@ msgstr "Czynności użytkownika" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Trwa usuwanie użytkownika..." #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/pt/LC_MESSAGES/statusnet.po b/locale/pt/LC_MESSAGES/statusnet.po index 4d94d95b0..4d1a30ea4 100644 --- a/locale/pt/LC_MESSAGES/statusnet.po +++ b/locale/pt/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:23+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:52+0000\n" "Language-Team: Portuguese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: pt\n" "X-Message-Group: out-statusnet\n" @@ -770,23 +770,28 @@ msgstr "Carregar" msgid "Crop" msgstr "Cortar" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Não foi especificado um perfil." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Escolha uma área quadrada da imagem para ser o seu avatar" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Perdi os dados do nosso ficheiro." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar actualizado." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Falha ao actualizar avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar apagado." @@ -925,7 +930,7 @@ msgid "Conversation" msgstr "Conversação" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Notas" @@ -1772,7 +1777,7 @@ msgstr "Notas de %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Actualizações dos membros de %1$s em %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grupos" @@ -3450,7 +3455,7 @@ msgid "Description" msgstr "Descrição" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Estatísticas" @@ -3617,7 +3622,7 @@ msgid "Members" msgstr "Membros" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Nenhum)" @@ -3799,7 +3804,8 @@ msgid "Unknown language \"%s\"." msgstr "Língua desconhecida \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "O valor mínimo de limite para o texto é 140 caracteres." #: actions/siteadminpanel.php:171 @@ -4078,8 +4084,7 @@ msgstr "Gravar configurações do site" msgid "You are not subscribed to that profile." msgstr "Não subscreveu esse perfil." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Não foi possível gravar a subscrição." @@ -4668,36 +4673,36 @@ msgstr "Problema na gravação da nota." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Foi bloqueado de fazer subscrições" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Já subscrito!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "O utilizador bloqueou-o." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Não subscrito!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Não foi possível apagar a auto-subscrição." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Não foi possível apagar a subscrição." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Não foi possível apagar a subscrição." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "%1$s dá-lhe as boas-vindas, @%2$s!" @@ -5000,22 +5005,22 @@ msgstr "Posteriores" msgid "Before" msgstr "Anteriores" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5535,19 +5540,19 @@ msgstr "" "tracks - ainda não implementado.\n" "tracking - ainda não implementado.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Ficheiro de configuração não encontrado. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Procurei ficheiros de configuração nos seguintes sítios: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Talvez queira correr o instalador para resolver esta questão." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Ir para o instalador." @@ -5725,40 +5730,40 @@ msgstr "Categorias nas notas do grupo %s" msgid "This page is not available in a media type you accept" msgstr "Esta página não está disponível num formato que você aceite" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Formato do ficheiro da imagem não é suportado." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Esse ficheiro é demasiado grande. O tamanho máximo de ficheiro é %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Transferência parcial." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Ocorreu um erro de sistema ao transferir o ficheiro." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Ficheiro não é uma imagem ou está corrompido." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Perdi o nosso ficheiro." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Tipo do ficheiro é desconhecido" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6293,7 +6298,7 @@ msgstr "Categorias nas notas de %s" msgid "Unknown" msgstr "Desconhecida" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Subscrições" @@ -6301,7 +6306,7 @@ msgstr "Subscrições" msgid "All subscriptions" msgstr "Todas as subscrições" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Subscritores" @@ -6309,15 +6314,20 @@ msgstr "Subscritores" msgid "All subscribers" msgstr "Todos os subscritores" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID do utilizador" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Membro desde" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Todos os grupos" @@ -6488,6 +6498,11 @@ msgstr "Deixar de subscrever este utilizador" msgid "Unsubscribe" msgstr "Abandonar" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Utilizador não tem perfil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Editar Avatar" diff --git a/locale/pt_BR/LC_MESSAGES/statusnet.po b/locale/pt_BR/LC_MESSAGES/statusnet.po index a431c99b8..78c07d4b8 100644 --- a/locale/pt_BR/LC_MESSAGES/statusnet.po +++ b/locale/pt_BR/LC_MESSAGES/statusnet.po @@ -12,12 +12,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:27+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:55+0000\n" "Language-Team: Brazilian Portuguese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: pt-br\n" "X-Message-Group: out-statusnet\n" @@ -46,10 +46,9 @@ msgstr "Impedir usuários anônimos (não autenticados) de visualizar o site?" #. TRANS: Checkbox label for prohibiting anonymous users from viewing site. #: actions/accessadminpanel.php:167 -#, fuzzy msgctxt "LABEL" msgid "Private" -msgstr "Particular" +msgstr "Privado" #. TRANS: Checkbox instructions for admin setting "Invite only" #: actions/accessadminpanel.php:174 @@ -627,7 +626,7 @@ msgstr "Essa mensagem não existe." #: actions/apistatusesretweet.php:83 msgid "Cannot repeat your own notice." -msgstr "Você não pode repetria sua própria mensagem." +msgstr "Você não pode repetir a sua própria mensagem." #: actions/apistatusesretweet.php:91 msgid "Already repeated that notice." @@ -778,23 +777,28 @@ msgstr "Enviar" msgid "Crop" msgstr "Cortar" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Não foi especificado nenhum perfil." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Selecione uma área quadrada da imagem para ser seu avatar" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Os dados do nosso arquivo foram perdidos." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "O avatar foi atualizado." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Não foi possível atualizar o avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "O avatar foi excluído." @@ -933,7 +937,7 @@ msgid "Conversation" msgstr "Conversa" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Mensagens" @@ -1587,23 +1591,20 @@ msgid "Cannot read file." msgstr "Não foi possível ler o arquivo." #: actions/grantrole.php:62 actions/revokerole.php:62 -#, fuzzy msgid "Invalid role." -msgstr "Token inválido." +msgstr "Papel inválido." #: actions/grantrole.php:66 actions/revokerole.php:66 msgid "This role is reserved and cannot be set." -msgstr "" +msgstr "Este papel está reservado e não pode ser definido." #: actions/grantrole.php:75 -#, fuzzy msgid "You cannot grant user roles on this site." -msgstr "Você não pode colocar usuários deste site em isolamento." +msgstr "Você não pode definir papéis para os usuários neste site." #: actions/grantrole.php:82 -#, fuzzy msgid "User already has this role." -msgstr "O usuário já está silenciado." +msgstr "O usuário já possui este papel." #: actions/groupblock.php:71 actions/groupunblock.php:71 #: actions/makeadmin.php:71 actions/subedit.php:46 @@ -1764,7 +1765,7 @@ msgstr "Mensagens de %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Atualizações dos membros de %1$s no %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grupos" @@ -2098,9 +2099,8 @@ msgid "You must be logged in to join a group." msgstr "Você deve estar autenticado para se associar a um grupo." #: actions/joingroup.php:88 actions/leavegroup.php:88 -#, fuzzy msgid "No nickname or ID." -msgstr "Nenhuma identificação." +msgstr "Nenhum apelido ou identificação." #: actions/joingroup.php:141 #, php-format @@ -3358,14 +3358,12 @@ msgid "Replies to %1$s on %2$s!" msgstr "Respostas para %1$s no %2$s" #: actions/revokerole.php:75 -#, fuzzy msgid "You cannot revoke user roles on this site." -msgstr "Você não pode silenciar os usuários neste site." +msgstr "Não é possível revogar os papéis dos usuários neste site." #: actions/revokerole.php:82 -#, fuzzy msgid "User doesn't have this role." -msgstr "Usuário sem um perfil correspondente" +msgstr "O usuário não possui este papel." #: actions/rsd.php:146 actions/version.php:157 msgid "StatusNet" @@ -3395,7 +3393,7 @@ msgstr "Gerenciar sessões" #: actions/sessionsadminpanel.php:177 msgid "Whether to handle sessions ourselves." -msgstr "Define se nós cuidamos do gerenciamento das sessões." +msgstr "Define se as sessões terão gerenciamento próprio." #: actions/sessionsadminpanel.php:181 msgid "Session debugging" @@ -3437,7 +3435,7 @@ msgid "Description" msgstr "Descrição" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Estatísticas" @@ -3604,7 +3602,7 @@ msgid "Members" msgstr "Membros" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Nenhum)" @@ -3770,7 +3768,6 @@ msgid "User is already silenced." msgstr "O usuário já está silenciado." #: actions/siteadminpanel.php:69 -#, fuzzy msgid "Basic settings for this StatusNet site" msgstr "Configurações básicas para esta instância do StatusNet." @@ -3788,7 +3785,8 @@ msgid "Unknown language \"%s\"." msgstr "Idioma \"%s\" desconhecido." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "O comprimento máximo do texto é de 140 caracteres." #: actions/siteadminpanel.php:171 @@ -3846,6 +3844,8 @@ msgstr "Idioma padrão" #: actions/siteadminpanel.php:263 msgid "Site language when autodetection from browser settings is not available" msgstr "" +"Idioma do site quando as configurações de autodetecção a partir do navegador " +"não estiverem disponíveis" #: actions/siteadminpanel.php:271 msgid "Limits" @@ -3870,37 +3870,32 @@ msgstr "" "coisa novamente." #: actions/sitenoticeadminpanel.php:56 -#, fuzzy msgid "Site Notice" -msgstr "Mensagem do site" +msgstr "Avisos do site" #: actions/sitenoticeadminpanel.php:67 -#, fuzzy msgid "Edit site-wide message" -msgstr "Nova mensagem" +msgstr "Editar os avisos do site (exibidos em todas as páginas)" #: actions/sitenoticeadminpanel.php:103 -#, fuzzy msgid "Unable to save site notice." -msgstr "Não foi possível salvar suas configurações de aparência." +msgstr "Não foi possível salvar os avisos do site." #: actions/sitenoticeadminpanel.php:113 msgid "Max length for the site-wide notice is 255 chars" -msgstr "" +msgstr "O tamanho máximo para os avisos é de 255 caracteres." #: actions/sitenoticeadminpanel.php:176 -#, fuzzy msgid "Site notice text" -msgstr "Mensagem do site" +msgstr "Texto dos avisos" #: actions/sitenoticeadminpanel.php:178 msgid "Site-wide notice text (255 chars max; HTML okay)" -msgstr "" +msgstr "Texto dos avisos do site (no máximo 255 caracteres; pode usar HTML)" #: actions/sitenoticeadminpanel.php:198 -#, fuzzy msgid "Save site notice" -msgstr "Mensagem do site" +msgstr "Salvar os avisos do site" #: actions/smssettings.php:58 msgid "SMS settings" @@ -4007,9 +4002,8 @@ msgid "Snapshots" msgstr "Estatísticas" #: actions/snapshotadminpanel.php:65 -#, fuzzy msgid "Manage snapshot configuration" -msgstr "Mude as configurações do site" +msgstr "Gerenciar as configurações das estatísticas" #: actions/snapshotadminpanel.php:127 msgid "Invalid snapshot run value." @@ -4056,32 +4050,28 @@ msgid "Snapshots will be sent to this URL" msgstr "As estatísticas serão enviadas para esta URL" #: actions/snapshotadminpanel.php:248 -#, fuzzy msgid "Save snapshot settings" -msgstr "Salvar as configurações do site" +msgstr "Salvar as configurações de estatísticas" #: actions/subedit.php:70 msgid "You are not subscribed to that profile." msgstr "Você não está assinando esse perfil." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Não foi possível salvar a assinatura." #: actions/subscribe.php:77 msgid "This action only accepts POST requests." -msgstr "" +msgstr "Esta ação aceita somente requisições POST." #: actions/subscribe.php:107 -#, fuzzy msgid "No such profile." -msgstr "Esse arquivo não existe." +msgstr "Este perfil não existe." #: actions/subscribe.php:117 -#, fuzzy msgid "You cannot subscribe to an OMB 0.1 remote profile with this action." -msgstr "Você não está assinando esse perfil." +msgstr "Não é possível assinar um perfil OMB 0.1 remoto com essa ação." #: actions/subscribe.php:145 msgid "Subscribed" @@ -4586,9 +4576,8 @@ msgid "Group leave failed." msgstr "Não foi possível deixar o grupo." #: classes/Local_group.php:41 -#, fuzzy msgid "Could not update local group." -msgstr "Não foi possível atualizar o grupo." +msgstr "Não foi possível atualizar o grupo local." #: classes/Login_token.php:76 #, php-format @@ -4652,36 +4641,35 @@ msgstr "Problema no salvamento das mensagens recebidas do grupo." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Você está proibido de assinar." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Já assinado!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "O usuário bloqueou você." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Não assinado!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Não foi possível excluir a auto-assinatura." -#: classes/Subscription.php:190 -#, fuzzy +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." -msgstr "Não foi possível excluir a assinatura." +msgstr "Não foi possível excluir o token de assinatura OMB." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Não foi possível excluir a assinatura." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Bem vindo(a) a %1$s, @%2$s!" @@ -4691,18 +4679,16 @@ msgid "Could not create group." msgstr "Não foi possível criar o grupo." #: classes/User_group.php:489 -#, fuzzy msgid "Could not set group URI." -msgstr "Não foi possível configurar a associação ao grupo." +msgstr "Não foi possível definir a URI do grupo." #: classes/User_group.php:510 msgid "Could not set group membership." msgstr "Não foi possível configurar a associação ao grupo." #: classes/User_group.php:524 -#, fuzzy msgid "Could not save local group info." -msgstr "Não foi possível salvar a assinatura." +msgstr "Não foi possível salvar a informação do grupo local." #: lib/accountsettingsaction.php:108 msgid "Change your profile settings" @@ -4747,27 +4733,23 @@ msgstr "Navegação primária no site" #. TRANS: Tooltip for main menu option "Personal" #: lib/action.php:430 -#, fuzzy msgctxt "TOOLTIP" msgid "Personal profile and friends timeline" msgstr "Perfil pessoal e fluxo de mensagens dos amigos" #: lib/action.php:433 -#, fuzzy msgctxt "MENU" msgid "Personal" msgstr "Pessoal" #. TRANS: Tooltip for main menu option "Account" #: lib/action.php:435 -#, fuzzy msgctxt "TOOLTIP" msgid "Change your email, avatar, password, profile" -msgstr "Mude seu e-mail, avatar, senha, perfil" +msgstr "Altere seu e-mail, avatar, senha, perfil" #. TRANS: Tooltip for main menu option "Services" #: lib/action.php:440 -#, fuzzy msgctxt "TOOLTIP" msgid "Connect to services" msgstr "Conecte-se a outros serviços" @@ -4778,16 +4760,14 @@ msgstr "Conectar" #. TRANS: Tooltip for menu option "Admin" #: lib/action.php:446 -#, fuzzy msgctxt "TOOLTIP" msgid "Change site configuration" -msgstr "Mude as configurações do site" +msgstr "Altere as configurações do site" #: lib/action.php:449 -#, fuzzy msgctxt "MENU" msgid "Admin" -msgstr "Admin" +msgstr "Administrar" #. TRANS: Tooltip for main menu option "Invite" #: lib/action.php:453 @@ -4979,22 +4959,22 @@ msgstr "Próximo" msgid "Before" msgstr "Anterior" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5214,9 +5194,9 @@ msgid "Could not find a user with nickname %s" msgstr "Não foi possível encontrar um usuário com a identificação %s" #: lib/command.php:143 -#, fuzzy, php-format +#, php-format msgid "Could not find a local user with nickname %s" -msgstr "Não foi possível encontrar um usuário com a identificação %s" +msgstr "Não foi possível encontrar um usuário local com a identificação %s" #: lib/command.php:176 msgid "Sorry, this command is not yet implemented." @@ -5296,6 +5276,8 @@ msgid "" "%s is a remote profile; you can only send direct messages to users on the " "same server." msgstr "" +"%s é um perfil remoto; você pode só pode enviar mensagens diretas para " +"usuários do mesmo servidor." #: lib/command.php:450 #, php-format @@ -5349,9 +5331,8 @@ msgid "Specify the name of the user to subscribe to" msgstr "Especifique o nome do usuário que será assinado" #: lib/command.php:602 -#, fuzzy msgid "Can't subscribe to OMB profiles by command." -msgstr "Você não está assinando esse perfil." +msgstr "Não é possível assinar perfis OMB com comandos." #: lib/command.php:608 #, php-format @@ -5399,7 +5380,7 @@ msgstr "" "s" #: lib/command.php:735 -#, fuzzy, php-format +#, php-format msgid "Unsubscribed %s" msgstr "Cancelada a assinatura de %s" @@ -5434,7 +5415,6 @@ msgstr[0] "Você é membro deste grupo:" msgstr[1] "Você é membro destes grupos:" #: lib/command.php:812 -#, fuzzy msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5485,8 +5465,9 @@ msgstr "" "subscribers - lista as pessoas que seguem você\n" "leave - deixa de assinar o usuário\n" "d - mensagem direta para o usuário\n" -"get - obtém a última mensagem do usuário\n" -"whois - obtém as informações do perfil do usuário\n" +"get - obtém a última mensagem do usuário\n" +"whois - obtém as informações do perfil do usuário\n" +"lose - obriga o usuário a deixar de segui-lo\n" "fav - adiciona a último mensagem do usuário como uma " "'favorita'\n" "fav # - adiciona a mensagem identificada como 'favorita'\n" @@ -5514,19 +5495,19 @@ msgstr "" "tracks - não implementado ainda\n" "tracking - não implementado ainda\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Não foi encontrado nenhum arquivo de configuração. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Eu procurei pelos arquivos de configuração nos seguintes lugares: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Você pode querer executar o instalador para corrigir isto." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Ir para o instalador." @@ -5627,7 +5608,7 @@ msgstr "Ir" #: lib/grantroleform.php:91 #, php-format msgid "Grant this user the \"%s\" role" -msgstr "" +msgstr "Associa o papel \"%s\" a este usuário" #: lib/groupeditform.php:163 msgid "URL of the homepage or blog of the group or topic" @@ -5704,40 +5685,40 @@ msgstr "Etiquetas nas mensagens do grupo %s" msgid "This page is not available in a media type you accept" msgstr "Esta página não está disponível em um tipo de mídia que você aceita" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Formato de imagem não suportado." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "O arquivo é muito grande. O tamanho máximo é de %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Envio parcial." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Erro no sistema durante o envio do arquivo." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Imagem inválida ou arquivo corrompido." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Nosso arquivo foi perdido." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Tipo de arquivo desconhecido" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "Mb" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "Kb" @@ -6273,7 +6254,7 @@ msgstr "Etiquetas nas mensagens de %s" msgid "Unknown" msgstr "Desconhecido" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Assinaturas" @@ -6281,7 +6262,7 @@ msgstr "Assinaturas" msgid "All subscriptions" msgstr "Todas as assinaturas" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Assinantes" @@ -6289,15 +6270,20 @@ msgstr "Assinantes" msgid "All subscribers" msgstr "Todos os assinantes" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID do usuário" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Membro desde" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Todos os grupos" @@ -6338,9 +6324,9 @@ msgid "Repeat this notice" msgstr "Repetir esta mensagem" #: lib/revokeroleform.php:91 -#, fuzzy, php-format +#, php-format msgid "Revoke the \"%s\" role from this user" -msgstr "Bloquear este usuário neste grupo" +msgstr "Revoga o papel \"%s\" deste usuário" #: lib/router.php:677 msgid "No single user defined for single-user mode." @@ -6468,6 +6454,11 @@ msgstr "Cancelar a assinatura deste usuário" msgid "Unsubscribe" msgstr "Cancelar" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "O usuário não tem perfil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Editar o avatar" @@ -6478,7 +6469,7 @@ msgstr "Ações do usuário" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Exclusão do usuário em andamento..." #: lib/userprofile.php:263 msgid "Edit profile settings" @@ -6501,9 +6492,8 @@ msgid "Moderate" msgstr "Moderar" #: lib/userprofile.php:364 -#, fuzzy msgid "User role" -msgstr "Perfil do usuário" +msgstr "Papel do usuário" #: lib/userprofile.php:366 msgctxt "role" @@ -6511,10 +6501,9 @@ msgid "Administrator" msgstr "Administrador" #: lib/userprofile.php:367 -#, fuzzy msgctxt "role" msgid "Moderator" -msgstr "Moderar" +msgstr "Moderador" #: lib/util.php:1046 msgid "a few seconds ago" diff --git a/locale/ru/LC_MESSAGES/statusnet.po b/locale/ru/LC_MESSAGES/statusnet.po index b436d9f1e..472b3cbbe 100644 --- a/locale/ru/LC_MESSAGES/statusnet.po +++ b/locale/ru/LC_MESSAGES/statusnet.po @@ -12,12 +12,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:30+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:10:59+0000\n" "Language-Team: Russian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: ru\n" "X-Message-Group: out-statusnet\n" @@ -774,23 +774,28 @@ msgstr "Загрузить" msgid "Crop" msgstr "Обрезать" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Профиль не определен." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Подберите нужный квадратный участок для вашей аватары" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Потеряна информация о файле." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Аватара обновлена." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Неудача при обновлении аватары." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Аватара удалена." @@ -928,7 +933,7 @@ msgid "Conversation" msgstr "Дискуссия" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Записи" @@ -1760,7 +1765,7 @@ msgstr "Лента %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Обновления участников %1$s на %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Группы" @@ -3414,7 +3419,7 @@ msgid "Description" msgstr "Описание" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Статистика" @@ -3581,7 +3586,7 @@ msgid "Members" msgstr "Участники" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(пока ничего нет)" @@ -3765,7 +3770,8 @@ msgid "Unknown language \"%s\"." msgstr "Неизвестный язык «%s»." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Минимальное ограничение текста составляет 140 символов." #: actions/siteadminpanel.php:171 @@ -4039,8 +4045,7 @@ msgstr "Сохранить настройки снимка" msgid "You are not subscribed to that profile." msgstr "Вы не подписаны на этот профиль." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Не удаётся сохранить подписку." @@ -4623,35 +4628,35 @@ msgstr "Проблемы с сохранением входящих сообще msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Вы заблокированы от подписки." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Уже подписаны!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Пользователь заблокировал Вас." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Не подписаны!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Невозможно удалить самоподписку." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Не удаётся удалить подписочный жетон OMB." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Не удаётся удалить подписку." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Добро пожаловать на %1$s, @%2$s!" @@ -4939,22 +4944,22 @@ msgstr "Сюда" msgid "Before" msgstr "Туда" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "Ожидался корневой элемент потока, а получен XML-документ целиком." + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Пока ещё нельзя обрабатывать удалённое содержимое." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Пока ещё нельзя обрабатывать встроенный XML." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Пока ещё нельзя обрабатывать встроенное содержание Base64." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5469,19 +5474,19 @@ msgstr "" "tracks — пока не реализовано.\n" "tracking — пока не реализовано.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Конфигурационный файл не найден. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Конфигурационные файлы искались в следующих местах: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Возможно, вы решите запустить установщик для исправления этого." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Перейти к установщику" @@ -5659,40 +5664,40 @@ msgstr "Теги записей группы %s" msgid "This page is not available in a media type you accept" msgstr "Страница недоступна для того типа, который Вы задействовали." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Неподдерживаемый формат файла изображения." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Этот файл слишком большой. Максимальный размер файла составляет %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Частичная загрузка." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Системная ошибка при загрузке файла." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Не является изображением или повреждённый файл." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Потерян файл." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Неподдерживаемый тип файла" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "МБ" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "КБ" @@ -6226,7 +6231,7 @@ msgstr "Теги записей пользователя %s" msgid "Unknown" msgstr "Неизвестно" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Подписки" @@ -6234,7 +6239,7 @@ msgstr "Подписки" msgid "All subscriptions" msgstr "Все подписки." -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Подписчики" @@ -6242,15 +6247,20 @@ msgstr "Подписчики" msgid "All subscribers" msgstr "Все подписчики" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ID пользователя" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Регистрация" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Все группы" @@ -6421,6 +6431,11 @@ msgstr "Отписаться от этого пользователя" msgid "Unsubscribe" msgstr "Отписаться" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "У пользователя нет профиля." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Изменить аватару" @@ -6431,7 +6446,7 @@ msgstr "Действия пользователя" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Идёт удаление пользователя…" #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/statusnet.po b/locale/statusnet.po index eccc291e2..f8d6ea29c 100644 --- a/locale/statusnet.po +++ b/locale/statusnet.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -744,23 +744,27 @@ msgstr "" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +msgid "No file uploaded." +msgstr "" + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "" -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "" @@ -895,7 +899,7 @@ msgid "Conversation" msgstr "" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "" @@ -1690,7 +1694,7 @@ msgstr "" msgid "Updates from members of %1$s on %2$s!" msgstr "" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "" @@ -3216,7 +3220,7 @@ msgid "Description" msgstr "" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "" @@ -3373,7 +3377,7 @@ msgid "Members" msgstr "" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3532,7 +3536,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -3793,8 +3797,7 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "" @@ -4330,35 +4333,35 @@ msgstr "" msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "" -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "" -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4637,22 +4640,22 @@ msgstr "" msgid "Before" msgstr "" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5116,19 +5119,19 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5302,40 +5305,40 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -5778,7 +5781,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "" @@ -5786,7 +5789,7 @@ msgstr "" msgid "All subscriptions" msgstr "" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "" @@ -5794,15 +5797,20 @@ msgstr "" msgid "All subscribers" msgstr "" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "" @@ -5973,6 +5981,11 @@ msgstr "" msgid "Unsubscribe" msgstr "" +#: lib/usernoprofileexception.php:58 +#, php-format +msgid "User %s (%d) has no profile record." +msgstr "" + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "" diff --git a/locale/sv/LC_MESSAGES/statusnet.po b/locale/sv/LC_MESSAGES/statusnet.po index eee7b6d72..681dfedce 100644 --- a/locale/sv/LC_MESSAGES/statusnet.po +++ b/locale/sv/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:33+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:11:02+0000\n" "Language-Team: Swedish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: sv\n" "X-Message-Group: out-statusnet\n" @@ -762,23 +762,28 @@ msgstr "Ladda upp" msgid "Crop" msgstr "Beskär" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Ingen profil angiven." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Välj ett kvadratiskt område i bilden som din avatar" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Förlorade vår fildata." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar uppdaterad." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Misslyckades uppdatera avatar." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Avatar borttagen." @@ -917,7 +922,7 @@ msgid "Conversation" msgstr "Konversationer" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Notiser" @@ -1739,7 +1744,7 @@ msgstr "%s tidslinje" msgid "Updates from members of %1$s on %2$s!" msgstr "Uppdateringar från medlemmar i %1$s på %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Grupper" @@ -3398,7 +3403,7 @@ msgid "Description" msgstr "Beskrivning" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Statistik" @@ -3566,7 +3571,7 @@ msgid "Members" msgstr "Medlemmar" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Ingen)" @@ -3745,7 +3750,8 @@ msgid "Unknown language \"%s\"." msgstr "Okänt språk \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Minsta textbegränsning är 140 tecken." #: actions/siteadminpanel.php:171 @@ -4016,8 +4022,7 @@ msgstr "Spara inställningar för ögonblicksbild" msgid "You are not subscribed to that profile." msgstr "Du är inte prenumerat hos den profilen." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Kunde inte spara prenumeration." @@ -4601,35 +4606,35 @@ msgstr "Problem med att spara gruppinkorg." msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Du har blivit utestängd från att prenumerera." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Redan prenumerant!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Användaren har blockerat dig." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Inte prenumerant!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Kunde inte ta bort själv-prenumeration." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Kunde inte radera OMB prenumerations-token." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Kunde inte ta bort prenumeration." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Välkommen till %1$s, @%2$s!" @@ -4914,22 +4919,22 @@ msgstr "Senare" msgid "Before" msgstr "Tidigare" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "Förväntade ett flödes rotelement, men fick ett helt XML-dokument." + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Kan inte hantera fjärrinnehåll ännu." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Kan inte hantera inbäddat XML-innehåll ännu." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Kan inte hantera inbäddat Base64-innehåll ännu." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5441,19 +5446,19 @@ msgstr "" "tracks - inte implementerat än.\n" "tracking - inte implementerat än.\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Ingen konfigurationsfil hittades. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Jag letade efter konfigurationsfiler på följande platser: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Du kanske vill köra installeraren för att åtgärda detta." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Gå till installeraren." @@ -5629,40 +5634,40 @@ msgstr "Taggar i %s grupps notiser" msgid "This page is not available in a media type you accept" msgstr "Denna sida är inte tillgänglig i den mediatyp du accepterat" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Bildfilens format stödjs inte." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Denna fil är för stor. Den maximala filstorleken är %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Bitvis uppladdad." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Systemfel vid uppladdning av fil." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Inte en bildfil eller så är filen korrupt." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Förlorade vår fil." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Okänd filtyp" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "MB" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "kB" @@ -6196,7 +6201,7 @@ msgstr "Taggar i %ss notiser" msgid "Unknown" msgstr "Okänd" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Prenumerationer" @@ -6204,7 +6209,7 @@ msgstr "Prenumerationer" msgid "All subscriptions" msgstr "Alla prenumerationer" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Prenumeranter" @@ -6212,15 +6217,20 @@ msgstr "Prenumeranter" msgid "All subscribers" msgstr "Alla prenumeranter" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "Användar-ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Medlem sedan" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Alla grupper" @@ -6391,6 +6401,11 @@ msgstr "Avsluta prenumerationen på denna användare" msgid "Unsubscribe" msgstr "Avsluta pren." +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Användaren har ingen profil." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Redigera avatar" @@ -6401,7 +6416,7 @@ msgstr "Åtgärder för användare" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Borttagning av användare pågår..." #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/te/LC_MESSAGES/statusnet.po b/locale/te/LC_MESSAGES/statusnet.po index 091dd8fda..270bf6885 100644 --- a/locale/te/LC_MESSAGES/statusnet.po +++ b/locale/te/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:36+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:11:06+0000\n" "Language-Team: Telugu\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: te\n" "X-Message-Group: out-statusnet\n" @@ -758,23 +758,28 @@ msgstr "ఎగుమతించు" msgid "Crop" msgstr "కత్తిరించు" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "పాక్షిక ఎగుమతి." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "మీ అవతారానికి గానూ ఈ చిత్రం నుండి ఒక చతురస్రపు ప్రదేశాన్ని ఎంచుకోండి" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "అవతారాన్ని తాజాకరించాం." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "అవతారపు తాజాకరణ విఫలమైంది." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "అవతారాన్ని తొలగించాం." @@ -913,7 +918,7 @@ msgid "Conversation" msgstr "సంభాషణ" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "సందేశాలు" @@ -1722,7 +1727,7 @@ msgstr "%s కాలరేఖ" msgid "Updates from members of %1$s on %2$s!" msgstr "%s యొక్క మైక్రోబ్లాగు" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "గుంపులు" @@ -3316,7 +3321,7 @@ msgid "Description" msgstr "వివరణ" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "గణాంకాలు" @@ -3475,7 +3480,7 @@ msgid "Members" msgstr "సభ్యులు" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(ఏమీలేదు)" @@ -3637,7 +3642,8 @@ msgid "Unknown language \"%s\"." msgstr "గుర్తు తెలియని భాష \"%s\"." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "కనిష్ఠ పాఠ్య పరిమితి 140 అక్షరాలు." #: actions/siteadminpanel.php:171 @@ -3908,8 +3914,7 @@ msgstr "సైటు అమరికలను భద్రపరచు" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "చందాని సృష్టించలేకపోయాం." @@ -4457,38 +4462,38 @@ msgstr "సందేశాన్ని భద్రపరచడంలో పొ msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "చందాచేరడం నుండి మిమ్మల్ని నిషేధించారు." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "ఇప్పటికే చందాచేరారు!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "వాడుకరి మిమ్మల్ని నిరోధించారు." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "చందాదార్లు" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "చందాని తొలగించలేకపోయాం." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "చందాని తొలగించలేకపోయాం." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "చందాని తొలగించలేకపోయాం." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "@%2$s, %1$sకి స్వాగతం!" @@ -4779,22 +4784,22 @@ msgstr "తర్వాత" msgid "Before" msgstr "ఇంతక్రితం" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5276,20 +5281,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "నిర్ధారణ సంకేతం లేదు." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5467,41 +5472,41 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "ఇది చాలా పొడవుంది. గరిష్ఠ సందేశ పరిమాణం 140 అక్షరాలు." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "పాక్షిక ఎగుమతి." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "బొమ్మ కాదు లేదా పాడైపోయిన ఫైలు." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "అటువంటి సందేశమేమీ లేదు." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "తెలియని ఫైలు రకం" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "మెబై" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "కిబై" @@ -5989,7 +5994,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "చందాలు" @@ -5997,7 +6002,7 @@ msgstr "చందాలు" msgid "All subscriptions" msgstr "అన్ని చందాలు" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "చందాదార్లు" @@ -6005,15 +6010,20 @@ msgstr "చందాదార్లు" msgid "All subscribers" msgstr "అందరు చందాదార్లు" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "వాడుకరి ID" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "సభ్యులైన తేదీ" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "అన్ని గుంపులు" @@ -6190,6 +6200,11 @@ msgstr "ఈ వాడుకరి నుండి చందామాను" msgid "Unsubscribe" msgstr "చందామాను" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "వాడుకరికి ప్రొఫైలు లేదు." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "అవతారాన్ని మార్చు" diff --git a/locale/tr/LC_MESSAGES/statusnet.po b/locale/tr/LC_MESSAGES/statusnet.po index b6668adcd..051abd983 100644 --- a/locale/tr/LC_MESSAGES/statusnet.po +++ b/locale/tr/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:39+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:11:09+0000\n" "Language-Team: Turkish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: tr\n" "X-Message-Group: out-statusnet\n" @@ -785,23 +785,28 @@ msgstr "Yükle" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Kısmi yükleme." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Avatar güncellendi." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Avatar güncellemede hata." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "Avatar güncellendi." @@ -946,7 +951,7 @@ msgid "Conversation" msgstr "Yer" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Durum mesajları" @@ -1797,7 +1802,7 @@ msgstr "" msgid "Updates from members of %1$s on %2$s!" msgstr "%s adli kullanicinin durum mesajlari" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "" @@ -3418,7 +3423,7 @@ msgid "Description" msgstr "Abonelikler" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "İstatistikler" @@ -3578,7 +3583,7 @@ msgid "Members" msgstr "Üyelik başlangıcı" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3741,7 +3746,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4015,8 +4020,7 @@ msgstr "Ayarlar" msgid "You are not subscribed to that profile." msgstr "Bize o profili yollamadınız" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "Abonelik oluşturulamadı." @@ -4584,39 +4588,39 @@ msgstr "Durum mesajını kaydederken hata oluştu." msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 #, fuzzy msgid "User has blocked you." msgstr "Kullanıcının profili yok." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Bu kullanıcıyı zaten takip etmiyorsunuz!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Abonelik silinemedi." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Abonelik silinemedi." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Abonelik silinemedi." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4924,22 +4928,22 @@ msgstr "« Sonra" msgid "Before" msgstr "Önce »" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5430,20 +5434,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Onay kodu yok." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5628,42 +5632,42 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "Bu sayfa kabul ettiğiniz ortam türünde kullanılabilir değil" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Desteklenmeyen görüntü dosyası biçemi." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" "Ah, durumunuz biraz uzun kaçtı. Azami 180 karaktere sığdırmaya ne dersiniz?" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Kısmi yükleme." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Dosya yüklemede sistem hatası." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Bu bir resim dosyası değil ya da dosyada hata var" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "Böyle bir durum mesajı yok." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6127,7 +6131,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Abonelikler" @@ -6135,7 +6139,7 @@ msgstr "Abonelikler" msgid "All subscriptions" msgstr "Bütün abonelikler" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Abone olanlar" @@ -6144,15 +6148,20 @@ msgstr "Abone olanlar" msgid "All subscribers" msgstr "Abone olanlar" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Üyelik başlangıcı" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "" @@ -6334,6 +6343,11 @@ msgstr "" msgid "Unsubscribe" msgstr "Aboneliği sonlandır" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Kullanıcının profili yok." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/uk/LC_MESSAGES/statusnet.po b/locale/uk/LC_MESSAGES/statusnet.po index 39b7d186b..8121f2068 100644 --- a/locale/uk/LC_MESSAGES/statusnet.po +++ b/locale/uk/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:42+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:11:12+0000\n" "Language-Team: Ukrainian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: uk\n" "X-Message-Group: out-statusnet\n" @@ -772,23 +772,28 @@ msgstr "Завантажити" msgid "Crop" msgstr "Втяти" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Не визначено жодного профілю." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "Оберіть квадратну ділянку зображення, яка й буде Вашою автарою." -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "Дані Вашого файлу десь загубились." -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Аватару оновлено." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Оновлення аватари невдале." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 msgid "Avatar deleted." msgstr "Аватару видалено." @@ -926,7 +931,7 @@ msgid "Conversation" msgstr "Розмова" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Дописи" @@ -1744,7 +1749,7 @@ msgstr "%s стрічка" msgid "Updates from members of %1$s on %2$s!" msgstr "Оновлення членів %1$s на %2$s!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "Групи" @@ -3405,7 +3410,7 @@ msgid "Description" msgstr "Опис" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Статистика" @@ -3572,7 +3577,7 @@ msgid "Members" msgstr "Учасники" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(Пусто)" @@ -3752,7 +3757,8 @@ msgid "Unknown language \"%s\"." msgstr "Невідома мова «%s»." #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +#, fuzzy +msgid "Minimum text limit is 0 (unlimited)." msgstr "Ліміт текстових повідомлень становить 140 знаків." #: actions/siteadminpanel.php:171 @@ -4026,8 +4032,7 @@ msgstr "Зберегти налаштування знімку" msgid "You are not subscribed to that profile." msgstr "Ви не підписані до цього профілю." -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 msgid "Could not save subscription." msgstr "Не вдалося зберегти підписку." @@ -4608,35 +4613,35 @@ msgstr "Проблема при збереженні вхідних дописі msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "Вас позбавлено можливості підписатись." -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "Вже підписаний!" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "Користувач заблокував Вас." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 msgid "Not subscribed!" msgstr "Не підписано!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 msgid "Couldn't delete self-subscription." msgstr "Не можу видалити самопідписку." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 msgid "Couldn't delete subscription OMB token." msgstr "Не вдається видалити токен підписки OMB." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Не вдалося видалити підписку." -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Вітаємо на %1$s, @%2$s!" @@ -4921,22 +4926,23 @@ msgstr "Вперед" msgid "Before" msgstr "Назад" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" +"В очікуванні кореневого елементу веб-стрічки, отримали цілий документ XML." + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "Поки що не можу обробити віддалений контент." -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "Поки що не можу обробити вбудований XML контент." -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "Поки що не можу обробити вбудований контент Base64." -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5448,19 +5454,19 @@ msgstr "" "tracks — наразі не виконується\n" "tracking — наразі не виконується\n" -#: lib/common.php:136 +#: lib/common.php:135 msgid "No configuration file found. " msgstr "Файлу конфігурації не знайдено. " -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "Шукав файли конфігурації в цих місцях: " -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "Запустіть файл інсталяції, аби полагодити це." -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "Іти до файлу інсталяції." @@ -5637,40 +5643,40 @@ msgstr "Теґи у дописах групи %s" msgid "This page is not available in a media type you accept" msgstr "Ця сторінка не доступна для того типу медіа, з яким ви погодились" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Формат зображення не підтримується." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "Цей файл завеликий. Максимальний розмір %s." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Часткове завантаження." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Система відповіла помилкою при завантаженні цього файла." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "Це не зображення, або файл зіпсовано." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 msgid "Lost our file." msgstr "Файл втрачено." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "Тип файлу не підтримується" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "Мб" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "кб" @@ -6204,7 +6210,7 @@ msgstr "Теґи у дописах %s" msgid "Unknown" msgstr "Невідомо" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Підписки" @@ -6212,7 +6218,7 @@ msgstr "Підписки" msgid "All subscriptions" msgstr "Всі підписки" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Підписчики" @@ -6220,15 +6226,20 @@ msgstr "Підписчики" msgid "All subscribers" msgstr "Всі підписчики" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "ІД" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "З нами від" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "Всі групи" @@ -6399,6 +6410,11 @@ msgstr "Відписатись від цього користувача" msgid "Unsubscribe" msgstr "Відписатись" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Користувач не має профілю." + #: lib/userprofile.php:117 msgid "Edit Avatar" msgstr "Аватара" @@ -6409,7 +6425,7 @@ msgstr "Діяльність користувача" #: lib/userprofile.php:237 msgid "User deletion in progress..." -msgstr "" +msgstr "Видалення користувача у процесі..." #: lib/userprofile.php:263 msgid "Edit profile settings" diff --git a/locale/vi/LC_MESSAGES/statusnet.po b/locale/vi/LC_MESSAGES/statusnet.po index 0f560f41d..c934fa28d 100644 --- a/locale/vi/LC_MESSAGES/statusnet.po +++ b/locale/vi/LC_MESSAGES/statusnet.po @@ -7,12 +7,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:45+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:11:15+0000\n" "Language-Team: Vietnamese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: vi\n" "X-Message-Group: out-statusnet\n" @@ -790,23 +790,28 @@ msgstr "Tải file" msgid "Crop" msgstr "Nhóm" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "Upload từng phần." + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "Hình đại diện đã được cập nhật." -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "Cập nhật hình đại diện không thành công." -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "Hình đại diện đã được cập nhật." @@ -950,7 +955,7 @@ msgid "Conversation" msgstr "Không có mã số xác nhận." #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "Tin nhắn" @@ -1842,7 +1847,7 @@ msgstr "Dòng tin nhắn của %s" msgid "Updates from members of %1$s on %2$s!" msgstr "Dòng tin nhắn cho %s" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 #, fuzzy msgid "Groups" @@ -3537,7 +3542,7 @@ msgid "Description" msgstr "Mô tả" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "Số liệu thống kê" @@ -3698,7 +3703,7 @@ msgid "Members" msgstr "Thành viên" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3864,7 +3869,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4155,8 +4160,7 @@ msgstr "Thay đổi hình đại diện" msgid "You are not subscribed to that profile." msgstr "Bạn chưa cập nhật thông tin riêng" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "Không thể tạo đăng nhận." @@ -4737,39 +4741,39 @@ msgstr "Có lỗi xảy ra khi lưu tin nhắn." msgid "RT @%1$s %2$s" msgstr "%s (%s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 #, fuzzy msgid "User has blocked you." msgstr "Người dùng không có thông tin." -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "Chưa đăng nhận!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "Không thể xóa đăng nhận." -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "Không thể xóa đăng nhận." -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "Không thể xóa đăng nhận." -#: classes/User.php:378 +#: classes/User.php:363 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "%s chào mừng bạn " @@ -5081,22 +5085,22 @@ msgstr "Sau" msgid "Before" msgstr "Trước" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 #, fuzzy @@ -5595,20 +5599,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "Không có mã số xác nhận." -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5798,44 +5802,44 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "Trang này không phải là phương tiện truyền thông mà bạn chấp nhận." -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "Không hỗ trợ kiểu file ảnh này." -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" "Bạn có thể cập nhật hồ sơ cá nhân tại đây để mọi người có thể biết thông tin " "về bạn." -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "Upload từng phần." -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "Hệ thống xảy ra lỗi trong khi tải file." -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "File hỏng hoặc không phải là file ảnh." -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "Không có tin nhắn nào." -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 #, fuzzy msgid "Unknown file type" msgstr "Không hỗ trợ kiểu file ảnh này." -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6357,7 +6361,7 @@ msgstr "cảnh báo tin nhắn" msgid "Unknown" msgstr "Không tìm thấy action" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "Tôi theo bạn này" @@ -6365,7 +6369,7 @@ msgstr "Tôi theo bạn này" msgid "All subscriptions" msgstr "Tất cả đăng nhận" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "Bạn này theo tôi" @@ -6374,15 +6378,20 @@ msgstr "Bạn này theo tôi" msgid "All subscribers" msgstr "Bạn này theo tôi" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "Gia nhập từ" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 #, fuzzy msgid "All groups" msgstr "Nhóm" @@ -6573,6 +6582,11 @@ msgstr "Ngừng đăng ký từ người dùng này" msgid "Unsubscribe" msgstr "Hết theo" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "Người dùng không có thông tin." + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/zh_CN/LC_MESSAGES/statusnet.po b/locale/zh_CN/LC_MESSAGES/statusnet.po index a5cef8add..f67435d91 100644 --- a/locale/zh_CN/LC_MESSAGES/statusnet.po +++ b/locale/zh_CN/LC_MESSAGES/statusnet.po @@ -10,12 +10,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:49+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:11:18+0000\n" "Language-Team: Simplified Chinese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: zh-hans\n" "X-Message-Group: out-statusnet\n" @@ -784,23 +784,28 @@ msgstr "上传" msgid "Crop" msgstr "剪裁" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +#, fuzzy +msgid "No file uploaded." +msgstr "没有收件人。" + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "请选择一块方形区域作为你的头像" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "文件数据丢失" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "头像已更新。" -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "更新头像失败。" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "头像已更新。" @@ -946,7 +951,7 @@ msgid "Conversation" msgstr "确认码" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "通告" @@ -1819,7 +1824,7 @@ msgstr "%s 时间表" msgid "Updates from members of %1$s on %2$s!" msgstr "%2$s 上 %1$s 的更新!" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "组" @@ -3472,7 +3477,7 @@ msgid "Description" msgstr "描述" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "统计" @@ -3633,7 +3638,7 @@ msgid "Members" msgstr "注册于" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "(没有)" @@ -3802,7 +3807,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -4084,8 +4089,7 @@ msgstr "头像设置" msgid "You are not subscribed to that profile." msgstr "您未告知此个人信息" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "无法删除订阅。" @@ -4664,40 +4668,40 @@ msgstr "保存通告时出错。" msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 #, fuzzy msgid "You have been banned from subscribing." msgstr "那个用户阻止了你的订阅。" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 #, fuzzy msgid "User has blocked you." msgstr "用户没有个人信息。" -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "未订阅!" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "无法删除订阅。" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "无法删除订阅。" -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "无法删除订阅。" -#: classes/User.php:378 +#: classes/User.php:363 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "发送给 %1$s 的 %2$s 消息" @@ -5009,22 +5013,22 @@ msgstr "« 之后" msgid "Before" msgstr "之前 »" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 #, fuzzy @@ -5517,20 +5521,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "没有验证码" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 #, fuzzy msgid "Go to the installer." msgstr "登入本站" @@ -5718,41 +5722,41 @@ msgstr "这个组所发布的消息的标签" msgid "This page is not available in a media type you accept" msgstr "这个页面不提供您想要的媒体类型" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "不支持这种图像格式。" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, fuzzy, php-format msgid "That file is too big. The maximum file size is %s." msgstr "你可以给你的组上载一个logo图。" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "部分上传。" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "上传文件时出错。" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "不是图片文件或文件已损坏。" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "没有这份通告。" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "未知文件类型" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6230,7 +6234,7 @@ msgstr "%s's 的消息的标签" msgid "Unknown" msgstr "未知动作" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "订阅" @@ -6238,7 +6242,7 @@ msgstr "订阅" msgid "All subscriptions" msgstr "所有订阅" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "订阅者" @@ -6247,16 +6251,21 @@ msgstr "订阅者" msgid "All subscribers" msgstr "订阅者" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 #, fuzzy msgid "User ID" msgstr "用户" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "用户始于" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "所有组" @@ -6444,6 +6453,11 @@ msgstr "取消订阅 %s" msgid "Unsubscribe" msgstr "退订" +#: lib/usernoprofileexception.php:58 +#, fuzzy, php-format +msgid "User %s (%d) has no profile record." +msgstr "用户没有个人信息。" + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" diff --git a/locale/zh_TW/LC_MESSAGES/statusnet.po b/locale/zh_TW/LC_MESSAGES/statusnet.po index a7b777d9d..6b5c237b5 100644 --- a/locale/zh_TW/LC_MESSAGES/statusnet.po +++ b/locale/zh_TW/LC_MESSAGES/statusnet.po @@ -7,12 +7,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-17 21:39+0000\n" -"PO-Revision-Date: 2010-03-17 21:41:53+0000\n" +"POT-Creation-Date: 2010-03-23 20:09+0000\n" +"PO-Revision-Date: 2010-03-23 20:11:21+0000\n" "Language-Team: Traditional Chinese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.17alpha (r63880); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.17alpha (r64087); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" "X-Language-Code: zh-hant\n" "X-Message-Group: out-statusnet\n" @@ -774,23 +774,27 @@ msgstr "" msgid "Crop" msgstr "" -#: actions/avatarsettings.php:328 +#: actions/avatarsettings.php:305 +msgid "No file uploaded." +msgstr "" + +#: actions/avatarsettings.php:332 msgid "Pick a square area of the image to be your avatar" msgstr "" -#: actions/avatarsettings.php:343 actions/grouplogo.php:380 +#: actions/avatarsettings.php:347 actions/grouplogo.php:380 msgid "Lost our file data." msgstr "" -#: actions/avatarsettings.php:366 +#: actions/avatarsettings.php:370 msgid "Avatar updated." msgstr "更新個人圖像" -#: actions/avatarsettings.php:369 +#: actions/avatarsettings.php:373 msgid "Failed updating avatar." msgstr "無法上傳個人圖像" -#: actions/avatarsettings.php:393 +#: actions/avatarsettings.php:397 #, fuzzy msgid "Avatar deleted." msgstr "更新個人圖像" @@ -935,7 +939,7 @@ msgid "Conversation" msgstr "地點" #: actions/conversation.php:154 lib/mailbox.php:116 lib/noticelist.php:87 -#: lib/profileaction.php:218 lib/searchgroupnav.php:82 +#: lib/profileaction.php:224 lib/searchgroupnav.php:82 msgid "Notices" msgstr "" @@ -1777,7 +1781,7 @@ msgstr "" msgid "Updates from members of %1$s on %2$s!" msgstr "&s的微型部落格" -#: actions/groups.php:62 lib/profileaction.php:212 lib/profileaction.php:232 +#: actions/groups.php:62 lib/profileaction.php:218 lib/profileaction.php:244 #: lib/publicgroupnav.php:81 lib/searchgroupnav.php:84 lib/subgroupnav.php:98 msgid "Groups" msgstr "" @@ -3348,7 +3352,7 @@ msgid "Description" msgstr "所有訂閱" #: actions/showapplication.php:192 actions/showgroup.php:439 -#: lib/profileaction.php:176 +#: lib/profileaction.php:182 msgid "Statistics" msgstr "" @@ -3507,7 +3511,7 @@ msgid "Members" msgstr "何時加入會員的呢?" #: actions/showgroup.php:396 lib/profileaction.php:117 -#: lib/profileaction.php:150 lib/profileaction.php:238 lib/section.php:95 +#: lib/profileaction.php:150 lib/profileaction.php:250 lib/section.php:95 #: lib/subscriptionlist.php:126 lib/tagcloudsection.php:71 msgid "(None)" msgstr "" @@ -3669,7 +3673,7 @@ msgid "Unknown language \"%s\"." msgstr "" #: actions/siteadminpanel.php:165 -msgid "Minimum text limit is 140 characters." +msgid "Minimum text limit is 0 (unlimited)." msgstr "" #: actions/siteadminpanel.php:171 @@ -3942,8 +3946,7 @@ msgstr "線上即時通設定" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 classes/Subscription.php:89 -#: classes/Subscription.php:116 +#: actions/subedit.php:83 classes/Subscription.php:132 #, fuzzy msgid "Could not save subscription." msgstr "註冊失敗" @@ -4501,38 +4504,38 @@ msgstr "儲存使用者發生錯誤" msgid "RT @%1$s %2$s" msgstr "" -#: classes/Subscription.php:66 lib/oauthstore.php:465 +#: classes/Subscription.php:74 lib/oauthstore.php:465 msgid "You have been banned from subscribing." msgstr "" -#: classes/Subscription.php:70 +#: classes/Subscription.php:78 msgid "Already subscribed!" msgstr "" -#: classes/Subscription.php:74 +#: classes/Subscription.php:82 msgid "User has blocked you." msgstr "" -#: classes/Subscription.php:157 +#: classes/Subscription.php:167 #, fuzzy msgid "Not subscribed!" msgstr "此帳號已註冊" -#: classes/Subscription.php:163 +#: classes/Subscription.php:173 #, fuzzy msgid "Couldn't delete self-subscription." msgstr "無法刪除帳號" -#: classes/Subscription.php:190 +#: classes/Subscription.php:200 #, fuzzy msgid "Couldn't delete subscription OMB token." msgstr "無法刪除帳號" -#: classes/Subscription.php:201 +#: classes/Subscription.php:211 msgid "Couldn't delete subscription." msgstr "無法刪除帳號" -#: classes/User.php:378 +#: classes/User.php:363 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4834,22 +4837,22 @@ msgstr "" msgid "Before" msgstr "之前的內容»" -#: lib/activity.php:453 +#: lib/activity.php:120 +msgid "Expecting a root feed element but got a whole XML document." +msgstr "" + +#: lib/activityutils.php:208 msgid "Can't handle remote content yet." msgstr "" -#: lib/activity.php:481 +#: lib/activityutils.php:236 msgid "Can't handle embedded XML content yet." msgstr "" -#: lib/activity.php:485 +#: lib/activityutils.php:240 msgid "Can't handle embedded Base64 content yet." msgstr "" -#: lib/activity.php:1089 -msgid "Expecting a root feed element but got a whole XML document." -msgstr "" - #. TRANS: Client error message #: lib/adminpanelaction.php:98 msgid "You cannot make changes to this site." @@ -5329,20 +5332,20 @@ msgid "" "tracking - not yet implemented.\n" msgstr "" -#: lib/common.php:136 +#: lib/common.php:135 #, fuzzy msgid "No configuration file found. " msgstr "無確認碼" -#: lib/common.php:137 +#: lib/common.php:136 msgid "I looked for configuration files in the following places: " msgstr "" -#: lib/common.php:139 +#: lib/common.php:138 msgid "You may wish to run the installer to fix this." msgstr "" -#: lib/common.php:140 +#: lib/common.php:139 msgid "Go to the installer." msgstr "" @@ -5522,41 +5525,41 @@ msgstr "" msgid "This page is not available in a media type you accept" msgstr "" -#: lib/imagefile.php:74 +#: lib/imagefile.php:72 msgid "Unsupported image file format." msgstr "" -#: lib/imagefile.php:90 +#: lib/imagefile.php:88 #, php-format msgid "That file is too big. The maximum file size is %s." msgstr "" -#: lib/imagefile.php:95 +#: lib/imagefile.php:93 msgid "Partial upload." msgstr "" -#: lib/imagefile.php:103 lib/mediafile.php:170 +#: lib/imagefile.php:101 lib/mediafile.php:170 msgid "System error uploading file." msgstr "" -#: lib/imagefile.php:111 +#: lib/imagefile.php:109 msgid "Not an image or corrupt file." msgstr "" -#: lib/imagefile.php:124 +#: lib/imagefile.php:122 #, fuzzy msgid "Lost our file." msgstr "無此通知" -#: lib/imagefile.php:168 lib/imagefile.php:233 +#: lib/imagefile.php:163 lib/imagefile.php:224 msgid "Unknown file type" msgstr "" -#: lib/imagefile.php:253 +#: lib/imagefile.php:244 msgid "MB" msgstr "" -#: lib/imagefile.php:255 +#: lib/imagefile.php:246 msgid "kB" msgstr "" @@ -6018,7 +6021,7 @@ msgstr "" msgid "Unknown" msgstr "" -#: lib/profileaction.php:109 lib/profileaction.php:194 lib/subgroupnav.php:82 +#: lib/profileaction.php:109 lib/profileaction.php:200 lib/subgroupnav.php:82 msgid "Subscriptions" msgstr "" @@ -6026,7 +6029,7 @@ msgstr "" msgid "All subscriptions" msgstr "所有訂閱" -#: lib/profileaction.php:142 lib/profileaction.php:203 lib/subgroupnav.php:90 +#: lib/profileaction.php:142 lib/profileaction.php:209 lib/subgroupnav.php:90 msgid "Subscribers" msgstr "" @@ -6035,15 +6038,20 @@ msgstr "" msgid "All subscribers" msgstr "所有訂閱" -#: lib/profileaction.php:180 +#: lib/profileaction.php:186 msgid "User ID" msgstr "" -#: lib/profileaction.php:185 +#: lib/profileaction.php:191 msgid "Member since" msgstr "何時加入會員的呢?" -#: lib/profileaction.php:247 +#. TRANS: Average count of posts made per day since account registration +#: lib/profileaction.php:230 +msgid "Daily average" +msgstr "" + +#: lib/profileaction.php:259 msgid "All groups" msgstr "" @@ -6222,6 +6230,11 @@ msgstr "" msgid "Unsubscribe" msgstr "" +#: lib/usernoprofileexception.php:58 +#, php-format +msgid "User %s (%d) has no profile record." +msgstr "" + #: lib/userprofile.php:117 #, fuzzy msgid "Edit Avatar" -- cgit v1.2.3-54-g00ecf From 5f32cf32cd7d4a5df7ba64d4f1e7d9edee8d418c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 14:18:45 -0700 Subject: Don't spew XML parse warnings to output when checking a remote XRD page --- plugins/OStatus/lib/xrd.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/lib/xrd.php b/plugins/OStatus/lib/xrd.php index aa13ef024..34b28790b 100644 --- a/plugins/OStatus/lib/xrd.php +++ b/plugins/OStatus/lib/xrd.php @@ -53,7 +53,14 @@ class XRD $xrd = new XRD(); $dom = new DOMDocument(); - if (!$dom->loadXML($xml)) { + + // Don't spew XML warnings to output + $old = error_reporting(); + error_reporting($old & ~E_WARNING); + $ok = $dom->loadXML($xml); + error_reporting($old); + + if (!$ok) { throw new Exception("Invalid XML"); } $xrd_element = $dom->getElementsByTagName('XRD')->item(0); -- cgit v1.2.3-54-g00ecf From df8c9090c0deabe20b804e0fd0766d6b86b7968f Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 14:19:12 -0700 Subject: Add basic subscribe/unsubscribe test to OStatus test cases --- plugins/OStatus/tests/remote-tests.php | 176 +++++++++++++++++++++++++++++---- 1 file changed, 157 insertions(+), 19 deletions(-) diff --git a/plugins/OStatus/tests/remote-tests.php b/plugins/OStatus/tests/remote-tests.php index 103ca066c..b06411491 100644 --- a/plugins/OStatus/tests/remote-tests.php +++ b/plugins/OStatus/tests/remote-tests.php @@ -40,6 +40,20 @@ class TestBase } return true; } + + function assertTrue($a) + { + if (!$a) { + throw new Exception("Failed to assert true: got false"); + } + } + + function assertFalse($a) + { + if ($a) { + throw new Exception("Failed to assert false: got true"); + } + } } class OStatusTester extends TestBase @@ -60,8 +74,12 @@ class OStatusTester extends TestBase function run() { $this->setup(); + $this->testLocalPost(); $this->testMentionUrl(); + $this->testSubscribe(); + $this->testUnsubscribe(); + $this->log("DONE!"); } @@ -98,6 +116,25 @@ class OStatusTester extends TestBase $post = $this->pub->post("@$base/$name should have this in home and replies"); $this->sub->assertReceived($post); } + + function testSubscribe() + { + $this->assertFalse($this->sub->hasSubscription($this->pub->getProfileUri())); + $this->assertFalse($this->pub->hasSubscriber($this->sub->getProfileUri())); + $this->sub->subscribe($this->pub->getProfileLink()); + $this->assertTrue($this->sub->hasSubscription($this->pub->getProfileUri())); + $this->assertTrue($this->pub->hasSubscriber($this->sub->getProfileUri())); + } + + function testUnsubscribe() + { + $this->assertTrue($this->sub->hasSubscription($this->pub->getProfileUri())); + $this->assertTrue($this->pub->hasSubscriber($this->sub->getProfileUri())); + $this->sub->unsubscribe($this->pub->getProfileLink()); + $this->assertFalse($this->sub->hasSubscription($this->pub->getProfileUri())); + $this->assertFalse($this->pub->hasSubscriber($this->sub->getProfileUri())); + } + } class SNTestClient extends TestBase @@ -202,6 +239,43 @@ class SNTestClient extends TestBase return $dom; } + protected function parseXml($path, $body) + { + $dom = new DOMDocument(); + if ($dom->loadXML($body)) { + return $dom; + } else { + throw new Exception("Bogus XML data from $path:\n$body"); + } + } + + /** + * Make a hit to a REST-y XML page on the site, without authentication. + * @param string $path URL fragment for something relative to base + * @param array $params POST parameters to send + * @return DOMDocument + * @throws Exception on low-level error conditions + */ + protected function xml($path, $params=array()) + { + $response = $this->hit($path, $params, true); + $body = $response->getBody(); + return $this->parseXml($path, $body); + } + + protected function parseJson($path, $body) + { + $data = json_decode($body, true); + if ($data !== null) { + if (!empty($data['error'])) { + throw new Exception("JSON API returned error: " . $data['error']); + } + return $data; + } else { + throw new Exception("Bogus JSON data from $path:\n$body"); + } + } + /** * Make an API hit to this site, with authentication. * @param string $path URL fragment for something under 'api' folder @@ -215,22 +289,9 @@ class SNTestClient extends TestBase $response = $this->hit("api/$path.$style", $params, true); $body = $response->getBody(); if ($style == 'json') { - $data = json_decode($body, true); - if ($data !== null) { - if (!empty($data['error'])) { - throw new Exception("JSON API returned error: " . $data['error']); - } - return $data; - } else { - throw new Exception("Bogus JSON data from $path:\n$body"); - } + return $this->parseJson($path, $body); } else if ($style == 'xml' || $style == 'atom') { - $dom = new DOMDocument(); - if ($dom->loadXML($body)) { - return $dom; - } else { - throw new Exception("Bogus XML data from $path:\n$body"); - } + return $this->parseXml($path, $body); } else { throw new Exception("API needs to be JSON, XML, or Atom"); } @@ -257,6 +318,24 @@ class SNTestClient extends TestBase 'submit' => 'Register')); } + /** + * @return string canonical URI/URL to profile page + */ + function getProfileUri() + { + $data = $this->api('account/verify_credentials', 'json'); + $id = $data['id']; + return $this->basepath . '/user/' . $id; + } + + /** + * @return string human-friendly URL to profile page + */ + function getProfileLink() + { + return $this->basepath . '/' . $this->username; + } + /** * Check that the account has been registered and can be used. * On failure, throws a test failure exception. @@ -349,22 +428,81 @@ class SNTestClient extends TestBase return false; } + /** + * @param string $profile user page link or webfinger + */ + function subscribe($profile) + { + // This uses the command interface, since there's not currently + // a friendly Twit-API way to do a fresh remote subscription and + // the web form's a pain to use. + $this->post('follow ' . $profile); + } + + /** + * @param string $profile user page link or webfinger + */ + function unsubscribe($profile) + { + // This uses the command interface, since there's not currently + // a friendly Twit-API way to do a fresh remote subscription and + // the web form's a pain to use. + $this->post('leave ' . $profile); + } + /** * Check that this account is subscribed to the given profile. * @param string $profile_uri URI for the profile to check for + * @return boolean */ - function assertHasSubscription($profile_uri) + function hasSubscription($profile_uri) { - throw new Exception('tbi'); + $this->log("Checking if $this->username has a subscription to $profile_uri"); + + $me = $this->getProfileUri(); + return $this->checkSubscription($me, $profile_uri); } /** * Check that this account is subscribed to by the given profile. * @param string $profile_uri URI for the profile to check for + * @return boolean */ - function assertHasSubscriber($profile_uri) + function hasSubscriber($profile_uri) + { + $this->log("Checking if $this->username is subscribed to by $profile_uri"); + + $me = $this->getProfileUri(); + return $this->checkSubscription($profile_uri, $me); + } + + protected function checkSubscription($subscriber, $subscribed) { - throw new Exception('tbi'); + // Using FOAF as the API methods for checking the social graph + // currently are unfriendly to remote profiles + $ns_foaf = 'http://xmlns.com/foaf/0.1/'; + $ns_sioc = 'http://rdfs.org/sioc/ns#'; + $ns_rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + + $dom = $this->xml($this->username . '/foaf'); + $agents = $dom->getElementsByTagNameNS($ns_foaf, 'Agent'); + foreach ($agents as $agent) { + $agent_uri = $agent->getAttributeNS($ns_rdf, 'about'); + if ($agent_uri == $subscriber) { + $follows = $agent->getElementsByTagNameNS($ns_sioc, 'follows'); + foreach ($follows as $follow) { + $target = $follow->getAttributeNS($ns_rdf, 'resource'); + if ($target == ($subscribed . '#acct')) { + $this->log("Confirmed $subscriber subscribed to $subscribed"); + return true; + } + } + $this->log("We found $subscriber but they don't follow $subscribed"); + return false; + } + } + $this->log("Can't find $subscriber in {$this->username}'s social graph."); + return false; } } -- cgit v1.2.3-54-g00ecf From 13d59e0c76b887a2bfd2e5cfcc2e0fedf728bc07 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 17:24:01 -0700 Subject: fixup_deletions.php script to look for notices posted by now-deleted profiles and remove them. --- classes/Notice.php | 4 +- scripts/fixup_deletions.php | 166 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) create mode 100755 scripts/fixup_deletions.php diff --git a/classes/Notice.php b/classes/Notice.php index f7194e339..be3e9ca2a 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -421,7 +421,9 @@ class Notice extends Memcached_DataObject } $profile = Profile::staticGet($this->profile_id); - $profile->blowNoticeCount(); + if (!empty($profile)) { + $profile->blowNoticeCount(); + } } /** diff --git a/scripts/fixup_deletions.php b/scripts/fixup_deletions.php new file mode 100755 index 000000000..07ada7f9d --- /dev/null +++ b/scripts/fixup_deletions.php @@ -0,0 +1,166 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$longoptions = array('dry-run', 'start=', 'end='); + +$helptext = <<query($query); + + if ($profile->fetch()) { + return intval($profile->id); + } else { + die("Something went awry; could not look up max used profile_id."); + } +} + +/** + * Check for profiles in the given id range that are missing, presumed deleted. + * + * @param int $start beginning profile.id, inclusive + * @param int $end final profile.id, inclusive + * @return array of integer profile.ids + * @access private + */ +function get_missing_profiles($start, $end) +{ + $query = sprintf("SELECT id FROM profile WHERE id BETWEEN %d AND %d", + $start, $end); + + $profile = new Profile(); + $profile->query($query); + + $all = range($start, $end); + $known = array(); + while ($row = $profile->fetch()) { + $known[] = intval($profile->id); + } + unset($profile); + + $missing = array_diff($all, $known); + return $missing; +} + +/** + * Look for stray notices from this profile and, if present, kill them. + * + * @param int $profile_id + * @param bool $dry if true, we won't delete anything + */ +function cleanup_missing_profile($profile_id, $dry) +{ + $notice = new Notice(); + $notice->profile_id = $profile_id; + $notice->find(); + if ($notice->N == 0) { + return; + } + + $s = ($notice->N == 1) ? '' : 's'; + print "Deleted profile $profile_id has $notice->N stray notice$s:\n"; + + while ($notice->fetch()) { + print " notice $notice->id"; + if ($dry) { + print " (skipped; dry run)\n"; + } else { + $victim = clone($notice); + try { + $victim->delete(); + print " (deleted)\n"; + } catch (Exception $e) { + print " FAILED: "; + print $e->getMessage(); + print "\n"; + } + } + } +} + +$dry = have_option('dry-run'); + +$max_profile_id = get_max_profile_id(); +$chunk = 1000; + +if (have_option('start')) { + $begin = intval(get_option_value('start')); +} else { + $begin = 1; +} +if (have_option('end')) { + $final = min($max_profile_id, intval(get_option_value('end'))); +} else { + $final = $max_profile_id; +} + +if ($begin < 1) { + die("Silly human, you can't begin before profile number 1!\n"); +} +if ($final < $begin) { + die("Silly human, you can't end at $final if it's before $begin!\n"); +} + +// Identify missing profiles... +for ($start = $begin; $start <= $final; $start += $chunk) { + $end = min($start + $chunk - 1, $final); + + print "Checking for missing profiles between id $start and $end"; + if ($dry) { + print " (dry run)"; + } + print "...\n"; + $missing = get_missing_profiles($start, $end); + + foreach ($missing as $profile_id) { + cleanup_missing_profile($profile_id, $dry); + } +} + +echo "done.\n"; + -- cgit v1.2.3-54-g00ecf From d9dcdf5b4966fc244fa9b6fa8415c2aeae6cbb47 Mon Sep 17 00:00:00 2001 From: Nick Holliday Date: Tue, 23 Mar 2010 22:30:02 +0000 Subject: Converts Spotify URI/HTTP Links to pretty ones. --- plugins/SpotifyPlugin.php | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 plugins/SpotifyPlugin.php diff --git a/plugins/SpotifyPlugin.php b/plugins/SpotifyPlugin.php new file mode 100644 index 000000000..e7a5a5382 --- /dev/null +++ b/plugins/SpotifyPlugin.php @@ -0,0 +1,113 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Nick Holliday + * @copyright Nick Holliday + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see Event + */ +if (!defined('STATUSNET')) { + exit(1); +} +define('SPOTIFYPLUGIN_VERSION', '0.1'); + +/** + * Plugin to create pretty Spotify URLs + * + * The Spotify API is called before the notice is saved to gather artist and track information. + * + * @category Plugin + * @package StatusNet + * @author Nick Holliday + * @copyright Nick Holliday + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see Event + */ + +class SpotifyPlugin extends Plugin +{ + + function __construct() + { + parent::__construct(); + } + + function onStartNoticeSave($notice) + { + $notice->rendered = preg_replace_callback('/spotify:[a-z]{5,6}:[a-z0-9]{22}/i', + "renderSpotifyURILink", + $notice->rendered); + + $notice->rendered = preg_replace_callback('/http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}<\/a>/i', + "renderSpotifyHTTPLink", + $notice->rendered); + + return true; + } + + function userAgent() + { + return 'SpotifyPlugin/'.SPOTIFYPLUGIN_VERSION . + ' StatusNet/' . STATUSNET_VERSION; + } +} + +function doSpotifyLookup($uri, $isArtist) +{ + $request = HTTPClient::start(); + $response = $request->get('http://ws.spotify.com/lookup/1/?uri=' . $uri); + if ($response->isOk()) { + $xml = simplexml_load_string($response->getBody()); + + if($isArtist) + return $xml->name; + else + return $xml->artist->name . ' - ' . $xml->name; + } +} + +function renderSpotifyURILink($match) +{ + $isArtist = false; + if(preg_match('/artist/', $match[0]) > 0) $isArtist = true; + + $name = doSpotifyLookup($match[0], $isArtist); + return "" . $name . ""; +} + +function renderSpotifyHTTPLink($match) +{ + $match[0] = preg_replace('/http:\/\/open.spotify.com\//i', 'spotify:', $match[0]); + $match[0] = preg_replace('/<\/a>/', '', $match[0]); + $match[0] = preg_replace('/\//', ':', $match[0]); + + $isArtist = false; + if(preg_match('/artist/', $match[0]) > 0) $isArtist = true; + + $name = doSpotifyLookup($match[0], $isArtist); + return "" . $name . ""; +} -- cgit v1.2.3-54-g00ecf From 9380eed794e1bd419a4af4dcbbcd176f164112fc Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 18:44:54 -0700 Subject: add a general PuSHed post and an @-reply back to a subscribee by name to OStatus remote test cases --- plugins/OStatus/tests/remote-tests.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/plugins/OStatus/tests/remote-tests.php b/plugins/OStatus/tests/remote-tests.php index b06411491..a27ecb854 100644 --- a/plugins/OStatus/tests/remote-tests.php +++ b/plugins/OStatus/tests/remote-tests.php @@ -78,6 +78,8 @@ class OStatusTester extends TestBase $this->testLocalPost(); $this->testMentionUrl(); $this->testSubscribe(); + $this->testPush(); + $this->testMentionSubscribee(); $this->testUnsubscribe(); $this->log("DONE!"); @@ -126,6 +128,26 @@ class OStatusTester extends TestBase $this->assertTrue($this->pub->hasSubscriber($this->sub->getProfileUri())); } + function testPush() + { + $this->assertTrue($this->sub->hasSubscription($this->pub->getProfileUri())); + $this->assertTrue($this->pub->hasSubscriber($this->sub->getProfileUri())); + + $name = $this->sub->username; + $post = $this->pub->post("Regular post, which $name should get via PuSH"); + $this->sub->assertReceived($post); + } + + function testMentionSubscribee() + { + $this->assertTrue($this->sub->hasSubscription($this->pub->getProfileUri())); + $this->assertFalse($this->pub->hasSubscription($this->sub->getProfileUri())); + + $name = $this->pub->username; + $post = $this->sub->post("Just a quick note back to my remote subscribee @$name"); + $this->pub->assertReceived($post); + } + function testUnsubscribe() { $this->assertTrue($this->sub->hasSubscription($this->pub->getProfileUri())); -- cgit v1.2.3-54-g00ecf From 6b538cd9b31ffa25d2046e16d47a0cde26d0398f Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 23 Mar 2010 21:50:31 -0400 Subject: Fix some regressions caused by refactor of LDAP plugin --- .../LdapAuthenticationPlugin.php | 2 +- plugins/LdapCommon/LdapCommon.php | 24 +++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/plugins/LdapAuthentication/LdapAuthenticationPlugin.php b/plugins/LdapAuthentication/LdapAuthenticationPlugin.php index a55c45ff5..2e01738ec 100644 --- a/plugins/LdapAuthentication/LdapAuthenticationPlugin.php +++ b/plugins/LdapAuthentication/LdapAuthenticationPlugin.php @@ -118,7 +118,7 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin function suggestNicknameForUsername($username) { - $entry = $this->ldap_get_user($username, $this->attributes); + $entry = $this->ldapCommon->get_user($username, $this->attributes); if(!$entry){ //this really shouldn't happen $nickname = $username; diff --git a/plugins/LdapCommon/LdapCommon.php b/plugins/LdapCommon/LdapCommon.php index 39d872df5..e2ca569f3 100644 --- a/plugins/LdapCommon/LdapCommon.php +++ b/plugins/LdapCommon/LdapCommon.php @@ -47,7 +47,7 @@ class LdapCommon public $uniqueMember_attribute = null; public $attributes=array(); public $password_encoding=null; - + public function __construct($config) { Event::addHandler('Autoload',array($this,'onAutoload')); @@ -68,7 +68,7 @@ class LdapCommon } function onAutoload($cls) - { + { switch ($cls) { case 'MemcacheSchemaCache': @@ -77,6 +77,15 @@ class LdapCommon case 'Net_LDAP2': require_once 'Net/LDAP2.php'; return false; + case 'Net_LDAP2_Filter': + require_once 'Net/LDAP2/Filter.php'; + return false; + case 'Net_LDAP2_Filter': + require_once 'Net/LDAP2/Filter.php'; + return false; + case 'Net_LDAP2_Entry': + require_once 'Net/LDAP2/Entry.php'; + return false; } } @@ -97,8 +106,9 @@ class LdapCommon $config = $this->ldap_config; } $config_id = crc32(serialize($config)); - $ldap = self::$ldap_connections[$config_id]; - if(! isset($ldap)) { + if(array_key_exists($config_id,self::$ldap_connections)) { + $ldap = self::$ldap_connections[$config_id]; + } else { //cannot use Net_LDAP2::connect() as StatusNet uses //PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError'); //PEAR handling can be overridden on instance objects, so we do that. @@ -197,10 +207,10 @@ class LdapCommon return false; } } - + /** * get an LDAP entry for a user with a given username - * + * * @param string $username * $param array $attributes LDAP attributes to retrieve * @return string DN @@ -212,7 +222,7 @@ class LdapCommon 'attributes' => $attributes ); $search = $ldap->search(null,$filter,$options); - + if (PEAR::isError($search)) { common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage()); return false; -- cgit v1.2.3-54-g00ecf From fcf86b4fdf200b1f2955f4f93c5b85054c7254b7 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Mar 2010 18:56:40 -0700 Subject: Improve legibility of OStatus remote tests output --- plugins/OStatus/tests/remote-tests.php | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/plugins/OStatus/tests/remote-tests.php b/plugins/OStatus/tests/remote-tests.php index a27ecb854..24b4b1660 100644 --- a/plugins/OStatus/tests/remote-tests.php +++ b/plugins/OStatus/tests/remote-tests.php @@ -75,13 +75,16 @@ class OStatusTester extends TestBase { $this->setup(); - $this->testLocalPost(); - $this->testMentionUrl(); - $this->testSubscribe(); - $this->testPush(); - $this->testMentionSubscribee(); - $this->testUnsubscribe(); + $methods = get_class_methods($this); + foreach ($methods as $method) { + if (strtolower(substr($method, 0, 4)) == 'test') { + print "\n"; + print "== $method ==\n"; + call_user_func(array($this, $method)); + } + } + print "\n"; $this->log("DONE!"); } @@ -372,6 +375,7 @@ class SNTestClient extends TestBase $this->assertEqual($this->fullname, $data['name']); $this->assertEqual($this->homepage, $data['url']); $this->assertEqual($this->bio, $data['description']); + $this->log(" looks good!"); } /** @@ -408,11 +412,11 @@ class SNTestClient extends TestBase } $tries--; if ($tries) { - $this->log("Didn't see it yet, waiting $timeout seconds"); + $this->log(" didn't see it yet, waiting $timeout seconds"); sleep($timeout); } } - throw new Exception("Message $notice_uri not received by $this->username"); + throw new Exception(" message $notice_uri not received by $this->username"); } /** @@ -442,10 +446,9 @@ class SNTestClient extends TestBase } foreach ($entries as $entry) { if ($entry->id == $notice_uri) { - $this->log("found it $notice_uri"); + $this->log(" found it $notice_uri"); return true; } - //$this->log("nope... " . $entry->id); } return false; } @@ -515,15 +518,15 @@ class SNTestClient extends TestBase foreach ($follows as $follow) { $target = $follow->getAttributeNS($ns_rdf, 'resource'); if ($target == ($subscribed . '#acct')) { - $this->log("Confirmed $subscriber subscribed to $subscribed"); + $this->log(" confirmed $subscriber subscribed to $subscribed"); return true; } } - $this->log("We found $subscriber but they don't follow $subscribed"); + $this->log(" we found $subscriber but they don't follow $subscribed"); return false; } } - $this->log("Can't find $subscriber in {$this->username}'s social graph."); + $this->log(" can't find $subscriber in {$this->username}'s social graph."); return false; } -- cgit v1.2.3-54-g00ecf From 1f73156daeef47cf8a7214936383fbc496255fd7 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 23 Mar 2010 21:57:47 -0400 Subject: Move the bundled Net/LDAP2 library to the LdapCommon directory --- extlib/Net/LDAP2.php | 1791 -------------------- extlib/Net/LDAP2/Entry.php | 1055 ------------ extlib/Net/LDAP2/Filter.php | 514 ------ extlib/Net/LDAP2/LDIF.php | 922 ---------- extlib/Net/LDAP2/RootDSE.php | 240 --- extlib/Net/LDAP2/Schema.php | 516 ------ extlib/Net/LDAP2/SchemaCache.interface.php | 59 - extlib/Net/LDAP2/Search.php | 614 ------- extlib/Net/LDAP2/SimpleFileSchemaCache.php | 97 -- extlib/Net/LDAP2/Util.php | 572 ------- plugins/LdapCommon/LdapCommon.php | 3 + plugins/LdapCommon/extlib/Net/LDAP2.php | 1791 ++++++++++++++++++++ plugins/LdapCommon/extlib/Net/LDAP2/Entry.php | 1055 ++++++++++++ plugins/LdapCommon/extlib/Net/LDAP2/Filter.php | 514 ++++++ plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php | 922 ++++++++++ plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php | 240 +++ plugins/LdapCommon/extlib/Net/LDAP2/Schema.php | 516 ++++++ .../extlib/Net/LDAP2/SchemaCache.interface.php | 59 + plugins/LdapCommon/extlib/Net/LDAP2/Search.php | 614 +++++++ .../extlib/Net/LDAP2/SimpleFileSchemaCache.php | 97 ++ plugins/LdapCommon/extlib/Net/LDAP2/Util.php | 572 +++++++ 21 files changed, 6383 insertions(+), 6380 deletions(-) delete mode 100644 extlib/Net/LDAP2.php delete mode 100644 extlib/Net/LDAP2/Entry.php delete mode 100644 extlib/Net/LDAP2/Filter.php delete mode 100644 extlib/Net/LDAP2/LDIF.php delete mode 100644 extlib/Net/LDAP2/RootDSE.php delete mode 100644 extlib/Net/LDAP2/Schema.php delete mode 100644 extlib/Net/LDAP2/SchemaCache.interface.php delete mode 100644 extlib/Net/LDAP2/Search.php delete mode 100644 extlib/Net/LDAP2/SimpleFileSchemaCache.php delete mode 100644 extlib/Net/LDAP2/Util.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/Entry.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/Filter.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/Schema.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/SchemaCache.interface.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/Search.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/SimpleFileSchemaCache.php create mode 100644 plugins/LdapCommon/extlib/Net/LDAP2/Util.php diff --git a/extlib/Net/LDAP2.php b/extlib/Net/LDAP2.php deleted file mode 100644 index 26f5e7560..000000000 --- a/extlib/Net/LDAP2.php +++ /dev/null @@ -1,1791 +0,0 @@ - -* @author Jan Wagner -* @author Del -* @author Benedikt Hallinger -* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: LDAP2.php 286788 2009-08-04 06:05:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Package includes. -*/ -require_once 'PEAR.php'; -require_once 'Net/LDAP2/RootDSE.php'; -require_once 'Net/LDAP2/Schema.php'; -require_once 'Net/LDAP2/Entry.php'; -require_once 'Net/LDAP2/Search.php'; -require_once 'Net/LDAP2/Util.php'; -require_once 'Net/LDAP2/Filter.php'; -require_once 'Net/LDAP2/LDIF.php'; -require_once 'Net/LDAP2/SchemaCache.interface.php'; -require_once 'Net/LDAP2/SimpleFileSchemaCache.php'; - -/** -* Error constants for errors that are not LDAP errors. -*/ -define('NET_LDAP2_ERROR', 1000); - -/** -* Net_LDAP2 Version -*/ -define('NET_LDAP2_VERSION', '2.0.7'); - -/** -* Net_LDAP2 - manipulate LDAP servers the right way! -* -* @category Net -* @package Net_LDAP2 -* @author Tarjej Huse -* @author Jan Wagner -* @author Del -* @author Benedikt Hallinger -* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP2/ -*/ -class Net_LDAP2 extends PEAR -{ - /** - * Class configuration array - * - * host = the ldap host to connect to - * (may be an array of several hosts to try) - * port = the server port - * version = ldap version (defaults to v 3) - * starttls = when set, ldap_start_tls() is run after connecting. - * bindpw = no explanation needed - * binddn = the DN to bind as. - * basedn = ldap base - * options = hash of ldap options to set (opt => val) - * filter = default search filter - * scope = default search scope - * - * Newly added in 2.0.0RC4, for auto-reconnect: - * auto_reconnect = if set to true then the class will automatically - * attempt to reconnect to the LDAP server in certain - * failure conditionswhen attempting a search, or other - * LDAP operation. Defaults to false. Note that if you - * set this to true, calls to search() may block - * indefinitely if there is a catastrophic server failure. - * min_backoff = minimum reconnection delay period (in seconds). - * current_backoff = initial reconnection delay period (in seconds). - * max_backoff = maximum reconnection delay period (in seconds). - * - * @access protected - * @var array - */ - protected $_config = array('host' => 'localhost', - 'port' => 389, - 'version' => 3, - 'starttls' => false, - 'binddn' => '', - 'bindpw' => '', - 'basedn' => '', - 'options' => array(), - 'filter' => '(objectClass=*)', - 'scope' => 'sub', - 'auto_reconnect' => false, - 'min_backoff' => 1, - 'current_backoff' => 1, - 'max_backoff' => 32); - - /** - * List of hosts we try to establish a connection to - * - * @access protected - * @var array - */ - protected $_host_list = array(); - - /** - * List of hosts that are known to be down. - * - * @access protected - * @var array - */ - protected $_down_host_list = array(); - - /** - * LDAP resource link. - * - * @access protected - * @var resource - */ - protected $_link = false; - - /** - * Net_LDAP2_Schema object - * - * This gets set and returned by {@link schema()} - * - * @access protected - * @var object Net_LDAP2_Schema - */ - protected $_schema = null; - - /** - * Schema cacher function callback - * - * @see registerSchemaCache() - * @var string - */ - protected $_schema_cache = null; - - /** - * Cache for attribute encoding checks - * - * @access protected - * @var array Hash with attribute names as key and boolean value - * to determine whether they should be utf8 encoded or not. - */ - protected $_schemaAttrs = array(); - - /** - * Cache for rootDSE objects - * - * Hash with requested rootDSE attr names as key and rootDSE object as value - * - * Since the RootDSE object itself may request a rootDSE object, - * {@link rootDse()} caches successful requests. - * Internally, Net_LDAP2 needs several lookups to this object, so - * caching increases performance significally. - * - * @access protected - * @var array - */ - protected $_rootDSE_cache = array(); - - /** - * Returns the Net_LDAP2 Release version, may be called statically - * - * @static - * @return string Net_LDAP2 version - */ - public static function getVersion() - { - return NET_LDAP2_VERSION; - } - - /** - * Configure Net_LDAP2, connect and bind - * - * Use this method as starting point of using Net_LDAP2 - * to establish a connection to your LDAP server. - * - * Static function that returns either an error object or the new Net_LDAP2 - * object. Something like a factory. Takes a config array with the needed - * parameters. - * - * @param array $config Configuration array - * - * @access public - * @return Net_LDAP2_Error|Net_LDAP2 Net_LDAP2_Error or Net_LDAP2 object - */ - public static function &connect($config = array()) - { - $ldap_check = self::checkLDAPExtension(); - if (self::iserror($ldap_check)) { - return $ldap_check; - } - - @$obj = new Net_LDAP2($config); - - // todo? better errorhandling for setConfig()? - - // connect and bind with credentials in config - $err = $obj->bind(); - if (self::isError($err)) { - return $err; - } - - return $obj; - } - - /** - * Net_LDAP2 constructor - * - * Sets the config array - * - * Please note that the usual way of getting Net_LDAP2 to work is - * to call something like: - * $ldap = Net_LDAP2::connect($ldap_config); - * - * @param array $config Configuration array - * - * @access protected - * @return void - * @see $_config - */ - public function __construct($config = array()) - { - $this->PEAR('Net_LDAP2_Error'); - $this->setConfig($config); - } - - /** - * Sets the internal configuration array - * - * @param array $config Configuration array - * - * @access protected - * @return void - */ - protected function setConfig($config) - { - // - // Parameter check -- probably should raise an error here if config - // is not an array. - // - if (! is_array($config)) { - return; - } - - foreach ($config as $k => $v) { - if (isset($this->_config[$k])) { - $this->_config[$k] = $v; - } else { - // map old (Net_LDAP2) parms to new ones - switch($k) { - case "dn": - $this->_config["binddn"] = $v; - break; - case "password": - $this->_config["bindpw"] = $v; - break; - case "tls": - $this->_config["starttls"] = $v; - break; - case "base": - $this->_config["basedn"] = $v; - break; - } - } - } - - // - // Ensure the host list is an array. - // - if (is_array($this->_config['host'])) { - $this->_host_list = $this->_config['host']; - } else { - if (strlen($this->_config['host']) > 0) { - $this->_host_list = array($this->_config['host']); - } else { - $this->_host_list = array(); - // ^ this will cause an error in performConnect(), - // so the user is notified about the failure - } - } - - // - // Reset the down host list, which seems like a sensible thing to do - // if the config is being reset for some reason. - // - $this->_down_host_list = array(); - } - - /** - * Bind or rebind to the ldap-server - * - * This function binds with the given dn and password to the server. In case - * no connection has been made yet, it will be started and startTLS issued - * if appropiate. - * - * The internal bind configuration is not being updated, so if you call - * bind() without parameters, you can rebind with the credentials - * provided at first connecting to the server. - * - * @param string $dn Distinguished name for binding - * @param string $password Password for binding - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - public function bind($dn = null, $password = null) - { - // fetch current bind credentials - if (is_null($dn)) { - $dn = $this->_config["binddn"]; - } - if (is_null($password)) { - $password = $this->_config["bindpw"]; - } - - // Connect first, if we haven't so far. - // This will also bind us to the server. - if ($this->_link === false) { - // store old credentials so we can revert them later - // then overwrite config with new bind credentials - $olddn = $this->_config["binddn"]; - $oldpw = $this->_config["bindpw"]; - - // overwrite bind credentials in config - // so performConnect() knows about them - $this->_config["binddn"] = $dn; - $this->_config["bindpw"] = $password; - - // try to connect with provided credentials - $msg = $this->performConnect(); - - // reset to previous config - $this->_config["binddn"] = $olddn; - $this->_config["bindpw"] = $oldpw; - - // see if bind worked - if (self::isError($msg)) { - return $msg; - } - } else { - // do the requested bind as we are - // asked to bind manually - if (is_null($dn)) { - // anonymous bind - $msg = @ldap_bind($this->_link); - } else { - // privileged bind - $msg = @ldap_bind($this->_link, $dn, $password); - } - if (false === $msg) { - return PEAR::raiseError("Bind failed: " . - @ldap_error($this->_link), - @ldap_errno($this->_link)); - } - } - return true; - } - - /** - * Connect to the ldap-server - * - * This function connects to the LDAP server specified in - * the configuration, binds and set up the LDAP protocol as needed. - * - * @access protected - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - protected function performConnect() - { - // Note: Connecting is briefly described in RFC1777. - // Basicly it works like this: - // 1. set up TCP connection - // 2. secure that connection if neccessary - // 3a. setLDAPVersion to tell server which version we want to speak - // 3b. perform bind - // 3c. setLDAPVersion to tell server which version we want to speak - // together with a test for supported versions - // 4. set additional protocol options - - // Return true if we are already connected. - if ($this->_link !== false) { - return true; - } - - // Connnect to the LDAP server if we are not connected. Note that - // with some LDAP clients, ldapperformConnect returns a link value even - // if no connection is made. We need to do at least one anonymous - // bind to ensure that a connection is actually valid. - // - // Ref: http://www.php.net/manual/en/function.ldap-connect.php - - // Default error message in case all connection attempts - // fail but no message is set - $current_error = new PEAR_Error('Unknown connection error'); - - // Catch empty $_host_list arrays. - if (!is_array($this->_host_list) || count($this->_host_list) == 0) { - $current_error = PEAR::raiseError('No Servers configured! Please '. - 'pass in an array of servers to Net_LDAP2'); - return $current_error; - } - - // Cycle through the host list. - foreach ($this->_host_list as $host) { - - // Ensure we have a valid string for host name - if (is_array($host)) { - $current_error = PEAR::raiseError('No Servers configured! '. - 'Please pass in an one dimensional array of servers to '. - 'Net_LDAP2! (multidimensional array detected!)'); - continue; - } - - // Skip this host if it is known to be down. - if (in_array($host, $this->_down_host_list)) { - continue; - } - - // Record the host that we are actually connecting to in case - // we need it later. - $this->_config['host'] = $host; - - // Attempt a connection. - $this->_link = @ldap_connect($host, $this->_config['port']); - if (false === $this->_link) { - $current_error = PEAR::raiseError('Could not connect to ' . - $host . ':' . $this->_config['port']); - $this->_down_host_list[] = $host; - continue; - } - - // If we're supposed to use TLS, do so before we try to bind, - // as some strict servers only allow binding via secure connections - if ($this->_config["starttls"] === true) { - if (self::isError($msg = $this->startTLS())) { - $current_error = $msg; - $this->_link = false; - $this->_down_host_list[] = $host; - continue; - } - } - - // Try to set the configured LDAP version on the connection if LDAP - // server needs that before binding (eg OpenLDAP). - // This could be necessary since rfc-1777 states that the protocol version - // has to be set at the bind request. - // We use force here which means that the test in the rootDSE is skipped; - // this is neccessary, because some strict LDAP servers only allow to - // read the LDAP rootDSE (which tells us the supported protocol versions) - // with authenticated clients. - // This may fail in which case we try again after binding. - // In this case, most probably the bind() or setLDAPVersion()-call - // below will also fail, providing error messages. - $version_set = false; - $ignored_err = $this->setLDAPVersion(0, true); - if (!self::isError($ignored_err)) { - $version_set = true; - } - - // Attempt to bind to the server. If we have credentials configured, - // we try to use them, otherwise its an anonymous bind. - // As stated by RFC-1777, the bind request should be the first - // operation to be performed after the connection is established. - // This may give an protocol error if the server does not support - // V2 binds and the above call to setLDAPVersion() failed. - // In case the above call failed, we try an V2 bind here and set the - // version afterwards (with checking to the rootDSE). - $msg = $this->bind(); - if (self::isError($msg)) { - // The bind failed, discard link and save error msg. - // Then record the host as down and try next one - if ($msg->getCode() == 0x02 && !$version_set) { - // provide a finer grained error message - // if protocol error arieses because of invalid version - $msg = new Net_LDAP2_Error($msg->getMessage(). - " (could not set LDAP protocol version to ". - $this->_config['version'].")", - $msg->getCode()); - } - $this->_link = false; - $current_error = $msg; - $this->_down_host_list[] = $host; - continue; - } - - // Set desired LDAP version if not successfully set before. - // Here, a check against the rootDSE is performed, so we get a - // error message if the server does not support the version. - // The rootDSE entry should tell us which LDAP versions are - // supported. However, some strict LDAP servers only allow - // bound suers to read the rootDSE. - if (!$version_set) { - if (self::isError($msg = $this->setLDAPVersion())) { - $current_error = $msg; - $this->_link = false; - $this->_down_host_list[] = $host; - continue; - } - } - - // Set LDAP parameters, now we know we have a valid connection. - if (isset($this->_config['options']) && - is_array($this->_config['options']) && - count($this->_config['options'])) { - foreach ($this->_config['options'] as $opt => $val) { - $err = $this->setOption($opt, $val); - if (self::isError($err)) { - $current_error = $err; - $this->_link = false; - $this->_down_host_list[] = $host; - continue 2; - } - } - } - - // At this stage we have connected, bound, and set up options, - // so we have a known good LDAP server. Time to go home. - return true; - } - - - // All connection attempts have failed, return the last error. - return $current_error; - } - - /** - * Reconnect to the ldap-server. - * - * In case the connection to the LDAP - * service has dropped out for some reason, this function will reconnect, - * and re-bind if a bind has been attempted in the past. It is probably - * most useful when the server list provided to the new() or connect() - * function is an array rather than a single host name, because in that - * case it will be able to connect to a failover or secondary server in - * case the primary server goes down. - * - * This doesn't return anything, it just tries to re-establish - * the current connection. It will sleep for the current backoff - * period (seconds) before attempting the connect, and if the - * connection fails it will double the backoff period, but not - * try again. If you want to ensure a reconnection during a - * transient period of server downtime then you need to call this - * function in a loop. - * - * @access protected - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - protected function performReconnect() - { - - // Return true if we are already connected. - if ($this->_link !== false) { - return true; - } - - // Default error message in case all connection attempts - // fail but no message is set - $current_error = new PEAR_Error('Unknown connection error'); - - // Sleep for a backoff period in seconds. - sleep($this->_config['current_backoff']); - - // Retry all available connections. - $this->_down_host_list = array(); - $msg = $this->performConnect(); - - // Bail out if that fails. - if (self::isError($msg)) { - $this->_config['current_backoff'] = - $this->_config['current_backoff'] * 2; - if ($this->_config['current_backoff'] > $this->_config['max_backoff']) { - $this->_config['current_backoff'] = $this->_config['max_backoff']; - } - return $msg; - } - - // Now we should be able to safely (re-)bind. - $msg = $this->bind(); - if (self::isError($msg)) { - $this->_config['current_backoff'] = $this->_config['current_backoff'] * 2; - if ($this->_config['current_backoff'] > $this->_config['max_backoff']) { - $this->_config['current_backoff'] = $this->_config['max_backoff']; - } - - // _config['host'] should have had the last connected host stored in it - // by performConnect(). Since we are unable to bind to that host we can safely - // assume that it is down or has some other problem. - $this->_down_host_list[] = $this->_config['host']; - return $msg; - } - - // At this stage we have connected, bound, and set up options, - // so we have a known good LDAP server. Time to go home. - $this->_config['current_backoff'] = $this->_config['min_backoff']; - return true; - } - - /** - * Starts an encrypted session - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - public function startTLS() - { - // Test to see if the server supports TLS first. - // This is done via testing the extensions offered by the server. - // The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported. - $rootDSE = $this->rootDse(); - if (self::isError($rootDSE)) { - return $this->raiseError("Unable to fetch rootDSE entry ". - "to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode()); - } - - $supported_extensions = $rootDSE->getValue('supportedExtension'); - if (self::isError($supported_extensions)) { - return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ". - "to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode()); - } - - if (in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) { - if (false === @ldap_start_tls($this->_link)) { - return $this->raiseError("TLS not started: " . - @ldap_error($this->_link), - @ldap_errno($this->_link)); - } - return true; - } else { - return $this->raiseError("Server reports that it does not support TLS"); - } - } - - /** - * alias function of startTLS() for perl-ldap interface - * - * @return void - * @see startTLS() - */ - public function start_tls() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'startTLS' ), $args); - } - - /** - * Close LDAP connection. - * - * Closes the connection. Use this when the session is over. - * - * @return void - */ - public function done() - { - $this->_Net_LDAP2(); - } - - /** - * Alias for {@link done()} - * - * @return void - * @see done() - */ - public function disconnect() - { - $this->done(); - } - - /** - * Destructor - * - * @access protected - */ - public function _Net_LDAP2() - { - @ldap_close($this->_link); - } - - /** - * Add a new entryobject to a directory. - * - * Use add to add a new Net_LDAP2_Entry object to the directory. - * This also links the entry to the connection used for the add, - * if it was a fresh entry ({@link Net_LDAP2_Entry::createFresh()}) - * - * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry - * - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - public function add(&$entry) - { - if (!$entry instanceof Net_LDAP2_Entry) { - return PEAR::raiseError('Parameter to Net_LDAP2::add() must be a Net_LDAP2_Entry object.'); - } - - // Continue attempting the add operation in a loop until we - // get a success, a definitive failure, or the world ends. - $foo = 0; - while (true) { - $link = $this->getLink(); - - if ($link === false) { - // We do not have a successful connection yet. The call to - // getLink() would have kept trying if we wanted one. Go - // home now. - return PEAR::raiseError("Could not add entry " . $entry->dn() . - " no valid LDAP connection could be found."); - } - - if (@ldap_add($link, $entry->dn(), $entry->getValues())) { - // entry successfully added, we should update its $ldap reference - // in case it is not set so far (fresh entry) - if (!$entry->getLDAP() instanceof Net_LDAP2) { - $entry->setLDAP($this); - } - // store, that the entry is present inside the directory - $entry->markAsNew(false); - return true; - } else { - // We have a failure. What type? We may be able to reconnect - // and try again. - $error_code = @ldap_errno($link); - $error_name = $this->errorMessage($error_code); - - if (($error_name === 'LDAP_OPERATIONS_ERROR') && - ($this->_config['auto_reconnect'])) { - - // The server has become disconnected before trying the - // operation. We should try again, possibly with a different - // server. - $this->_link = false; - $this->performReconnect(); - } else { - // Errors other than the above catched are just passed - // back to the user so he may react upon them. - return PEAR::raiseError("Could not add entry " . $entry->dn() . " " . - $error_name, - $error_code); - } - } - } - } - - /** - * Delete an entry from the directory - * - * The object may either be a string representing the dn or a Net_LDAP2_Entry - * object. When the boolean paramter recursive is set, all subentries of the - * entry will be deleted as well. - * - * @param string|Net_LDAP2_Entry $dn DN-string or Net_LDAP2_Entry - * @param boolean $recursive Should we delete all children recursive as well? - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - public function delete($dn, $recursive = false) - { - if ($dn instanceof Net_LDAP2_Entry) { - $dn = $dn->dn(); - } - if (false === is_string($dn)) { - return PEAR::raiseError("Parameter is not a string nor an entry object!"); - } - // Recursive delete searches for children and calls delete for them - if ($recursive) { - $result = @ldap_list($this->_link, $dn, '(objectClass=*)', array(null), 0, 0); - if (@ldap_count_entries($this->_link, $result)) { - $subentry = @ldap_first_entry($this->_link, $result); - $this->delete(@ldap_get_dn($this->_link, $subentry), true); - while ($subentry = @ldap_next_entry($this->_link, $subentry)) { - $this->delete(@ldap_get_dn($this->_link, $subentry), true); - } - } - } - - // Continue attempting the delete operation in a loop until we - // get a success, a definitive failure, or the world ends. - while (true) { - $link = $this->getLink(); - - if ($link === false) { - // We do not have a successful connection yet. The call to - // getLink() would have kept trying if we wanted one. Go - // home now. - return PEAR::raiseError("Could not add entry " . $dn . - " no valid LDAP connection could be found."); - } - - if (@ldap_delete($link, $dn)) { - // entry successfully deleted. - return true; - } else { - // We have a failure. What type? - // We may be able to reconnect and try again. - $error_code = @ldap_errno($link); - $error_name = $this->errorMessage($error_code); - - if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && - ($this->_config['auto_reconnect'])) { - // The server has become disconnected before trying the - // operation. We should try again, possibly with a - // different server. - $this->_link = false; - $this->performReconnect(); - - } elseif ($error_code == 66) { - // Subentries present, server refused to delete. - // Deleting subentries is the clients responsibility, but - // since the user may not know of the subentries, we do not - // force that here but instead notify the developer so he - // may take actions himself. - return PEAR::raiseError("Could not delete entry $dn because of subentries. Use the recursive parameter to delete them."); - - } else { - // Errors other than the above catched are just passed - // back to the user so he may react upon them. - return PEAR::raiseError("Could not delete entry " . $dn . " " . - $error_name, - $error_code); - } - } - } - } - - /** - * Modify an ldapentry directly on the server - * - * This one takes the DN or a Net_LDAP2_Entry object and an array of actions. - * This array should be something like this: - * - * array('add' => array('attribute1' => array('val1', 'val2'), - * 'attribute2' => array('val1')), - * 'delete' => array('attribute1'), - * 'replace' => array('attribute1' => array('val1')), - * 'changes' => array('add' => ..., - * 'replace' => ..., - * 'delete' => array('attribute1', 'attribute2' => array('val1'))) - * - * The changes array is there so the order of operations can be influenced - * (the operations are done in order of appearance). - * The order of execution is as following: - * 1. adds from 'add' array - * 2. deletes from 'delete' array - * 3. replaces from 'replace' array - * 4. changes (add, replace, delete) in order of appearance - * All subarrays (add, replace, delete, changes) may be given at the same time. - * - * The function calls the corresponding functions of an Net_LDAP2_Entry - * object. A detailed description of array structures can be found there. - * - * Unlike the modification methods provided by the Net_LDAP2_Entry object, - * this method will instantly carry out an update() after each operation, - * thus modifying "directly" on the server. - * - * @param string|Net_LDAP2_Entry $entry DN-string or Net_LDAP2_Entry - * @param array $parms Array of changes - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - public function modify($entry, $parms = array()) - { - if (is_string($entry)) { - $entry = $this->getEntry($entry); - if (self::isError($entry)) { - return $entry; - } - } - if (!$entry instanceof Net_LDAP2_Entry) { - return PEAR::raiseError("Parameter is not a string nor an entry object!"); - } - - // Perform changes mentioned separately - foreach (array('add', 'delete', 'replace') as $action) { - if (isset($parms[$action])) { - $msg = $entry->$action($parms[$action]); - if (self::isError($msg)) { - return $msg; - } - $entry->setLDAP($this); - - // Because the @ldap functions are called inside Net_LDAP2_Entry::update(), - // we have to trap the error codes issued from that if we want to support - // reconnection. - while (true) { - $msg = $entry->update(); - - if (self::isError($msg)) { - // We have a failure. What type? We may be able to reconnect - // and try again. - $error_code = $msg->getCode(); - $error_name = $this->errorMessage($error_code); - - if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && - ($this->_config['auto_reconnect'])) { - - // The server has become disconnected before trying the - // operation. We should try again, possibly with a different - // server. - $this->_link = false; - $this->performReconnect(); - - } else { - - // Errors other than the above catched are just passed - // back to the user so he may react upon them. - return PEAR::raiseError("Could not modify entry: ".$msg->getMessage()); - } - } else { - // modification succeedet, evaluate next change - break; - } - } - } - } - - // perform combined changes in 'changes' array - if (isset($parms['changes']) && is_array($parms['changes'])) { - foreach ($parms['changes'] as $action => $value) { - - // Because the @ldap functions are called inside Net_LDAP2_Entry::update, - // we have to trap the error codes issued from that if we want to support - // reconnection. - while (true) { - $msg = $this->modify($entry, array($action => $value)); - - if (self::isError($msg)) { - // We have a failure. What type? We may be able to reconnect - // and try again. - $error_code = $msg->getCode(); - $error_name = $this->errorMessage($error_code); - - if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && - ($this->_config['auto_reconnect'])) { - - // The server has become disconnected before trying the - // operation. We should try again, possibly with a different - // server. - $this->_link = false; - $this->performReconnect(); - - } else { - // Errors other than the above catched are just passed - // back to the user so he may react upon them. - return $msg; - } - } else { - // modification succeedet, evaluate next change - break; - } - } - } - } - - return true; - } - - /** - * Run a ldap search query - * - * Search is used to query the ldap-database. - * $base and $filter may be ommitted. The one from config will - * then be used. $base is either a DN-string or an Net_LDAP2_Entry - * object in which case its DN willb e used. - * - * Params may contain: - * - * scope: The scope which will be used for searching - * base - Just one entry - * sub - The whole tree - * one - Immediately below $base - * sizelimit: Limit the number of entries returned (default: 0 = unlimited), - * timelimit: Limit the time spent for searching (default: 0 = unlimited), - * attrsonly: If true, the search will only return the attribute names, - * attributes: Array of attribute names, which the entry should contain. - * It is good practice to limit this to just the ones you need. - * [NOT IMPLEMENTED] - * deref: By default aliases are dereferenced to locate the base object for the search, but not when - * searching subordinates of the base object. This may be changed by specifying one of the - * following values: - * - * never - Do not dereference aliases in searching or in locating the base object of the search. - * search - Dereference aliases in subordinates of the base object in searching, but not in - * locating the base object of the search. - * find - * always - * - * Please note, that you cannot override server side limitations to sizelimit - * and timelimit: You can always only lower a given limit. - * - * @param string|Net_LDAP2_Entry $base LDAP searchbase - * @param string|Net_LDAP2_Filter $filter LDAP search filter or a Net_LDAP2_Filter object - * @param array $params Array of options - * - * @access public - * @return Net_LDAP2_Search|Net_LDAP2_Error Net_LDAP2_Search object or Net_LDAP2_Error object - * @todo implement search controls (sorting etc) - */ - public function search($base = null, $filter = null, $params = array()) - { - if (is_null($base)) { - $base = $this->_config['basedn']; - } - if ($base instanceof Net_LDAP2_Entry) { - $base = $base->dn(); // fetch DN of entry, making searchbase relative to the entry - } - if (is_null($filter)) { - $filter = $this->_config['filter']; - } - if ($filter instanceof Net_LDAP2_Filter) { - $filter = $filter->asString(); // convert Net_LDAP2_Filter to string representation - } - if (PEAR::isError($filter)) { - return $filter; - } - if (PEAR::isError($base)) { - return $base; - } - - /* setting searchparameters */ - (isset($params['sizelimit'])) ? $sizelimit = $params['sizelimit'] : $sizelimit = 0; - (isset($params['timelimit'])) ? $timelimit = $params['timelimit'] : $timelimit = 0; - (isset($params['attrsonly'])) ? $attrsonly = $params['attrsonly'] : $attrsonly = 0; - (isset($params['attributes'])) ? $attributes = $params['attributes'] : $attributes = array(); - - // Ensure $attributes to be an array in case only one - // attribute name was given as string - if (!is_array($attributes)) { - $attributes = array($attributes); - } - - // reorganize the $attributes array index keys - // sometimes there are problems with not consecutive indexes - $attributes = array_values($attributes); - - // scoping makes searches faster! - $scope = (isset($params['scope']) ? $params['scope'] : $this->_config['scope']); - - switch ($scope) { - case 'one': - $search_function = 'ldap_list'; - break; - case 'base': - $search_function = 'ldap_read'; - break; - default: - $search_function = 'ldap_search'; - } - - // Continue attempting the search operation until we get a success - // or a definitive failure. - while (true) { - $link = $this->getLink(); - $search = @call_user_func($search_function, - $link, - $base, - $filter, - $attributes, - $attrsonly, - $sizelimit, - $timelimit); - - if ($err = @ldap_errno($link)) { - if ($err == 32) { - // Errorcode 32 = no such object, i.e. a nullresult. - return $obj = new Net_LDAP2_Search ($search, $this, $attributes); - } elseif ($err == 4) { - // Errorcode 4 = sizelimit exeeded. - return $obj = new Net_LDAP2_Search ($search, $this, $attributes); - } elseif ($err == 87) { - // bad search filter - return $this->raiseError($this->errorMessage($err) . "($filter)", $err); - } elseif (($err == 1) && ($this->_config['auto_reconnect'])) { - // Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect. - $this->_link = false; - $this->performReconnect(); - } else { - $msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope"; - return $this->raiseError($this->errorMessage($err) . $msg, $err); - } - } else { - return $obj = new Net_LDAP2_Search($search, $this, $attributes); - } - } - } - - /** - * Set an LDAP option - * - * @param string $option Option to set - * @param mixed $value Value to set Option to - * - * @access public - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - */ - public function setOption($option, $value) - { - if ($this->_link) { - if (defined($option)) { - if (@ldap_set_option($this->_link, constant($option), $value)) { - return true; - } else { - $err = @ldap_errno($this->_link); - if ($err) { - $msg = @ldap_err2str($err); - } else { - $err = NET_LDAP2_ERROR; - $msg = $this->errorMessage($err); - } - return $this->raiseError($msg, $err); - } - } else { - return $this->raiseError("Unkown Option requested"); - } - } else { - return $this->raiseError("Could not set LDAP option: No LDAP connection"); - } - } - - /** - * Get an LDAP option value - * - * @param string $option Option to get - * - * @access public - * @return Net_LDAP2_Error|string Net_LDAP2_Error or option value - */ - public function getOption($option) - { - if ($this->_link) { - if (defined($option)) { - if (@ldap_get_option($this->_link, constant($option), $value)) { - return $value; - } else { - $err = @ldap_errno($this->_link); - if ($err) { - $msg = @ldap_err2str($err); - } else { - $err = NET_LDAP2_ERROR; - $msg = $this->errorMessage($err); - } - return $this->raiseError($msg, $err); - } - } else { - $this->raiseError("Unkown Option requested"); - } - } else { - $this->raiseError("No LDAP connection"); - } - } - - /** - * Get the LDAP_PROTOCOL_VERSION that is used on the connection. - * - * A lot of ldap functionality is defined by what protocol version the ldap server speaks. - * This might be 2 or 3. - * - * @return int - */ - public function getLDAPVersion() - { - if ($this->_link) { - $version = $this->getOption("LDAP_OPT_PROTOCOL_VERSION"); - } else { - $version = $this->_config['version']; - } - return $version; - } - - /** - * Set the LDAP_PROTOCOL_VERSION that is used on the connection. - * - * @param int $version LDAP-version that should be used - * @param boolean $force If set to true, the check against the rootDSE will be skipped - * - * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true - * @todo Checking via the rootDSE takes much time - why? fetching and instanciation is quick! - */ - public function setLDAPVersion($version = 0, $force = false) - { - if (!$version) { - $version = $this->_config['version']; - } - - // - // Check to see if the server supports this version first. - // - // Todo: Why is this so horribly slow? - // $this->rootDse() is very fast, as well as Net_LDAP2_RootDSE::fetch() - // seems like a problem at copiyng the object inside PHP?? - // Additionally, this is not always reproducable... - // - if (!$force) { - $rootDSE = $this->rootDse(); - if ($rootDSE instanceof Net_LDAP2_Error) { - return $rootDSE; - } else { - $supported_versions = $rootDSE->getValue('supportedLDAPVersion'); - if (is_string($supported_versions)) { - $supported_versions = array($supported_versions); - } - $check_ok = in_array($version, $supported_versions); - } - } - - if ($force || $check_ok) { - return $this->setOption("LDAP_OPT_PROTOCOL_VERSION", $version); - } else { - return $this->raiseError("LDAP Server does not support protocol version " . $version); - } - } - - - /** - * Tells if a DN does exist in the directory - * - * @param string|Net_LDAP2_Entry $dn The DN of the object to test - * - * @return boolean|Net_LDAP2_Error - */ - public function dnExists($dn) - { - if (PEAR::isError($dn)) { - return $dn; - } - if ($dn instanceof Net_LDAP2_Entry) { - $dn = $dn->dn(); - } - if (false === is_string($dn)) { - return PEAR::raiseError('Parameter $dn is not a string nor an entry object!'); - } - - // make dn relative to parent - $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false)); - if (self::isError($base)) { - return $base; - } - $entry_rdn = array_shift($base); - if (is_array($entry_rdn)) { - // maybe the dn consist of a multivalued RDN, we must build the dn in this case - // because the $entry_rdn is an array! - $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn); - } - $base = Net_LDAP2_Util::canonical_dn($base); - - $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1); - if (@ldap_count_entries($this->_link, $result)) { - return true; - } - if (ldap_errno($this->_link) == 32) { - return false; - } - if (ldap_errno($this->_link) != 0) { - return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link)); - } - return false; - } - - - /** - * Get a specific entry based on the DN - * - * @param string $dn DN of the entry that should be fetched - * @param array $attr Array of Attributes to select. If ommitted, all attributes are fetched. - * - * @return Net_LDAP2_Entry|Net_LDAP2_Error Reference to a Net_LDAP2_Entry object or Net_LDAP2_Error object - * @todo Maybe check against the shema should be done to be sure the attribute type exists - */ - public function &getEntry($dn, $attr = array()) - { - if (!is_array($attr)) { - $attr = array($attr); - } - $result = $this->search($dn, '(objectClass=*)', - array('scope' => 'base', 'attributes' => $attr)); - if (self::isError($result)) { - return $result; - } elseif ($result->count() == 0) { - return PEAR::raiseError('Could not fetch entry '.$dn.': no entry found'); - } - $entry = $result->shiftEntry(); - if (false == $entry) { - return PEAR::raiseError('Could not fetch entry (error retrieving entry from search result)'); - } - return $entry; - } - - /** - * Rename or move an entry - * - * This method will instantly carry out an update() after the move, - * so the entry is moved instantly. - * You can pass an optional Net_LDAP2 object. In this case, a cross directory - * move will be performed which deletes the entry in the source (THIS) directory - * and adds it in the directory $target_ldap. - * A cross directory move will switch the Entrys internal LDAP reference so - * updates to the entry will go to the new directory. - * - * Note that if you want to do a cross directory move, you need to - * pass an Net_LDAP2_Entry object, otherwise the attributes will be empty. - * - * @param string|Net_LDAP2_Entry $entry Entry DN or Entry object - * @param string $newdn New location - * @param Net_LDAP2 $target_ldap (optional) Target directory for cross server move; should be passed via reference - * - * @return Net_LDAP2_Error|true - */ - public function move($entry, $newdn, $target_ldap = null) - { - if (is_string($entry)) { - $entry_o = $this->getEntry($entry); - } else { - $entry_o =& $entry; - } - if (!$entry_o instanceof Net_LDAP2_Entry) { - return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object! (If DN was passed, conversion failed)'); - } - if (null !== $target_ldap && !$target_ldap instanceof Net_LDAP2) { - return PEAR::raiseError('Parameter $target_ldap is expected to be a Net_LDAP2 object!'); - } - - if ($target_ldap && $target_ldap !== $this) { - // cross directory move - if (is_string($entry)) { - return PEAR::raiseError('Unable to perform cross directory move: operation requires a Net_LDAP2_Entry object'); - } - if ($target_ldap->dnExists($newdn)) { - return PEAR::raiseError('Unable to perform cross directory move: entry does exist in target directory'); - } - $entry_o->dn($newdn); - $res = $target_ldap->add($entry_o); - if (self::isError($res)) { - return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in target directory'); - } - $res = $this->delete($entry_o->currentDN()); - if (self::isError($res)) { - $res2 = $target_ldap->delete($entry_o); // undo add - if (self::isError($res2)) { - $add_error_string = 'Additionally, the deletion (undo add) of $entry in target directory failed.'; - } - return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in source directory. '.$add_error_string); - } - $entry_o->setLDAP($target_ldap); - return true; - } else { - // local move - $entry_o->dn($newdn); - $entry_o->setLDAP($this); - return $entry_o->update(); - } - } - - /** - * Copy an entry to a new location - * - * The entry will be immediately copied. - * Please note that only attributes you have - * selected will be copied. - * - * @param Net_LDAP2_Entry &$entry Entry object - * @param string $newdn New FQF-DN of the entry - * - * @return Net_LDAP2_Error|Net_LDAP2_Entry Error Message or reference to the copied entry - */ - public function ©(&$entry, $newdn) - { - if (!$entry instanceof Net_LDAP2_Entry) { - return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object!'); - } - - $newentry = Net_LDAP2_Entry::createFresh($newdn, $entry->getValues()); - $result = $this->add($newentry); - - if ($result instanceof Net_LDAP2_Error) { - return $result; - } else { - return $newentry; - } - } - - - /** - * Returns the string for an ldap errorcode. - * - * Made to be able to make better errorhandling - * Function based on DB::errorMessage() - * Tip: The best description of the errorcodes is found here: - * http://www.directory-info.com/LDAP2/LDAPErrorCodes.html - * - * @param int $errorcode Error code - * - * @return string The errorstring for the error. - */ - public function errorMessage($errorcode) - { - $errorMessages = array( - 0x00 => "LDAP_SUCCESS", - 0x01 => "LDAP_OPERATIONS_ERROR", - 0x02 => "LDAP_PROTOCOL_ERROR", - 0x03 => "LDAP_TIMELIMIT_EXCEEDED", - 0x04 => "LDAP_SIZELIMIT_EXCEEDED", - 0x05 => "LDAP_COMPARE_FALSE", - 0x06 => "LDAP_COMPARE_TRUE", - 0x07 => "LDAP_AUTH_METHOD_NOT_SUPPORTED", - 0x08 => "LDAP_STRONG_AUTH_REQUIRED", - 0x09 => "LDAP_PARTIAL_RESULTS", - 0x0a => "LDAP_REFERRAL", - 0x0b => "LDAP_ADMINLIMIT_EXCEEDED", - 0x0c => "LDAP_UNAVAILABLE_CRITICAL_EXTENSION", - 0x0d => "LDAP_CONFIDENTIALITY_REQUIRED", - 0x0e => "LDAP_SASL_BIND_INPROGRESS", - 0x10 => "LDAP_NO_SUCH_ATTRIBUTE", - 0x11 => "LDAP_UNDEFINED_TYPE", - 0x12 => "LDAP_INAPPROPRIATE_MATCHING", - 0x13 => "LDAP_CONSTRAINT_VIOLATION", - 0x14 => "LDAP_TYPE_OR_VALUE_EXISTS", - 0x15 => "LDAP_INVALID_SYNTAX", - 0x20 => "LDAP_NO_SUCH_OBJECT", - 0x21 => "LDAP_ALIAS_PROBLEM", - 0x22 => "LDAP_INVALID_DN_SYNTAX", - 0x23 => "LDAP_IS_LEAF", - 0x24 => "LDAP_ALIAS_DEREF_PROBLEM", - 0x30 => "LDAP_INAPPROPRIATE_AUTH", - 0x31 => "LDAP_INVALID_CREDENTIALS", - 0x32 => "LDAP_INSUFFICIENT_ACCESS", - 0x33 => "LDAP_BUSY", - 0x34 => "LDAP_UNAVAILABLE", - 0x35 => "LDAP_UNWILLING_TO_PERFORM", - 0x36 => "LDAP_LOOP_DETECT", - 0x3C => "LDAP_SORT_CONTROL_MISSING", - 0x3D => "LDAP_INDEX_RANGE_ERROR", - 0x40 => "LDAP_NAMING_VIOLATION", - 0x41 => "LDAP_OBJECT_CLASS_VIOLATION", - 0x42 => "LDAP_NOT_ALLOWED_ON_NONLEAF", - 0x43 => "LDAP_NOT_ALLOWED_ON_RDN", - 0x44 => "LDAP_ALREADY_EXISTS", - 0x45 => "LDAP_NO_OBJECT_CLASS_MODS", - 0x46 => "LDAP_RESULTS_TOO_LARGE", - 0x47 => "LDAP_AFFECTS_MULTIPLE_DSAS", - 0x50 => "LDAP_OTHER", - 0x51 => "LDAP_SERVER_DOWN", - 0x52 => "LDAP_LOCAL_ERROR", - 0x53 => "LDAP_ENCODING_ERROR", - 0x54 => "LDAP_DECODING_ERROR", - 0x55 => "LDAP_TIMEOUT", - 0x56 => "LDAP_AUTH_UNKNOWN", - 0x57 => "LDAP_FILTER_ERROR", - 0x58 => "LDAP_USER_CANCELLED", - 0x59 => "LDAP_PARAM_ERROR", - 0x5a => "LDAP_NO_MEMORY", - 0x5b => "LDAP_CONNECT_ERROR", - 0x5c => "LDAP_NOT_SUPPORTED", - 0x5d => "LDAP_CONTROL_NOT_FOUND", - 0x5e => "LDAP_NO_RESULTS_RETURNED", - 0x5f => "LDAP_MORE_RESULTS_TO_RETURN", - 0x60 => "LDAP_CLIENT_LOOP", - 0x61 => "LDAP_REFERRAL_LIMIT_EXCEEDED", - 1000 => "Unknown Net_LDAP2 Error" - ); - - return isset($errorMessages[$errorcode]) ? - $errorMessages[$errorcode] : - $errorMessages[NET_LDAP2_ERROR] . ' (' . $errorcode . ')'; - } - - /** - * Gets a rootDSE object - * - * This either fetches a fresh rootDSE object or returns it from - * the internal cache for performance reasons, if possible. - * - * @param array $attrs Array of attributes to search for - * - * @access public - * @return Net_LDAP2_Error|Net_LDAP2_RootDSE Net_LDAP2_Error or Net_LDAP2_RootDSE object - */ - public function &rootDse($attrs = null) - { - if ($attrs !== null && !is_array($attrs)) { - return PEAR::raiseError('Parameter $attr is expected to be an array!'); - } - - $attrs_signature = serialize($attrs); - - // see if we need to fetch a fresh object, or if we already - // requested this object with the same attributes - if (true || !array_key_exists($attrs_signature, $this->_rootDSE_cache)) { - $rootdse =& Net_LDAP2_RootDSE::fetch($this, $attrs); - if ($rootdse instanceof Net_LDAP2_Error) { - return $rootdse; - } - - // search was ok, store rootDSE in cache - $this->_rootDSE_cache[$attrs_signature] = $rootdse; - } - return $this->_rootDSE_cache[$attrs_signature]; - } - - /** - * Alias function of rootDse() for perl-ldap interface - * - * @access public - * @see rootDse() - * @return Net_LDAP2_Error|Net_LDAP2_RootDSE - */ - public function &root_dse() - { - $args = func_get_args(); - return call_user_func_array(array(&$this, 'rootDse'), $args); - } - - /** - * Get a schema object - * - * @param string $dn (optional) Subschema entry dn - * - * @access public - * @return Net_LDAP2_Schema|Net_LDAP2_Error Net_LDAP2_Schema or Net_LDAP2_Error object - */ - public function &schema($dn = null) - { - // Schema caching by Knut-Olav Hoven - // If a schema caching object is registered, we use that to fetch - // a schema object. - // See registerSchemaCache() for more info on this. - if ($this->_schema === null) { - if ($this->_schema_cache) { - $cached_schema = $this->_schema_cache->loadSchema(); - if ($cached_schema instanceof Net_LDAP2_Error) { - return $cached_schema; // route error to client - } else { - if ($cached_schema instanceof Net_LDAP2_Schema) { - $this->_schema = $cached_schema; - } - } - } - } - - // Fetch schema, if not tried before and no cached version available. - // If we are already fetching the schema, we will skip fetching. - if ($this->_schema === null) { - // store a temporary error message so subsequent calls to schema() can - // detect, that we are fetching the schema already. - // Otherwise we will get an infinite loop at Net_LDAP2_Schema::fetch() - $this->_schema = new Net_LDAP2_Error('Schema not initialized'); - $this->_schema = Net_LDAP2_Schema::fetch($this, $dn); - - // If schema caching is active, advise the cache to store the schema - if ($this->_schema_cache) { - $caching_result = $this->_schema_cache->storeSchema($this->_schema); - if ($caching_result instanceof Net_LDAP2_Error) { - return $caching_result; // route error to client - } - } - } - return $this->_schema; - } - - /** - * Enable/disable persistent schema caching - * - * Sometimes it might be useful to allow your scripts to cache - * the schema information on disk, so the schema is not fetched - * every time the script runs which could make your scripts run - * faster. - * - * This method allows you to register a custom object that - * implements your schema cache. Please see the SchemaCache interface - * (SchemaCache.interface.php) for informations on how to implement this. - * To unregister the cache, pass null as $cache parameter. - * - * For ease of use, Net_LDAP2 provides a simple file based cache - * which is used in the example below. You may use this, for example, - * to store the schema in a linux tmpfs which results in the schema - * beeing cached inside the RAM which allows nearly instant access. - * - * // Create the simple file cache object that comes along with Net_LDAP2 - * $mySchemaCache_cfg = array( - * 'path' => '/tmp/Net_LDAP2_Schema.cache', - * 'max_age' => 86400 // max age is 24 hours (in seconds) - * ); - * $mySchemaCache = new Net_LDAP2_SimpleFileSchemaCache($mySchemaCache_cfg); - * $ldap = new Net_LDAP2::connect(...); - * $ldap->registerSchemaCache($mySchemaCache); // enable caching - * // now each call to $ldap->schema() will get the schema from disk! - * - * - * @param Net_LDAP2_SchemaCache|null $cache Object implementing the Net_LDAP2_SchemaCache interface - * - * @return true|Net_LDAP2_Error - */ - public function registerSchemaCache($cache) { - if (is_null($cache) - || (is_object($cache) && in_array('Net_LDAP2_SchemaCache', class_implements($cache))) ) { - $this->_schema_cache = $cache; - return true; - } else { - return new Net_LDAP2_Error('Custom schema caching object is either no '. - 'valid object or does not implement the Net_LDAP2_SchemaCache interface!'); - } - } - - - /** - * Checks if phps ldap-extension is loaded - * - * If it is not loaded, it tries to load it manually using PHPs dl(). - * It knows both windows-dll and *nix-so. - * - * @static - * @return Net_LDAP2_Error|true - */ - public static function checkLDAPExtension() - { - if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { - return new Net_LDAP2_Error("It seems that you do not have the ldap-extension installed. Please install it before using the Net_LDAP2 package."); - } else { - return true; - } - } - - /** - * Encodes given attributes to UTF8 if needed by schema - * - * This function takes attributes in an array and then checks against the schema if they need - * UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and - * can be used for adding or modifying. - * - * $attributes is expected to be an array with keys describing - * the attribute names and the values as the value of this attribute: - * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); - * - * @param array $attributes Array of attributes - * - * @access public - * @return array|Net_LDAP2_Error Array of UTF8 encoded attributes or Error - */ - public function utf8Encode($attributes) - { - return $this->utf8($attributes, 'utf8_encode'); - } - - /** - * Decodes the given attribute values if needed by schema - * - * $attributes is expected to be an array with keys describing - * the attribute names and the values as the value of this attribute: - * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); - * - * @param array $attributes Array of attributes - * - * @access public - * @see utf8Encode() - * @return array|Net_LDAP2_Error Array with decoded attribute values or Error - */ - public function utf8Decode($attributes) - { - return $this->utf8($attributes, 'utf8_decode'); - } - - /** - * Encodes or decodes attribute values if needed - * - * @param array $attributes Array of attributes - * @param array $function Function to apply to attribute values - * - * @access protected - * @return array|Net_LDAP2_Error Array of attributes with function applied to values or Error - */ - protected function utf8($attributes, $function) - { - if (!is_array($attributes) || array_key_exists(0, $attributes)) { - return PEAR::raiseError('Parameter $attributes is expected to be an associative array'); - } - - if (!$this->_schema) { - $this->_schema = $this->schema(); - } - - if (!$this->_link || self::isError($this->_schema) || !function_exists($function)) { - return $attributes; - } - - if (is_array($attributes) && count($attributes) > 0) { - - foreach ($attributes as $k => $v) { - - if (!isset($this->_schemaAttrs[$k])) { - - $attr = $this->_schema->get('attribute', $k); - if (self::isError($attr)) { - continue; - } - - if (false !== strpos($attr['syntax'], '1.3.6.1.4.1.1466.115.121.1.15')) { - $encode = true; - } else { - $encode = false; - } - $this->_schemaAttrs[$k] = $encode; - - } else { - $encode = $this->_schemaAttrs[$k]; - } - - if ($encode) { - if (is_array($v)) { - foreach ($v as $ak => $av) { - $v[$ak] = call_user_func($function, $av); - } - } else { - $v = call_user_func($function, $v); - } - } - $attributes[$k] = $v; - } - } - return $attributes; - } - - /** - * Get the LDAP link resource. It will loop attempting to - * re-establish the connection if the connection attempt fails and - * auto_reconnect has been turned on (see the _config array documentation). - * - * @access public - * @return resource LDAP link - */ - public function &getLink() - { - if ($this->_config['auto_reconnect']) { - while (true) { - // - // Return the link handle if we are already connected. Otherwise - // try to reconnect. - // - if ($this->_link !== false) { - return $this->_link; - } else { - $this->performReconnect(); - } - } - } - return $this->_link; - } -} - -/** -* Net_LDAP2_Error implements a class for reporting portable LDAP error messages. -* -* @category Net -* @package Net_LDAP2 -* @author Tarjej Huse -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP22/ -*/ -class Net_LDAP2_Error extends PEAR_Error -{ - /** - * Net_LDAP2_Error constructor. - * - * @param string $message String with error message. - * @param integer $code Net_LDAP2 error code - * @param integer $mode what "error mode" to operate in - * @param mixed $level what error level to use for $mode & PEAR_ERROR_TRIGGER - * @param mixed $debuginfo additional debug info, such as the last query - * - * @access public - * @see PEAR_Error - */ - public function __construct($message = 'Net_LDAP2_Error', $code = NET_LDAP2_ERROR, $mode = PEAR_ERROR_RETURN, - $level = E_USER_NOTICE, $debuginfo = null) - { - if (is_int($code)) { - $this->PEAR_Error($message . ': ' . Net_LDAP2::errorMessage($code), $code, $mode, $level, $debuginfo); - } else { - $this->PEAR_Error("$message: $code", NET_LDAP2_ERROR, $mode, $level, $debuginfo); - } - } -} - -?> diff --git a/extlib/Net/LDAP2/Entry.php b/extlib/Net/LDAP2/Entry.php deleted file mode 100644 index 66de96678..000000000 --- a/extlib/Net/LDAP2/Entry.php +++ /dev/null @@ -1,1055 +0,0 @@ - -* @author Tarjej Huse -* @author Benedikt Hallinger -* @copyright 2009 Tarjej Huse, Jan Wagner, Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: Entry.php 286787 2009-08-04 06:03:12Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; -require_once 'Util.php'; - -/** -* Object representation of a directory entry -* -* This class represents a directory entry. You can add, delete, replace -* attributes and their values, rename the entry, delete the entry. -* -* @category Net -* @package Net_LDAP2 -* @author Jan Wagner -* @author Tarjej Huse -* @author Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP2/ -*/ -class Net_LDAP2_Entry extends PEAR -{ - /** - * Entry ressource identifier - * - * @access protected - * @var ressource - */ - protected $_entry = null; - - /** - * LDAP ressource identifier - * - * @access protected - * @var ressource - */ - protected $_link = null; - - /** - * Net_LDAP2 object - * - * This object will be used for updating and schema checking - * - * @access protected - * @var object Net_LDAP2 - */ - protected $_ldap = null; - - /** - * Distinguished name of the entry - * - * @access protected - * @var string - */ - protected $_dn = null; - - /** - * Attributes - * - * @access protected - * @var array - */ - protected $_attributes = array(); - - /** - * Original attributes before any modification - * - * @access protected - * @var array - */ - protected $_original = array(); - - - /** - * Map of attribute names - * - * @access protected - * @var array - */ - protected $_map = array(); - - - /** - * Is this a new entry? - * - * @access protected - * @var boolean - */ - protected $_new = true; - - /** - * New distinguished name - * - * @access protected - * @var string - */ - protected $_newdn = null; - - /** - * Shall the entry be deleted? - * - * @access protected - * @var boolean - */ - protected $_delete = false; - - /** - * Map with changes to the entry - * - * @access protected - * @var array - */ - protected $_changes = array("add" => array(), - "delete" => array(), - "replace" => array() - ); - /** - * Internal Constructor - * - * Constructor of the entry. Sets up the distinguished name and the entries - * attributes. - * You should not call this method manually! Use {@link Net_LDAP2_Entry::createFresh()} - * or {@link Net_LDAP2_Entry::createConnected()} instead! - * - * @param Net_LDAP2|ressource|array &$ldap Net_LDAP2 object, ldap-link ressource or array of attributes - * @param string|ressource $entry Either a DN or a LDAP-Entry ressource - * - * @access protected - * @return none - */ - protected function __construct(&$ldap, $entry = null) - { - $this->PEAR('Net_LDAP2_Error'); - - // set up entry resource or DN - if (is_resource($entry)) { - $this->_entry = &$entry; - } else { - $this->_dn = $entry; - } - - // set up LDAP link - if ($ldap instanceof Net_LDAP2) { - $this->_ldap = &$ldap; - $this->_link = $ldap->getLink(); - } elseif (is_resource($ldap)) { - $this->_link = $ldap; - } elseif (is_array($ldap)) { - // Special case: here $ldap is an array of attributes, - // this means, we have no link. This is a "virtual" entry. - // We just set up the attributes so one can work with the object - // as expected, but an update() fails unless setLDAP() is called. - $this->setAttributes($ldap); - } - - // if this is an entry existing in the directory, - // then set up as old and fetch attrs - if (is_resource($this->_entry) && is_resource($this->_link)) { - $this->_new = false; - $this->_dn = @ldap_get_dn($this->_link, $this->_entry); - $this->setAttributes(); // fetch attributes from server - } - } - - /** - * Creates a fresh entry that may be added to the directory later on - * - * Use this method, if you want to initialize a fresh entry. - * - * The method should be called statically: $entry = Net_LDAP2_Entry::createFresh(); - * You should put a 'objectClass' attribute into the $attrs so the directory server - * knows which object you want to create. However, you may omit this in case you - * don't want to add this entry to a directory server. - * - * The attributes parameter is as following: - * - * $attrs = array( 'attribute1' => array('value1', 'value2'), - * 'attribute2' => 'single value' - * ); - * - * - * @param string $dn DN of the Entry - * @param array $attrs Attributes of the entry - * - * @static - * @return Net_LDAP2_Entry|Net_LDAP2_Error - */ - public static function createFresh($dn, $attrs = array()) - { - if (!is_array($attrs)) { - return PEAR::raiseError("Unable to create fresh entry: Parameter \$attrs needs to be an array!"); - } - - $entry = new Net_LDAP2_Entry($attrs, $dn); - return $entry; - } - - /** - * Creates a Net_LDAP2_Entry object out of an ldap entry resource - * - * Use this method, if you want to initialize an entry object that is - * already present in some directory and that you have read manually. - * - * Please note, that if you want to create an entry object that represents - * some already existing entry, you should use {@link createExisting()}. - * - * The method should be called statically: $entry = Net_LDAP2_Entry::createConnected(); - * - * @param Net_LDAP2 $ldap Net_LDA2 object - * @param resource $entry PHP LDAP entry resource - * - * @static - * @return Net_LDAP2_Entry|Net_LDAP2_Error - */ - public static function createConnected($ldap, $entry) - { - if (!$ldap instanceof Net_LDAP2) { - return PEAR::raiseError("Unable to create connected entry: Parameter \$ldap needs to be a Net_LDAP2 object!"); - } - if (!is_resource($entry)) { - return PEAR::raiseError("Unable to create connected entry: Parameter \$entry needs to be a ldap entry resource!"); - } - - $entry = new Net_LDAP2_Entry($ldap, $entry); - return $entry; - } - - /** - * Creates an Net_LDAP2_Entry object that is considered already existing - * - * Use this method, if you want to modify an already existing entry - * without fetching it first. - * In most cases however, it is better to fetch the entry via Net_LDAP2->getEntry()! - * - * Please note that you should take care if you construct entries manually with this - * because you may get weird synchronisation problems. - * The attributes and values as well as the entry itself are considered existent - * which may produce errors if you try to modify an entry which doesn't really exist - * or if you try to overwrite some attribute with an value already present. - * - * This method is equal to calling createFresh() and after that markAsNew(FALSE). - * - * The method should be called statically: $entry = Net_LDAP2_Entry::createExisting(); - * - * The attributes parameter is as following: - * - * $attrs = array( 'attribute1' => array('value1', 'value2'), - * 'attribute2' => 'single value' - * ); - * - * - * @param string $dn DN of the Entry - * @param array $attrs Attributes of the entry - * - * @static - * @return Net_LDAP2_Entry|Net_LDAP2_Error - */ - public static function createExisting($dn, $attrs = array()) - { - if (!is_array($attrs)) { - return PEAR::raiseError("Unable to create entry object: Parameter \$attrs needs to be an array!"); - } - - $entry = Net_LDAP2_Entry::createFresh($dn, $attrs); - if ($entry instanceof Net_LDAP2_Error) { - return $entry; - } else { - $entry->markAsNew(false); - return $entry; - } - } - - /** - * Get or set the distinguished name of the entry - * - * If called without an argument the current (or the new DN if set) DN gets returned. - * If you provide an DN, this entry is moved to the new location specified if a DN existed. - * If the DN was not set, the DN gets initialized. Call {@link update()} to actually create - * the new Entry in the directory. - * To fetch the current active DN after setting a new DN but before an update(), you can use - * {@link currentDN()} to retrieve the DN that is currently active. - * - * Please note that special characters (eg german umlauts) should be encoded using utf8_encode(). - * You may use {@link Net_LDAP2_Util::canonical_dn()} for properly encoding of the DN. - * - * @param string $dn New distinguished name - * - * @access public - * @return string|true Distinguished name (or true if a new DN was provided) - */ - public function dn($dn = null) - { - if (false == is_null($dn)) { - if (is_null($this->_dn)) { - $this->_dn = $dn; - } else { - $this->_newdn = $dn; - } - return true; - } - return (isset($this->_newdn) ? $this->_newdn : $this->currentDN()); - } - - /** - * Renames or moves the entry - * - * This is just a convinience alias to {@link dn()} - * to make your code more meaningful. - * - * @param string $newdn The new DN - * - * @return true - */ - public function move($newdn) - { - return $this->dn($newdn); - } - - /** - * Sets the internal attributes array - * - * This fetches the values for the attributes from the server. - * The attribute Syntax will be checked so binary attributes will be returned - * as binary values. - * - * Attributes may be passed directly via the $attributes parameter to setup this - * entry manually. This overrides attribute fetching from the server. - * - * @param array $attributes Attributes to set for this entry - * - * @access protected - * @return void - */ - protected function setAttributes($attributes = null) - { - /* - * fetch attributes from the server - */ - if (is_null($attributes) && is_resource($this->_entry) && is_resource($this->_link)) { - // fetch schema - if ($this->_ldap instanceof Net_LDAP2) { - $schema =& $this->_ldap->schema(); - } - // fetch attributes - $attributes = array(); - do { - if (empty($attr)) { - $ber = null; - $attr = @ldap_first_attribute($this->_link, $this->_entry, $ber); - } else { - $attr = @ldap_next_attribute($this->_link, $this->_entry, $ber); - } - if ($attr) { - $func = 'ldap_get_values'; // standard function to fetch value - - // Try to get binary values as binary data - if ($schema instanceof Net_LDAP2_Schema) { - if ($schema->isBinary($attr)) { - $func = 'ldap_get_values_len'; - } - } - // fetch attribute value (needs error checking?) - $attributes[$attr] = $func($this->_link, $this->_entry, $attr); - } - } while ($attr); - } - - /* - * set attribute data directly, if passed - */ - if (is_array($attributes) && count($attributes) > 0) { - if (isset($attributes["count"]) && is_numeric($attributes["count"])) { - unset($attributes["count"]); - } - foreach ($attributes as $k => $v) { - // attribute names should not be numeric - if (is_numeric($k)) { - continue; - } - // map generic attribute name to real one - $this->_map[strtolower($k)] = $k; - // attribute values should be in an array - if (false == is_array($v)) { - $v = array($v); - } - // remove the value count (comes from ldap server) - if (isset($v["count"])) { - unset($v["count"]); - } - $this->_attributes[$k] = $v; - } - } - - // save a copy for later use - $this->_original = $this->_attributes; - } - - /** - * Get the values of all attributes in a hash - * - * The returned hash has the form - * array('attributename' => 'single value', - * 'attributename' => array('value1', value2', value3')) - * - * @access public - * @return array Hash of all attributes with their values - */ - public function getValues() - { - $attrs = array(); - foreach ($this->_attributes as $attr => $value) { - $attrs[$attr] = $this->getValue($attr); - } - return $attrs; - } - - /** - * Get the value of a specific attribute - * - * The first parameter is the name of the attribute - * The second parameter influences the way the value is returned: - * 'single': only the first value is returned as string - * 'all': all values including the value count are returned in an - * array - * 'default': in all other cases an attribute value with a single value is - * returned as string, if it has multiple values it is returned - * as an array (without value count) - * - * @param string $attr Attribute name - * @param string $option Option - * - * @access public - * @return string|array|PEAR_Error string, array or PEAR_Error - */ - public function getValue($attr, $option = null) - { - $attr = $this->getAttrName($attr); - - if (false == array_key_exists($attr, $this->_attributes)) { - return PEAR::raiseError("Unknown attribute ($attr) requested"); - } - - $value = $this->_attributes[$attr]; - - if ($option == "single" || (count($value) == 1 && $option != 'all')) { - $value = array_shift($value); - } - - return $value; - } - - /** - * Alias function of getValue for perl-ldap interface - * - * @see getValue() - * @return string|array|PEAR_Error - */ - public function get_value() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'getValue' ), $args); - } - - /** - * Returns an array of attributes names - * - * @access public - * @return array Array of attribute names - */ - public function attributes() - { - return array_keys($this->_attributes); - } - - /** - * Returns whether an attribute exists or not - * - * @param string $attr Attribute name - * - * @access public - * @return boolean - */ - public function exists($attr) - { - $attr = $this->getAttrName($attr); - return array_key_exists($attr, $this->_attributes); - } - - /** - * Adds a new attribute or a new value to an existing attribute - * - * The paramter has to be an array of the form: - * array('attributename' => 'single value', - * 'attributename' => array('value1', 'value2)) - * When the attribute already exists the values will be added, else the - * attribute will be created. These changes are local to the entry and do - * not affect the entry on the server until update() is called. - * - * Note, that you can add values of attributes that you haven't selected, but if - * you do so, {@link getValue()} and {@link getValues()} will only return the - * values you added, _NOT_ all values present on the server. To avoid this, just refetch - * the entry after calling {@link update()} or select the attribute. - * - * @param array $attr Attributes to add - * - * @access public - * @return true|Net_LDAP2_Error - */ - public function add($attr = array()) - { - if (false == is_array($attr)) { - return PEAR::raiseError("Parameter must be an array"); - } - foreach ($attr as $k => $v) { - $k = $this->getAttrName($k); - if (false == is_array($v)) { - // Do not add empty values - if ($v == null) { - continue; - } else { - $v = array($v); - } - } - // add new values to existing attribute or add new attribute - if ($this->exists($k)) { - $this->_attributes[$k] = array_unique(array_merge($this->_attributes[$k], $v)); - } else { - $this->_map[strtolower($k)] = $k; - $this->_attributes[$k] = $v; - } - // save changes for update() - if (empty($this->_changes["add"][$k])) { - $this->_changes["add"][$k] = array(); - } - $this->_changes["add"][$k] = array_unique(array_merge($this->_changes["add"][$k], $v)); - } - $return = true; - return $return; - } - - /** - * Deletes an whole attribute or a value or the whole entry - * - * The parameter can be one of the following: - * - * "attributename" - The attribute as a whole will be deleted - * array("attributename1", "attributename2) - All given attributes will be - * deleted - * array("attributename" => "value") - The value will be deleted - * array("attributename" => array("value1", "value2") - The given values - * will be deleted - * If $attr is null or omitted , then the whole Entry will be deleted! - * - * These changes are local to the entry and do - * not affect the entry on the server until {@link update()} is called. - * - * Please note that you must select the attribute (at $ldap->search() for example) - * to be able to delete values of it, Otherwise {@link update()} will silently fail - * and remove nothing. - * - * @param string|array $attr Attributes to delete (NULL or missing to delete whole entry) - * - * @access public - * @return true - */ - public function delete($attr = null) - { - if (is_null($attr)) { - $this->_delete = true; - return true; - } - if (is_string($attr)) { - $attr = array($attr); - } - // Make the assumption that attribute names cannot be numeric, - // therefore this has to be a simple list of attribute names to delete - if (is_numeric(key($attr))) { - foreach ($attr as $name) { - if (is_array($name)) { - // someone mixed modes (list mode but specific values given!) - $del_attr_name = array_search($name, $attr); - $this->delete(array($del_attr_name => $name)); - } else { - // mark for update() if this attr was not marked before - $name = $this->getAttrName($name); - if ($this->exists($name)) { - $this->_changes["delete"][$name] = null; - unset($this->_attributes[$name]); - } - } - } - } else { - // Here we have a hash with "attributename" => "value to delete" - foreach ($attr as $name => $values) { - if (is_int($name)) { - // someone mixed modes and gave us just an attribute name - $this->delete($values); - } else { - // mark for update() if this attr was not marked before; - // this time it must consider the selected values also - $name = $this->getAttrName($name); - if ($this->exists($name)) { - if (false == is_array($values)) { - $values = array($values); - } - // save values to be deleted - if (empty($this->_changes["delete"][$name])) { - $this->_changes["delete"][$name] = array(); - } - $this->_changes["delete"][$name] = - array_unique(array_merge($this->_changes["delete"][$name], $values)); - foreach ($values as $value) { - // find the key for the value that should be deleted - $key = array_search($value, $this->_attributes[$name]); - if (false !== $key) { - // delete the value - unset($this->_attributes[$name][$key]); - } - } - } - } - } - } - $return = true; - return $return; - } - - /** - * Replaces attributes or its values - * - * The parameter has to an array of the following form: - * array("attributename" => "single value", - * "attribute2name" => array("value1", "value2"), - * "deleteme1" => null, - * "deleteme2" => "") - * If the attribute does not yet exist it will be added instead (see also $force). - * If the attribue value is null, the attribute will de deleted. - * - * These changes are local to the entry and do - * not affect the entry on the server until {@link update()} is called. - * - * In some cases you are not allowed to read the attributes value (for - * example the ActiveDirectory attribute unicodePwd) but are allowed to - * replace the value. In this case replace() would assume that the attribute - * is not in the directory yet and tries to add it which will result in an - * LDAP_TYPE_OR_VALUE_EXISTS error. - * To force replace mode instead of add, you can set $force to true. - * - * @param array $attr Attributes to replace - * @param bool $force Force replacing mode in case we can't read the attr value but are allowed to replace it - * - * @access public - * @return true|Net_LDAP2_Error - */ - public function replace($attr = array(), $force = false) - { - if (false == is_array($attr)) { - return PEAR::raiseError("Parameter must be an array"); - } - foreach ($attr as $k => $v) { - $k = $this->getAttrName($k); - if (false == is_array($v)) { - // delete attributes with empty values; treat ints as string - if (is_int($v)) { - $v = "$v"; - } - if ($v == null) { - $this->delete($k); - continue; - } else { - $v = array($v); - } - } - // existing attributes will get replaced - if ($this->exists($k) || $force) { - $this->_changes["replace"][$k] = $v; - $this->_attributes[$k] = $v; - } else { - // new ones just get added - $this->add(array($k => $v)); - } - } - $return = true; - return $return; - } - - /** - * Update the entry on the directory server - * - * This will evaluate all changes made so far and send them - * to the directory server. - * Please note, that if you make changes to objectclasses wich - * have mandatory attributes set, update() will currently fail. - * Remove the entry from the server and readd it as new in such cases. - * This also will deal with problems with setting structural object classes. - * - * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance - * - * @access public - * @return true|Net_LDAP2_Error - * @todo Entry rename with a DN containing special characters needs testing! - */ - public function update($ldap = null) - { - if ($ldap) { - $msg = $this->setLDAP($ldap); - if (Net_LDAP2::isError($msg)) { - return PEAR::raiseError('You passed an invalid $ldap variable to update()'); - } - } - - // ensure we have a valid LDAP object - $ldap =& $this->getLDAP(); - if (!$ldap instanceof Net_LDAP2) { - return PEAR::raiseError("The entries LDAP object is not valid"); - } - - // Get and check link - $link = $ldap->getLink(); - if (!is_resource($link)) { - return PEAR::raiseError("Could not update entry: internal LDAP link is invalid"); - } - - /* - * Delete the entry - */ - if (true === $this->_delete) { - return $ldap->delete($this); - } - - /* - * New entry - */ - if (true === $this->_new) { - $msg = $ldap->add($this); - if (Net_LDAP2::isError($msg)) { - return $msg; - } - $this->_new = false; - $this->_changes['add'] = array(); - $this->_changes['delete'] = array(); - $this->_changes['replace'] = array(); - $this->_original = $this->_attributes; - - $return = true; - return $return; - } - - /* - * Rename/move entry - */ - if (false == is_null($this->_newdn)) { - if ($ldap->getLDAPVersion() !== 3) { - return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3"); - } - // make dn relative to parent (needed for ldap rename) - $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false)); - if (Net_LDAP2::isError($parent)) { - return $parent; - } - $child = array_shift($parent); - // maybe the dn consist of a multivalued RDN, we must build the dn in this case - // because the $child-RDN is an array! - if (is_array($child)) { - $child = Net_LDAP2_Util::canonical_dn($child); - } - $parent = Net_LDAP2_Util::canonical_dn($parent); - - // rename/move - if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) { - return PEAR::raiseError("Entry not renamed: " . - @ldap_error($link), @ldap_errno($link)); - } - // reflect changes to local copy - $this->_dn = $this->_newdn; - $this->_newdn = null; - } - - /* - * Carry out modifications to the entry - */ - // ADD - foreach ($this->_changes["add"] as $attr => $value) { - // if attribute exists, add new values - if ($this->exists($attr)) { - if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) { - return PEAR::raiseError("Could not add new values to attribute $attr: " . - @ldap_error($link), @ldap_errno($link)); - } - } else { - // new attribute - if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { - return PEAR::raiseError("Could not add new attribute $attr: " . - @ldap_error($link), @ldap_errno($link)); - } - } - // all went well here, I guess - unset($this->_changes["add"][$attr]); - } - - // DELETE - foreach ($this->_changes["delete"] as $attr => $value) { - // In LDAPv3 you need to specify the old values for deleting - if (is_null($value) && $ldap->getLDAPVersion() === 3) { - $value = $this->_original[$attr]; - } - if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) { - return PEAR::raiseError("Could not delete attribute $attr: " . - @ldap_error($link), @ldap_errno($link)); - } - unset($this->_changes["delete"][$attr]); - } - - // REPLACE - foreach ($this->_changes["replace"] as $attr => $value) { - if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { - return PEAR::raiseError("Could not replace attribute $attr values: " . - @ldap_error($link), @ldap_errno($link)); - } - unset($this->_changes["replace"][$attr]); - } - - // all went well, so _original (server) becomes _attributes (local copy) - $this->_original = $this->_attributes; - - $return = true; - return $return; - } - - /** - * Returns the right attribute name - * - * @param string $attr Name of attribute - * - * @access protected - * @return string The right name of the attribute - */ - protected function getAttrName($attr) - { - $name = strtolower($attr); - if (array_key_exists($name, $this->_map)) { - $attr = $this->_map[$name]; - } - return $attr; - } - - /** - * Returns a reference to the LDAP-Object of this entry - * - * @access public - * @return Net_LDAP2|Net_LDAP2_Error Reference to the Net_LDAP2 Object (the connection) or Net_LDAP2_Error - */ - public function &getLDAP() - { - if (!$this->_ldap instanceof Net_LDAP2) { - $err = new PEAR_Error('LDAP is not a valid Net_LDAP2 object'); - return $err; - } else { - return $this->_ldap; - } - } - - /** - * Sets a reference to the LDAP-Object of this entry - * - * After setting a Net_LDAP2 object, calling update() will use that object for - * updating directory contents. Use this to dynamicly switch directorys. - * - * @param Net_LDAP2 &$ldap Net_LDAP2 object that this entry should be connected to - * - * @access public - * @return true|Net_LDAP2_Error - */ - public function setLDAP(&$ldap) - { - if (!$ldap instanceof Net_LDAP2) { - return PEAR::raiseError("LDAP is not a valid Net_LDAP2 object"); - } else { - $this->_ldap =& $ldap; - return true; - } - } - - /** - * Marks the entry as new/existing. - * - * If an Entry is marked as new, it will be added to the directory - * when calling {@link update()}. - * If the entry is marked as old ($mark = false), then the entry is - * assumed to be present in the directory server wich results in - * modification when calling {@link update()}. - * - * @param boolean $mark Value to set, defaults to "true" - * - * @return void - */ - public function markAsNew($mark = true) - { - $this->_new = ($mark)? true : false; - } - - /** - * Applies a regular expression onto a single- or multivalued attribute (like preg_match()) - * - * This method behaves like PHPs preg_match() but with some exceptions. - * If you want to retrieve match information, then you MUST pass the - * $matches parameter via reference! otherwise you will get no matches. - * Since it is possible to have multi valued attributes the $matches - * array will have a additionally numerical dimension (one for each value): - * - * $matches = array( - * 0 => array (usual preg_match() returnarray), - * 1 => array (usual preg_match() returnarray) - * ) - * - * Please note, that $matches will be initialized to an empty array inside. - * - * Usage example: - * - * $result = $entry->preg_match('/089(\d+)/', 'telephoneNumber', &$matches); - * if ( $result === true ){ - * echo "First match: ".$matches[0][1]; // Match of value 1, content of first bracket - * } else { - * if ( Net_LDAP2::isError($result) ) { - * echo "Error: ".$result->getMessage(); - * } else { - * echo "No match found."; - * } - * } - * - * - * Please note that it is important to test for an Net_LDAP2_Error, because objects are - * evaluating to true by default, thus if an error occured, and you only check using "==" then - * you get misleading results. Use the "identical" (===) operator to test for matches to - * avoid this as shown above. - * - * @param string $regex The regular expression - * @param string $attr_name The attribute to search in - * @param array $matches (optional, PASS BY REFERENCE!) Array to store matches in - * - * @return boolean|Net_LDAP2_Error TRUE, if we had a match in one of the values, otherwise false. Net_LDAP2_Error in case something went wrong - */ - public function pregMatch($regex, $attr_name, $matches = array()) - { - $matches = array(); - - // fetch attribute values - $attr = $this->getValue($attr_name, 'all'); - if (Net_LDAP2::isError($attr)) { - return $attr; - } else { - unset($attr['count']); - } - - // perform preg_match() on all values - $match = false; - foreach ($attr as $thisvalue) { - $matches_int = array(); - if (preg_match($regex, $thisvalue, $matches_int)) { - $match = true; - array_push($matches, $matches_int); // store matches in reference - } - } - return $match; - } - - /** - * Alias of {@link pregMatch()} for compatibility to Net_LDAP 1 - * - * @see pregMatch() - * @return boolean|Net_LDAP2_Error - */ - public function preg_match() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'pregMatch' ), $args); - } - - /** - * Tells if the entry is consiedered as new (not present in the server) - * - * Please note, that this doesn't tell you if the entry is present on the server. - * Use {@link Net_LDAP2::dnExists()} to see if an entry is already there. - * - * @return boolean - */ - public function isNew() - { - return $this->_new; - } - - - /** - * Is this entry going to be deleted once update() is called? - * - * @return boolean - */ - public function willBeDeleted() - { - return $this->_delete; - } - - /** - * Is this entry going to be moved once update() is called? - * - * @return boolean - */ - public function willBeMoved() - { - return ($this->dn() !== $this->currentDN()); - } - - /** - * Returns always the original DN - * - * If an entry will be moved but {@link update()} was not called, - * {@link dn()} will return the new DN. This method however, returns - * always the current active DN. - * - * @return string - */ - public function currentDN() - { - return $this->_dn; - } - - /** - * Returns the attribute changes to be carried out once update() is called - * - * @return array - */ - public function getChanges() - { - return $this->_changes; - } -} -?> diff --git a/extlib/Net/LDAP2/Filter.php b/extlib/Net/LDAP2/Filter.php deleted file mode 100644 index 0723edab2..000000000 --- a/extlib/Net/LDAP2/Filter.php +++ /dev/null @@ -1,514 +0,0 @@ - -* @copyright 2009 Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: Filter.php 289978 2009-10-27 09:56:41Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; -require_once 'Util.php'; - -/** -* Object representation of a part of a LDAP filter. -* -* This Class is not completely compatible to the PERL interface! -* -* The purpose of this class is, that users can easily build LDAP filters -* without having to worry about right escaping etc. -* A Filter is built using several independent filter objects -* which are combined afterwards. This object works in two -* modes, depending how the object is created. -* If the object is created using the {@link create()} method, then this is a leaf-object. -* If the object is created using the {@link combine()} method, then this is a container object. -* -* LDAP filters are defined in RFC-2254 and can be found under -* {@link http://www.ietf.org/rfc/rfc2254.txt} -* -* Here a quick copy&paste example: -* -* $filter0 = Net_LDAP2_Filter::create('stars', 'equals', '***'); -* $filter_not0 = Net_LDAP2_Filter::combine('not', $filter0); -* -* $filter1 = Net_LDAP2_Filter::create('gn', 'begins', 'bar'); -* $filter2 = Net_LDAP2_Filter::create('gn', 'ends', 'baz'); -* $filter_comp = Net_LDAP2_Filter::combine('or',array($filter_not0, $filter1, $filter2)); -* -* echo $filter_comp->asString(); -* // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz)) -* // The stars in $filter0 are treaten as real stars unless you disable escaping. -* -* -* @category Net -* @package Net_LDAP2 -* @author Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP2/ -*/ -class Net_LDAP2_Filter extends PEAR -{ - /** - * Storage for combination of filters - * - * This variable holds a array of filter objects - * that should be combined by this filter object. - * - * @access protected - * @var array - */ - protected $_subfilters = array(); - - /** - * Match of this filter - * - * If this is a leaf filter, then a matching rule is stored, - * if it is a container, then it is a logical operator - * - * @access protected - * @var string - */ - protected $_match; - - /** - * Single filter - * - * If we operate in leaf filter mode, - * then the constructing method stores - * the filter representation here - * - * @acces private - * @var string - */ - protected $_filter; - - /** - * Create a new Net_LDAP2_Filter object and parse $filter. - * - * This is for PERL Net::LDAP interface. - * Construction of Net_LDAP2_Filter objects should happen through either - * {@link create()} or {@link combine()} which give you more control. - * However, you may use the perl iterface if you already have generated filters. - * - * @param string $filter LDAP filter string - * - * @see parse() - */ - public function __construct($filter = false) - { - // The optional parameter must remain here, because otherwise create() crashes - if (false !== $filter) { - $filter_o = self::parse($filter); - if (PEAR::isError($filter_o)) { - $this->_filter = $filter_o; // assign error, so asString() can report it - } else { - $this->_filter = $filter_o->asString(); - } - } - } - - /** - * Constructor of a new part of a LDAP filter. - * - * The following matching rules exists: - * - equals: One of the attributes values is exactly $value - * Please note that case sensitiviness is depends on the - * attributes syntax configured in the server. - * - begins: One of the attributes values must begin with $value - * - ends: One of the attributes values must end with $value - * - contains: One of the attributes values must contain $value - * - present | any: The attribute can contain any value but must be existent - * - greater: The attributes value is greater than $value - * - less: The attributes value is less than $value - * - greaterOrEqual: The attributes value is greater or equal than $value - * - lessOrEqual: The attributes value is less or equal than $value - * - approx: One of the attributes values is similar to $value - * - * If $escape is set to true (default) then $value will be escaped - * properly. If it is set to false then $value will be treaten as raw filter value string. - * You should escape yourself using {@link Net_LDAP2_Util::escape_filter_value()}! - * - * Examples: - * - * // This will find entries that contain an attribute "sn" that ends with "foobar": - * $filter = new Net_LDAP2_Filter('sn', 'ends', 'foobar'); - * - * // This will find entries that contain an attribute "sn" that has any value set: - * $filter = new Net_LDAP2_Filter('sn', 'any'); - * - * - * @param string $attr_name Name of the attribute the filter should apply to - * @param string $match Matching rule (equals, begins, ends, contains, greater, less, greaterOrEqual, lessOrEqual, approx, any) - * @param string $value (optional) if given, then this is used as a filter - * @param boolean $escape Should $value be escaped? (default: yes, see {@link Net_LDAP2_Util::escape_filter_value()} for detailed information) - * - * @return Net_LDAP2_Filter|Net_LDAP2_Error - */ - public static function &create($attr_name, $match, $value = '', $escape = true) - { - $leaf_filter = new Net_LDAP2_Filter(); - if ($escape) { - $array = Net_LDAP2_Util::escape_filter_value(array($value)); - $value = $array[0]; - } - switch (strtolower($match)) { - case 'equals': - $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')'; - break; - case 'begins': - $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)'; - break; - case 'ends': - $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')'; - break; - case 'contains': - $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)'; - break; - case 'greater': - $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')'; - break; - case 'less': - $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')'; - break; - case 'greaterorequal': - case '>=': - $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')'; - break; - case 'lessorequal': - case '<=': - $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')'; - break; - case 'approx': - case '~=': - $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')'; - break; - case 'any': - case 'present': // alias that may improve user code readability - $leaf_filter->_filter = '(' . $attr_name . '=*)'; - break; - default: - return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!'); - } - return $leaf_filter; - } - - /** - * Combine two or more filter objects using a logical operator - * - * This static method combines two or more filter objects and returns one single - * filter object that contains all the others. - * Call this method statically: $filter = Net_LDAP2_Filter('or', array($filter1, $filter2)) - * If the array contains filter strings instead of filter objects, we will try to parse them. - * - * @param string $log_op The locicall operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!" - * @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects - * - * @return Net_LDAP2_Filter|Net_LDAP2_Error - * @static - */ - public static function &combine($log_op, $filters) - { - if (PEAR::isError($filters)) { - return $filters; - } - - // substitude named operators to logical operators - if ($log_op == 'and') $log_op = '&'; - if ($log_op == 'or') $log_op = '|'; - if ($log_op == 'not') $log_op = '!'; - - // tests for sane operation - if ($log_op == '!') { - // Not-combination, here we only accept one filter object or filter string - if ($filters instanceof Net_LDAP2_Filter) { - $filters = array($filters); // force array - } elseif (is_string($filters)) { - $filter_o = self::parse($filters); - if (PEAR::isError($filter_o)) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: '.$filter_o->getMessage()); - return $err; - } else { - $filters = array($filter_o); - } - } elseif (is_array($filters)) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!'); - return $err; - } else { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!'); - return $err; - } - } elseif ($log_op == '&' || $log_op == '|') { - if (!is_array($filters) || count($filters) < 2) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: parameter $filters is not an array or contains less than two Net_LDAP2_Filter objects!'); - return $err; - } - } else { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: logical operator is not known!'); - return $err; - } - - $combined_filter = new Net_LDAP2_Filter(); - foreach ($filters as $key => $testfilter) { // check for errors - if (PEAR::isError($testfilter)) { - return $testfilter; - } elseif (is_string($testfilter)) { - // string found, try to parse into an filter object - $filter_o = self::parse($testfilter); - if (PEAR::isError($filter_o)) { - return $filter_o; - } else { - $filters[$key] = $filter_o; - } - } elseif (!$testfilter instanceof Net_LDAP2_Filter) { - $err = PEAR::raiseError('Net_LDAP2_Filter combine error: invalid object passed in array $filters!'); - return $err; - } - } - - $combined_filter->_subfilters = $filters; - $combined_filter->_match = $log_op; - return $combined_filter; - } - - /** - * Parse FILTER into a Net_LDAP2_Filter object - * - * This parses an filter string into Net_LDAP2_Filter objects. - * - * @param string $FILTER The filter string - * - * @access static - * @return Net_LDAP2_Filter|Net_LDAP2_Error - * @todo Leaf-mode: Do we need to escape at all? what about *-chars?check for the need of encoding values, tackle problems (see code comments) - */ - public static function parse($FILTER) - { - if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) { - if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) { - // Subfilter processing: pass subfilters to parse() and combine - // the objects using the logical operator detected - // we have now something like "&(...)(...)(...)" but at least one part ("!(...)"). - // Each subfilter could be an arbitary complex subfilter. - - // extract logical operator and filter arguments - $log_op = substr($matches[1], 0, 1); - $remaining_component = substr($matches[1], 1); - - // split $remaining_component into individual subfilters - // we cannot use split() for this, because we do not know the - // complexiness of the subfilter. Thus, we look trough the filter - // string and just recognize ending filters at the first level. - // We record the index number of the char and use that information - // later to split the string. - $sub_index_pos = array(); - $prev_char = ''; // previous character looked at - $level = 0; // denotes the current bracket level we are, - // >1 is too deep, 1 is ok, 0 is outside any - // subcomponent - for ($curpos = 0; $curpos < strlen($remaining_component); $curpos++) { - $cur_char = substr($remaining_component, $curpos, 1); - - // rise/lower bracket level - if ($cur_char == '(' && $prev_char != '\\') { - $level++; - } elseif ($cur_char == ')' && $prev_char != '\\') { - $level--; - } - - if ($cur_char == '(' && $prev_char == ')' && $level == 1) { - array_push($sub_index_pos, $curpos); // mark the position for splitting - } - $prev_char = $cur_char; - } - - // now perform the splits. To get also the last part, we - // need to add the "END" index to the split array - array_push($sub_index_pos, strlen($remaining_component)); - $subfilters = array(); - $oldpos = 0; - foreach ($sub_index_pos as $s_pos) { - $str_part = substr($remaining_component, $oldpos, $s_pos - $oldpos); - array_push($subfilters, $str_part); - $oldpos = $s_pos; - } - - // some error checking... - if (count($subfilters) == 1) { - // only one subfilter found - } elseif (count($subfilters) > 1) { - // several subfilters found - if ($log_op == "!") { - return PEAR::raiseError("Filter parsing error: invalid filter syntax - NOT operator detected but several arguments given!"); - } - } else { - // this should not happen unless the user specified a wrong filter - return PEAR::raiseError("Filter parsing error: invalid filter syntax - got operator '$log_op' but no argument!"); - } - - // Now parse the subfilters into objects and combine them using the operator - $subfilters_o = array(); - foreach ($subfilters as $s_s) { - $o = self::parse($s_s); - if (PEAR::isError($o)) { - return $o; - } else { - array_push($subfilters_o, self::parse($s_s)); - } - } - - $filter_o = self::combine($log_op, $subfilters_o); - return $filter_o; - - } else { - // This is one leaf filter component, do some syntax checks, then escape and build filter_o - // $matches[1] should be now something like "foo=bar" - - // detect multiple leaf components - // [TODO] Maybe this will make problems with filters containing brackets inside the value - if (stristr($matches[1], ')(')) { - return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!"); - } else { - $filter_parts = preg_split('/(?|<|>=|<=)/', $matches[1], 2, PREG_SPLIT_DELIM_CAPTURE); - if (count($filter_parts) != 3) { - return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used"); - } else { - $filter_o = new Net_LDAP2_Filter(); - // [TODO]: Do we need to escape at all? what about *-chars user provide and that should remain special? - // I think, those prevent escaping! We need to check against PERL Net::LDAP! - // $value_arr = Net_LDAP2_Util::escape_filter_value(array($filter_parts[2])); - // $value = $value_arr[0]; - $value = $filter_parts[2]; - $filter_o->_filter = '('.$filter_parts[0].$filter_parts[1].$value.')'; - return $filter_o; - } - } - } - } else { - // ERROR: Filter components must be enclosed in round brackets - return PEAR::raiseError("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets"); - } - } - - /** - * Get the string representation of this filter - * - * This method runs through all filter objects and creates - * the string representation of the filter. If this - * filter object is a leaf filter, then it will return - * the string representation of this filter. - * - * @return string|Net_LDAP2_Error - */ - public function asString() - { - if ($this->isLeaf()) { - $return = $this->_filter; - } else { - $return = ''; - foreach ($this->_subfilters as $filter) { - $return = $return.$filter->asString(); - } - $return = '(' . $this->_match . $return . ')'; - } - return $return; - } - - /** - * Alias for perl interface as_string() - * - * @see asString() - * @return string|Net_LDAP2_Error - */ - public function as_string() - { - return $this->asString(); - } - - /** - * Print the text representation of the filter to FH, or the currently selected output handle if FH is not given - * - * This method is only for compatibility to the perl interface. - * However, the original method was called "print" but due to PHP language restrictions, - * we can't have a print() method. - * - * @param resource $FH (optional) A filehandle resource - * - * @return true|Net_LDAP2_Error - */ - public function printMe($FH = false) - { - if (!is_resource($FH)) { - if (PEAR::isError($FH)) { - return $FH; - } - $filter_str = $this->asString(); - if (PEAR::isError($filter_str)) { - return $filter_str; - } else { - print($filter_str); - } - } else { - $filter_str = $this->asString(); - if (PEAR::isError($filter_str)) { - return $filter_str; - } else { - $res = @fwrite($FH, $this->asString()); - if ($res == false) { - return PEAR::raiseError("Unable to write filter string to filehandle \$FH!"); - } - } - } - return true; - } - - /** - * This can be used to escape a string to provide a valid LDAP-Filter. - * - * LDAP will only recognise certain characters as the - * character istself if they are properly escaped. This is - * what this method does. - * The method can be called statically, so you can use it outside - * for your own purposes (eg for escaping only parts of strings) - * - * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}. - * For upward compatibiliy reasons you are strongly encouraged to use the escape - * methods provided by the Net_LDAP2_Util class. - * - * @param string $value Any string who should be escaped - * - * @static - * @return string The string $string, but escaped - * @deprecated Do not use this method anymore, instead use Net_LDAP2_Util::escape_filter_value() directly - */ - public static function escape($value) - { - $return = Net_LDAP2_Util::escape_filter_value(array($value)); - return $return[0]; - } - - /** - * Is this a container or a leaf filter object? - * - * @access protected - * @return boolean - */ - protected function isLeaf() - { - if (count($this->_subfilters) > 0) { - return false; // Container! - } else { - return true; // Leaf! - } - } -} -?> diff --git a/extlib/Net/LDAP2/LDIF.php b/extlib/Net/LDAP2/LDIF.php deleted file mode 100644 index 34f3e75dd..000000000 --- a/extlib/Net/LDAP2/LDIF.php +++ /dev/null @@ -1,922 +0,0 @@ - -* @copyright 2009 Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: LDIF.php 286718 2009-08-03 07:30:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; -require_once 'Net/LDAP2.php'; -require_once 'Net/LDAP2/Entry.php'; -require_once 'Net/LDAP2/Util.php'; - -/** -* LDIF capabilitys for Net_LDAP2, closely taken from PERLs Net::LDAP -* -* It provides a means to convert between Net_LDAP2_Entry objects and LDAP entries -* represented in LDIF format files. Reading and writing are supported and may -* manipulate single entries or lists of entries. -* -* Usage example: -* -* // Read and parse an ldif-file into Net_LDAP2_Entry objects -* // and print out the DNs. Store the entries for later use. -* require 'Net/LDAP2/LDIF.php'; -* $options = array( -* 'onerror' => 'die' -* ); -* $entries = array(); -* $ldif = new Net_LDAP2_LDIF('test.ldif', 'r', $options); -* do { -* $entry = $ldif->read_entry(); -* $dn = $entry->dn(); -* echo " done building entry: $dn\n"; -* array_push($entries, $entry); -* } while (!$ldif->eof()); -* $ldif->done(); -* -* -* // write those entries to another file -* $ldif = new Net_LDAP2_LDIF('test.out.ldif', 'w', $options); -* $ldif->write_entry($entries); -* $ldif->done(); -* -* -* @category Net -* @package Net_LDAP2 -* @author Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP22/ -* @see http://www.ietf.org/rfc/rfc2849.txt -* @todo Error handling should be PEARified -* @todo LDAPv3 controls are not implemented yet -*/ -class Net_LDAP2_LDIF extends PEAR -{ - /** - * Options - * - * @access protected - * @var array - */ - protected $_options = array('encode' => 'base64', - 'onerror' => null, - 'change' => 0, - 'lowercase' => 0, - 'sort' => 0, - 'version' => null, - 'wrap' => 78, - 'raw' => '' - ); - - /** - * Errorcache - * - * @access protected - * @var array - */ - protected $_error = array('error' => null, - 'line' => 0 - ); - - /** - * Filehandle for read/write - * - * @access protected - * @var array - */ - protected $_FH = null; - - /** - * Says, if we opened the filehandle ourselves - * - * @access protected - * @var array - */ - protected $_FH_opened = false; - - /** - * Linecounter for input file handle - * - * @access protected - * @var array - */ - protected $_input_line = 0; - - /** - * counter for processed entries - * - * @access protected - * @var int - */ - protected $_entrynum = 0; - - /** - * Mode we are working in - * - * Either 'r', 'a' or 'w' - * - * @access protected - * @var string - */ - protected $_mode = false; - - /** - * Tells, if the LDIF version string was already written - * - * @access protected - * @var boolean - */ - protected $_version_written = false; - - /** - * Cache for lines that have build the current entry - * - * @access protected - * @var boolean - */ - protected $_lines_cur = array(); - - /** - * Cache for lines that will build the next entry - * - * @access protected - * @var boolean - */ - protected $_lines_next = array(); - - /** - * Open LDIF file for reading or for writing - * - * new (FILE): - * Open the file read-only. FILE may be the name of a file - * or an already open filehandle. - * If the file doesn't exist, it will be created if in write mode. - * - * new (FILE, MODE, OPTIONS): - * Open the file with the given MODE (see PHPs fopen()), eg "w" or "a". - * FILE may be the name of a file or an already open filehandle. - * PERLs Net_LDAP2 "FILE|" mode does not work curently. - * - * OPTIONS is an associative array and may contain: - * encode => 'none' | 'canonical' | 'base64' - * Some DN values in LDIF cannot be written verbatim and have to be encoded in some way: - * 'none' No encoding. - * 'canonical' See "canonical_dn()" in Net::LDAP::Util. - * 'base64' Use base64. (default, this differs from the Perl interface. - * The perl default is "none"!) - * - * onerror => 'die' | 'warn' | NULL - * Specify what happens when an error is detected. - * 'die' Net_LDAP2_LDIF will croak with an appropriate message. - * 'warn' Net_LDAP2_LDIF will warn (echo) with an appropriate message. - * NULL Net_LDAP2_LDIF will not warn (default), use error(). - * - * change => 1 - * Write entry changes to the LDIF file instead of the entries itself. I.e. write LDAP - * operations acting on the entries to the file instead of the entries contents. - * This writes the changes usually carried out by an update() to the LDIF file. - * - * lowercase => 1 - * Convert attribute names to lowercase when writing. - * - * sort => 1 - * Sort attribute names when writing entries according to the rule: - * objectclass first then all other attributes alphabetically sorted by attribute name - * - * version => '1' - * Set the LDIF version to write to the resulting LDIF file. - * According to RFC 2849 currently the only legal value for this option is 1. - * When this option is set Net_LDAP2_LDIF tries to adhere more strictly to - * the LDIF specification in RFC2489 in a few places. - * The default is NULL meaning no version information is written to the LDIF file. - * - * wrap => 78 - * Number of columns where output line wrapping shall occur. - * Default is 78. Setting it to 40 or lower inhibits wrapping. - * - * raw => REGEX - * Use REGEX to denote the names of attributes that are to be - * considered binary in search results if writing entries. - * Example: raw => "/(?i:^jpegPhoto|;binary)/i" - * - * @param string|ressource $file Filename or filehandle - * @param string $mode Mode to open filename - * @param array $options Options like described above - */ - public function __construct($file, $mode = 'r', $options = array()) - { - $this->PEAR('Net_LDAP2_Error'); // default error class - - // First, parse options - // todo: maybe implement further checks on possible values - foreach ($options as $option => $value) { - if (!array_key_exists($option, $this->_options)) { - $this->dropError('Net_LDAP2_LDIF error: option '.$option.' not known!'); - return; - } else { - $this->_options[$option] = strtolower($value); - } - } - - // setup LDIF class - $this->version($this->_options['version']); - - // setup file mode - if (!preg_match('/^[rwa]\+?$/', $mode)) { - $this->dropError('Net_LDAP2_LDIF error: file mode '.$mode.' not supported!'); - } else { - $this->_mode = $mode; - - // setup filehandle - if (is_resource($file)) { - // TODO: checks on mode possible? - $this->_FH =& $file; - } else { - $imode = substr($this->_mode, 0, 1); - if ($imode == 'r') { - if (!file_exists($file)) { - $this->dropError('Unable to open '.$file.' for read: file not found'); - $this->_mode = false; - } - if (!is_readable($file)) { - $this->dropError('Unable to open '.$file.' for read: permission denied'); - $this->_mode = false; - } - } - - if (($imode == 'w' || $imode == 'a')) { - if (file_exists($file)) { - if (!is_writable($file)) { - $this->dropError('Unable to open '.$file.' for write: permission denied'); - $this->_mode = false; - } - } else { - if (!@touch($file)) { - $this->dropError('Unable to create '.$file.' for write: permission denied'); - $this->_mode = false; - } - } - } - - if ($this->_mode) { - $this->_FH = @fopen($file, $this->_mode); - if (false === $this->_FH) { - // Fallback; should never be reached if tests above are good enough! - $this->dropError('Net_LDAP2_LDIF error: Could not open file '.$file); - } else { - $this->_FH_opened = true; - } - } - } - } - } - - /** - * Read one entry from the file and return it as a Net::LDAP::Entry object. - * - * @return Net_LDAP2_Entry - */ - public function read_entry() - { - // read fresh lines, set them as current lines and create the entry - $attrs = $this->next_lines(true); - if (count($attrs) > 0) { - $this->_lines_cur = $attrs; - } - return $this->current_entry(); - } - - /** - * Returns true when the end of the file is reached. - * - * @return boolean - */ - public function eof() - { - return feof($this->_FH); - } - - /** - * Write the entry or entries to the LDIF file. - * - * If you want to build an LDIF file containing several entries AND - * you want to call write_entry() several times, you must open the filehandle - * in append mode ("a"), otherwise you will always get the last entry only. - * - * @param Net_LDAP2_Entry|array $entries Entry or array of entries - * - * @return void - * @todo implement operations on whole entries (adding a whole entry) - */ - public function write_entry($entries) - { - if (!is_array($entries)) { - $entries = array($entries); - } - - foreach ($entries as $entry) { - $this->_entrynum++; - if (!$entry instanceof Net_LDAP2_Entry) { - $this->dropError('Net_LDAP2_LDIF error: entry '.$this->_entrynum.' is not an Net_LDAP2_Entry object'); - } else { - if ($this->_options['change']) { - // LDIF change mode - // fetch change information from entry - $entry_attrs_changes = $entry->getChanges(); - $num_of_changes = count($entry_attrs_changes['add']) - + count($entry_attrs_changes['replace']) - + count($entry_attrs_changes['delete']); - - $is_changed = ($num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved()); - - // write version if not done yet - // also write DN of entry - if ($is_changed) { - if (!$this->_version_written) { - $this->write_version(); - } - $this->writeDN($entry->currentDN()); - } - - // process changes - // TODO: consider DN add! - if ($entry->willBeDeleted()) { - $this->writeLine("changetype: delete".PHP_EOL); - } elseif ($entry->willBeMoved()) { - $this->writeLine("changetype: modrdn".PHP_EOL); - $olddn = Net_LDAP2_Util::ldap_explode_dn($entry->currentDN(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs - $oldrdn = array_shift($olddn); - $oldparent = implode(',', $olddn); - $newdn = Net_LDAP2_Util::ldap_explode_dn($entry->dn(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs - $rdn = array_shift($newdn); - $parent = implode(',', $newdn); - $this->writeLine("newrdn: ".$rdn.PHP_EOL); - $this->writeLine("deleteoldrdn: 1".PHP_EOL); - if ($parent !== $oldparent) { - $this->writeLine("newsuperior: ".$parent.PHP_EOL); - } - // TODO: What if the entry has attribute changes as well? - // I think we should check for that and make a dummy - // entry with the changes that is written to the LDIF file - } elseif ($num_of_changes > 0) { - // write attribute change data - $this->writeLine("changetype: modify".PHP_EOL); - foreach ($entry_attrs_changes as $changetype => $entry_attrs) { - foreach ($entry_attrs as $attr_name => $attr_values) { - $this->writeLine("$changetype: $attr_name".PHP_EOL); - if ($attr_values !== null) $this->writeAttribute($attr_name, $attr_values, $changetype); - $this->writeLine("-".PHP_EOL); - } - } - } - - // finish this entrys data if we had changes - if ($is_changed) { - $this->finishEntry(); - } - } else { - // LDIF-content mode - // fetch attributes for further processing - $entry_attrs = $entry->getValues(); - - // sort and put objectclass-attrs to first position - if ($this->_options['sort']) { - ksort($entry_attrs); - if (array_key_exists('objectclass', $entry_attrs)) { - $oc = $entry_attrs['objectclass']; - unset($entry_attrs['objectclass']); - $entry_attrs = array_merge(array('objectclass' => $oc), $entry_attrs); - } - } - - // write data - if (!$this->_version_written) { - $this->write_version(); - } - $this->writeDN($entry->dn()); - foreach ($entry_attrs as $attr_name => $attr_values) { - $this->writeAttribute($attr_name, $attr_values); - } - $this->finishEntry(); - } - } - } - } - - /** - * Write version to LDIF - * - * If the object's version is defined, this method allows to explicitely write the version before an entry is written. - * If not called explicitely, it gets called automatically when writing the first entry. - * - * @return void - */ - public function write_version() - { - $this->_version_written = true; - if (!is_null($this->version())) { - return $this->writeLine('version: '.$this->version().PHP_EOL, 'Net_LDAP2_LDIF error: unable to write version'); - } - } - - /** - * Get or set LDIF version - * - * If called without arguments it returns the version of the LDIF file or NULL if no version has been set. - * If called with an argument it sets the LDIF version to VERSION. - * According to RFC 2849 currently the only legal value for VERSION is 1. - * - * @param int $version (optional) LDIF version to set - * - * @return int - */ - public function version($version = null) - { - if ($version !== null) { - if ($version != 1) { - $this->dropError('Net_LDAP2_LDIF error: illegal LDIF version set'); - } else { - $this->_options['version'] = $version; - } - } - return $this->_options['version']; - } - - /** - * Returns the file handle the Net_LDAP2_LDIF object reads from or writes to. - * - * You can, for example, use this to fetch the content of the LDIF file yourself - * - * @return null|resource - */ - public function &handle() - { - if (!is_resource($this->_FH)) { - $this->dropError('Net_LDAP2_LDIF error: invalid file resource'); - $null = null; - return $null; - } else { - return $this->_FH; - } - } - - /** - * Clean up - * - * This method signals that the LDIF object is no longer needed. - * You can use this to free up some memory and close the file handle. - * The file handle is only closed, if it was opened from Net_LDAP2_LDIF. - * - * @return void - */ - public function done() - { - // close FH if we opened it - if ($this->_FH_opened) { - fclose($this->handle()); - } - - // free variables - foreach (get_object_vars($this) as $name => $value) { - unset($this->$name); - } - } - - /** - * Returns last error message if error was found. - * - * Example: - * - * $ldif->someAction(); - * if ($ldif->error()) { - * echo "Error: ".$ldif->error()." at input line: ".$ldif->error_lines(); - * } - * - * - * @param boolean $as_string If set to true, only the message is returned - * - * @return false|Net_LDAP2_Error - */ - public function error($as_string = false) - { - if (Net_LDAP2::isError($this->_error['error'])) { - return ($as_string)? $this->_error['error']->getMessage() : $this->_error['error']; - } else { - return false; - } - } - - /** - * Returns lines that resulted in error. - * - * Perl returns an array of faulty lines in list context, - * but we always just return an int because of PHPs language. - * - * @return int - */ - public function error_lines() - { - return $this->_error['line']; - } - - /** - * Returns the current Net::LDAP::Entry object. - * - * @return Net_LDAP2_Entry|false - */ - public function current_entry() - { - return $this->parseLines($this->current_lines()); - } - - /** - * Parse LDIF lines of one entry into an Net_LDAP2_Entry object - * - * @param array $lines LDIF lines for one entry - * - * @return Net_LDAP2_Entry|false Net_LDAP2_Entry object for those lines - * @todo what about file inclusions and urls? "jpegphoto:< file:///usr/local/directory/photos/fiona.jpg" - */ - public function parseLines($lines) - { - // parse lines into an array of attributes and build the entry - $attributes = array(); - $dn = false; - foreach ($lines as $line) { - if (preg_match('/^(\w+)(:|::|:<)\s(.+)$/', $line, $matches)) { - $attr =& $matches[1]; - $delim =& $matches[2]; - $data =& $matches[3]; - - if ($delim == ':') { - // normal data - $attributes[$attr][] = $data; - } elseif ($delim == '::') { - // base64 data - $attributes[$attr][] = base64_decode($data); - } elseif ($delim == ':<') { - // file inclusion - // TODO: Is this the job of the LDAP-client or the server? - $this->dropError('File inclusions are currently not supported'); - //$attributes[$attr][] = ...; - } else { - // since the pattern above, the delimeter cannot be something else. - $this->dropError('Net_LDAP2_LDIF parsing error: invalid syntax at parsing entry line: '.$line); - continue; - } - - if (strtolower($attr) == 'dn') { - // DN line detected - $dn = $attributes[$attr][0]; // save possibly decoded DN - unset($attributes[$attr]); // remove wrongly added "dn: " attribute - } - } else { - // line not in "attr: value" format -> ignore - // maybe we should rise an error here, but this should be covered by - // next_lines() already. A problem arises, if users try to feed data of - // several entries to this method - the resulting entry will - // get wrong attributes. However, this is already mentioned in the - // methods documentation above. - } - } - - if (false === $dn) { - $this->dropError('Net_LDAP2_LDIF parsing error: unable to detect DN for entry'); - return false; - } else { - $newentry = Net_LDAP2_Entry::createFresh($dn, $attributes); - return $newentry; - } - } - - /** - * Returns the lines that generated the current Net::LDAP::Entry object. - * - * Note that this returns an empty array if no lines have been read so far. - * - * @return array Array of lines - */ - public function current_lines() - { - return $this->_lines_cur; - } - - /** - * Returns the lines that will generate the next Net::LDAP::Entry object. - * - * If you set $force to TRUE then you can iterate over the lines that build - * up entries manually. Otherwise, iterating is done using {@link read_entry()}. - * Force will move the file pointer forward, thus returning the next entries lines. - * - * Wrapped lines will be unwrapped. Comments are stripped. - * - * @param boolean $force Set this to true if you want to iterate over the lines manually - * - * @return array - */ - public function next_lines($force = false) - { - // if we already have those lines, just return them, otherwise read - if (count($this->_lines_next) == 0 || $force) { - $this->_lines_next = array(); // empty in case something was left (if used $force) - $entry_done = false; - $fh = &$this->handle(); - $commentmode = false; // if we are in an comment, for wrapping purposes - $datalines_read = 0; // how many lines with data we have read - - while (!$entry_done && !$this->eof()) { - $this->_input_line++; - // Read line. Remove line endings, we want only data; - // this is okay since ending spaces should be encoded - $data = rtrim(fgets($fh)); - if ($data === false) { - // error only, if EOF not reached after fgets() call - if (!$this->eof()) { - $this->dropError('Net_LDAP2_LDIF error: error reading from file at input line '.$this->_input_line, $this->_input_line); - } - break; - } else { - if (count($this->_lines_next) > 0 && preg_match('/^$/', $data)) { - // Entry is finished if we have an empty line after we had data - $entry_done = true; - - // Look ahead if the next EOF is nearby. Comments and empty - // lines at the file end may cause problems otherwise - $current_pos = ftell($fh); - $data = fgets($fh); - while (!feof($fh)) { - if (preg_match('/^\s*$/', $data) || preg_match('/^#/', $data)) { - // only empty lines or comments, continue to seek - // TODO: Known bug: Wrappings for comments are okay but are treaten as - // error, since we do not honor comment mode here. - // This should be a very theoretically case, however - // i am willing to fix this if really necessary. - $this->_input_line++; - $current_pos = ftell($fh); - $data = fgets($fh); - } else { - // Data found if non emtpy line and not a comment!! - // Rewind to position prior last read and stop lookahead - fseek($fh, $current_pos); - break; - } - } - // now we have either the file pointer at the beginning of - // a new data position or at the end of file causing feof() to return true - - } else { - // build lines - if (preg_match('/^version:\s(.+)$/', $data, $match)) { - // version statement, set version - $this->version($match[1]); - } elseif (preg_match('/^\w+::?\s.+$/', $data)) { - // normal attribute: add line - $commentmode = false; - $this->_lines_next[] = trim($data); - $datalines_read++; - } elseif (preg_match('/^\s(.+)$/', $data, $matches)) { - // wrapped data: unwrap if not in comment mode - if (!$commentmode) { - if ($datalines_read == 0) { - // first line of entry: wrapped data is illegal - $this->dropError('Net_LDAP2_LDIF error: illegal wrapping at input line '.$this->_input_line, $this->_input_line); - } else { - $last = array_pop($this->_lines_next); - $last = $last.trim($matches[1]); - $this->_lines_next[] = $last; - $datalines_read++; - } - } - } elseif (preg_match('/^#/', $data)) { - // LDIF comments - $commentmode = true; - } elseif (preg_match('/^\s*$/', $data)) { - // empty line but we had no data for this - // entry, so just ignore this line - $commentmode = false; - } else { - $this->dropError('Net_LDAP2_LDIF error: invalid syntax at input line '.$this->_input_line, $this->_input_line); - continue; - } - - } - } - } - } - return $this->_lines_next; - } - - /** - * Convert an attribute and value to LDIF string representation - * - * It honors correct encoding of values according to RFC 2849. - * Line wrapping will occur at the configured maximum but only if - * the value is greater than 40 chars. - * - * @param string $attr_name Name of the attribute - * @param string $attr_value Value of the attribute - * - * @access protected - * @return string LDIF string for that attribute and value - */ - protected function convertAttribute($attr_name, $attr_value) - { - // Handle empty attribute or process - if (strlen($attr_value) == 0) { - $attr_value = " "; - } else { - $base64 = false; - // ASCII-chars that are NOT safe for the - // start and for being inside the value. - // These are the int values of those chars. - $unsafe_init = array(0, 10, 13, 32, 58, 60); - $unsafe = array(0, 10, 13); - - // Test for illegal init char - $init_ord = ord(substr($attr_value, 0, 1)); - if ($init_ord > 127 || in_array($init_ord, $unsafe_init)) { - $base64 = true; - } - - // Test for illegal content char - for ($i = 0; $i < strlen($attr_value); $i++) { - $char_ord = ord(substr($attr_value, $i, 1)); - if ($char_ord > 127 || in_array($char_ord, $unsafe)) { - $base64 = true; - } - } - - // Test for ending space - if (substr($attr_value, -1) == ' ') { - $base64 = true; - } - - // If converting is needed, do it - // Either we have some special chars or a matching "raw" regex - if ($base64 || ($this->_options['raw'] && preg_match($this->_options['raw'], $attr_name))) { - $attr_name .= ':'; - $attr_value = base64_encode($attr_value); - } - - // Lowercase attr names if requested - if ($this->_options['lowercase']) $attr_name = strtolower($attr_name); - - // Handle line wrapping - if ($this->_options['wrap'] > 40 && strlen($attr_value) > $this->_options['wrap']) { - $attr_value = wordwrap($attr_value, $this->_options['wrap'], PHP_EOL." ", true); - } - } - - return $attr_name.': '.$attr_value; - } - - /** - * Convert an entries DN to LDIF string representation - * - * It honors correct encoding of values according to RFC 2849. - * - * @param string $dn UTF8-Encoded DN - * - * @access protected - * @return string LDIF string for that DN - * @todo I am not sure, if the UTF8 stuff is correctly handled right now - */ - protected function convertDN($dn) - { - $base64 = false; - // ASCII-chars that are NOT safe for the - // start and for being inside the dn. - // These are the int values of those chars. - $unsafe_init = array(0, 10, 13, 32, 58, 60); - $unsafe = array(0, 10, 13); - - // Test for illegal init char - $init_ord = ord(substr($dn, 0, 1)); - if ($init_ord >= 127 || in_array($init_ord, $unsafe_init)) { - $base64 = true; - } - - // Test for illegal content char - for ($i = 0; $i < strlen($dn); $i++) { - $char = substr($dn, $i, 1); - if (ord($char) >= 127 || in_array($init_ord, $unsafe)) { - $base64 = true; - } - } - - // Test for ending space - if (substr($dn, -1) == ' ') { - $base64 = true; - } - - // if converting is needed, do it - return ($base64)? 'dn:: '.base64_encode($dn) : 'dn: '.$dn; - } - - /** - * Writes an attribute to the filehandle - * - * @param string $attr_name Name of the attribute - * @param string|array $attr_values Single attribute value or array with attribute values - * - * @access protected - * @return void - */ - protected function writeAttribute($attr_name, $attr_values) - { - // write out attribute content - if (!is_array($attr_values)) { - $attr_values = array($attr_values); - } - foreach ($attr_values as $attr_val) { - $line = $this->convertAttribute($attr_name, $attr_val).PHP_EOL; - $this->writeLine($line, 'Net_LDAP2_LDIF error: unable to write attribute '.$attr_name.' of entry '.$this->_entrynum); - } - } - - /** - * Writes a DN to the filehandle - * - * @param string $dn DN to write - * - * @access protected - * @return void - */ - protected function writeDN($dn) - { - // prepare DN - if ($this->_options['encode'] == 'base64') { - $dn = $this->convertDN($dn).PHP_EOL; - } elseif ($this->_options['encode'] == 'canonical') { - $dn = Net_LDAP2_Util::canonical_dn($dn, array('casefold' => 'none')).PHP_EOL; - } else { - $dn = $dn.PHP_EOL; - } - $this->writeLine($dn, 'Net_LDAP2_LDIF error: unable to write DN of entry '.$this->_entrynum); - } - - /** - * Finishes an LDIF entry - * - * @access protected - * @return void - */ - protected function finishEntry() - { - $this->writeLine(PHP_EOL, 'Net_LDAP2_LDIF error: unable to close entry '.$this->_entrynum); - } - - /** - * Just write an arbitary line to the filehandle - * - * @param string $line Content to write - * @param string $error If error occurs, drop this message - * - * @access protected - * @return true|false - */ - protected function writeLine($line, $error = 'Net_LDAP2_LDIF error: unable to write to filehandle') - { - if (is_resource($this->handle()) && fwrite($this->handle(), $line, strlen($line)) === false) { - $this->dropError($error); - return false; - } else { - return true; - } - } - - /** - * Optionally raises an error and pushes the error on the error cache - * - * @param string $msg Errortext - * @param int $line Line in the LDIF that caused the error - * - * @access protected - * @return void - */ - protected function dropError($msg, $line = null) - { - $this->_error['error'] = new Net_LDAP2_Error($msg); - if ($line !== null) $this->_error['line'] = $line; - - if ($this->_options['onerror'] == 'die') { - die($msg.PHP_EOL); - } elseif ($this->_options['onerror'] == 'warn') { - echo $msg.PHP_EOL; - } - } -} -?> diff --git a/extlib/Net/LDAP2/RootDSE.php b/extlib/Net/LDAP2/RootDSE.php deleted file mode 100644 index 8dc81fd4f..000000000 --- a/extlib/Net/LDAP2/RootDSE.php +++ /dev/null @@ -1,240 +0,0 @@ - -* @copyright 2009 Jan Wagner -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: RootDSE.php 286718 2009-08-03 07:30:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; - -/** -* Getting the rootDSE entry of a LDAP server -* -* @category Net -* @package Net_LDAP2 -* @author Jan Wagner -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP22/ -*/ -class Net_LDAP2_RootDSE extends PEAR -{ - /** - * @access protected - * @var object Net_LDAP2_Entry - **/ - protected $_entry; - - /** - * Class constructor - * - * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry object of the RootDSE - */ - protected function __construct(&$entry) - { - $this->_entry = $entry; - } - - /** - * Fetches a RootDSE object from an LDAP connection - * - * @param Net_LDAP2 $ldap Directory from which the RootDSE should be fetched - * @param array $attrs Array of attributes to search for - * - * @access static - * @return Net_LDAP2_RootDSE|Net_LDAP2_Error - */ - public static function fetch($ldap, $attrs = null) - { - if (!$ldap instanceof Net_LDAP2) { - return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!"); - } - - if (is_array($attrs) && count($attrs) > 0 ) { - $attributes = $attrs; - } else { - $attributes = array('vendorName', - 'vendorVersion', - 'namingContexts', - 'altServer', - 'supportedExtension', - 'supportedControl', - 'supportedSASLMechanisms', - 'supportedLDAPVersion', - 'subschemaSubentry' ); - } - $result = $ldap->search('', '(objectClass=*)', array('attributes' => $attributes, 'scope' => 'base')); - if (self::isError($result)) { - return $result; - } - $entry = $result->shiftEntry(); - if (false === $entry) { - return PEAR::raiseError('Could not fetch RootDSE entry'); - } - $ret = new Net_LDAP2_RootDSE($entry); - return $ret; - } - - /** - * Gets the requested attribute value - * - * Same usuage as {@link Net_LDAP2_Entry::getValue()} - * - * @param string $attr Attribute name - * @param array $options Array of options - * - * @access public - * @return mixed Net_LDAP2_Error object or attribute values - * @see Net_LDAP2_Entry::get_value() - */ - public function getValue($attr = '', $options = '') - { - return $this->_entry->get_value($attr, $options); - } - - /** - * Alias function of getValue() for perl-ldap interface - * - * @see getValue() - * @return mixed - */ - public function get_value() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'getValue' ), $args); - } - - /** - * Determines if the extension is supported - * - * @param array $oids Array of oids to check - * - * @access public - * @return boolean - */ - public function supportedExtension($oids) - { - return $this->checkAttr($oids, 'supportedExtension'); - } - - /** - * Alias function of supportedExtension() for perl-ldap interface - * - * @see supportedExtension() - * @return boolean - */ - public function supported_extension() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'supportedExtension'), $args); - } - - /** - * Determines if the version is supported - * - * @param array $versions Versions to check - * - * @access public - * @return boolean - */ - public function supportedVersion($versions) - { - return $this->checkAttr($versions, 'supportedLDAPVersion'); - } - - /** - * Alias function of supportedVersion() for perl-ldap interface - * - * @see supportedVersion() - * @return boolean - */ - public function supported_version() - { - $args = func_get_args(); - return call_user_func_array(array(&$this, 'supportedVersion'), $args); - } - - /** - * Determines if the control is supported - * - * @param array $oids Control oids to check - * - * @access public - * @return boolean - */ - public function supportedControl($oids) - { - return $this->checkAttr($oids, 'supportedControl'); - } - - /** - * Alias function of supportedControl() for perl-ldap interface - * - * @see supportedControl() - * @return boolean - */ - public function supported_control() - { - $args = func_get_args(); - return call_user_func_array(array(&$this, 'supportedControl' ), $args); - } - - /** - * Determines if the sasl mechanism is supported - * - * @param array $mechlist SASL mechanisms to check - * - * @access public - * @return boolean - */ - public function supportedSASLMechanism($mechlist) - { - return $this->checkAttr($mechlist, 'supportedSASLMechanisms'); - } - - /** - * Alias function of supportedSASLMechanism() for perl-ldap interface - * - * @see supportedSASLMechanism() - * @return boolean - */ - public function supported_sasl_mechanism() - { - $args = func_get_args(); - return call_user_func_array(array(&$this, 'supportedSASLMechanism'), $args); - } - - /** - * Checks for existance of value in attribute - * - * @param array $values values to check - * @param string $attr attribute name - * - * @access protected - * @return boolean - */ - protected function checkAttr($values, $attr) - { - if (!is_array($values)) $values = array($values); - - foreach ($values as $value) { - if (!@in_array($value, $this->get_value($attr, 'all'))) { - return false; - } - } - return true; - } -} - -?> diff --git a/extlib/Net/LDAP2/Schema.php b/extlib/Net/LDAP2/Schema.php deleted file mode 100644 index b590eabc5..000000000 --- a/extlib/Net/LDAP2/Schema.php +++ /dev/null @@ -1,516 +0,0 @@ - -* @author Benedikt Hallinger -* @copyright 2009 Jan Wagner, Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: Schema.php 286718 2009-08-03 07:30:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -* @todo see the comment at the end of the file -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; - -/** -* Syntax definitions -* -* Please don't forget to add binary attributes to isBinary() below -* to support proper value fetching from Net_LDAP2_Entry -*/ -define('NET_LDAP2_SYNTAX_BOOLEAN', '1.3.6.1.4.1.1466.115.121.1.7'); -define('NET_LDAP2_SYNTAX_DIRECTORY_STRING', '1.3.6.1.4.1.1466.115.121.1.15'); -define('NET_LDAP2_SYNTAX_DISTINGUISHED_NAME', '1.3.6.1.4.1.1466.115.121.1.12'); -define('NET_LDAP2_SYNTAX_INTEGER', '1.3.6.1.4.1.1466.115.121.1.27'); -define('NET_LDAP2_SYNTAX_JPEG', '1.3.6.1.4.1.1466.115.121.1.28'); -define('NET_LDAP2_SYNTAX_NUMERIC_STRING', '1.3.6.1.4.1.1466.115.121.1.36'); -define('NET_LDAP2_SYNTAX_OID', '1.3.6.1.4.1.1466.115.121.1.38'); -define('NET_LDAP2_SYNTAX_OCTET_STRING', '1.3.6.1.4.1.1466.115.121.1.40'); - -/** -* Load an LDAP Schema and provide information -* -* This class takes a Subschema entry, parses this information -* and makes it available in an array. Most of the code has been -* inspired by perl-ldap( http://perl-ldap.sourceforge.net). -* You will find portions of their implementation in here. -* -* @category Net -* @package Net_LDAP2 -* @author Jan Wagner -* @author Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP22/ -*/ -class Net_LDAP2_Schema extends PEAR -{ - /** - * Map of entry types to ldap attributes of subschema entry - * - * @access public - * @var array - */ - public $types = array( - 'attribute' => 'attributeTypes', - 'ditcontentrule' => 'dITContentRules', - 'ditstructurerule' => 'dITStructureRules', - 'matchingrule' => 'matchingRules', - 'matchingruleuse' => 'matchingRuleUse', - 'nameform' => 'nameForms', - 'objectclass' => 'objectClasses', - 'syntax' => 'ldapSyntaxes' - ); - - /** - * Array of entries belonging to this type - * - * @access protected - * @var array - */ - protected $_attributeTypes = array(); - protected $_matchingRules = array(); - protected $_matchingRuleUse = array(); - protected $_ldapSyntaxes = array(); - protected $_objectClasses = array(); - protected $_dITContentRules = array(); - protected $_dITStructureRules = array(); - protected $_nameForms = array(); - - - /** - * hash of all fetched oids - * - * @access protected - * @var array - */ - protected $_oids = array(); - - /** - * Tells if the schema is initialized - * - * @access protected - * @var boolean - * @see parse(), get() - */ - protected $_initialized = false; - - - /** - * Constructor of the class - * - * @access protected - */ - protected function __construct() - { - $this->PEAR('Net_LDAP2_Error'); // default error class - } - - /** - * Fetch the Schema from an LDAP connection - * - * @param Net_LDAP2 $ldap LDAP connection - * @param string $dn (optional) Subschema entry dn - * - * @access public - * @return Net_LDAP2_Schema|NET_LDAP2_Error - */ - public function fetch($ldap, $dn = null) - { - if (!$ldap instanceof Net_LDAP2) { - return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!"); - } - - $schema_o = new Net_LDAP2_Schema(); - - if (is_null($dn)) { - // get the subschema entry via root dse - $dse = $ldap->rootDSE(array('subschemaSubentry')); - if (false == Net_LDAP2::isError($dse)) { - $base = $dse->getValue('subschemaSubentry', 'single'); - if (!Net_LDAP2::isError($base)) { - $dn = $base; - } - } - } - - // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that incorrectly - // call this entry subSchemaSubentry instead of subschemaSubentry. - // Note the correct case/spelling as per RFC 2251. - if (is_null($dn)) { - // get the subschema entry via root dse - $dse = $ldap->rootDSE(array('subSchemaSubentry')); - if (false == Net_LDAP2::isError($dse)) { - $base = $dse->getValue('subSchemaSubentry', 'single'); - if (!Net_LDAP2::isError($base)) { - $dn = $base; - } - } - } - - // Final fallback case where there is no subschemaSubentry attribute - // in the root DSE (this is a bug for an LDAP v3 server so report this - // to your LDAP vendor if you get this far). - if (is_null($dn)) { - $dn = 'cn=Subschema'; - } - - // fetch the subschema entry - $result = $ldap->search($dn, '(objectClass=*)', - array('attributes' => array_values($schema_o->types), - 'scope' => 'base')); - if (Net_LDAP2::isError($result)) { - return $result; - } - - $entry = $result->shiftEntry(); - if (!$entry instanceof Net_LDAP2_Entry) { - return PEAR::raiseError('Could not fetch Subschema entry'); - } - - $schema_o->parse($entry); - return $schema_o; - } - - /** - * Return a hash of entries for the given type - * - * Returns a hash of entry for th givene type. Types may be: - * objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules, - * matchingruleuses, nameforms, syntaxes - * - * @param string $type Type to fetch - * - * @access public - * @return array|Net_LDAP2_Error Array or Net_LDAP2_Error - */ - public function &getAll($type) - { - $map = array('objectclasses' => &$this->_objectClasses, - 'attributes' => &$this->_attributeTypes, - 'ditcontentrules' => &$this->_dITContentRules, - 'ditstructurerules' => &$this->_dITStructureRules, - 'matchingrules' => &$this->_matchingRules, - 'matchingruleuses' => &$this->_matchingRuleUse, - 'nameforms' => &$this->_nameForms, - 'syntaxes' => &$this->_ldapSyntaxes ); - - $key = strtolower($type); - $ret = ((key_exists($key, $map)) ? $map[$key] : PEAR::raiseError("Unknown type $type")); - return $ret; - } - - /** - * Return a specific entry - * - * @param string $type Type of name - * @param string $name Name or OID to fetch - * - * @access public - * @return mixed Entry or Net_LDAP2_Error - */ - public function &get($type, $name) - { - if ($this->_initialized) { - $type = strtolower($type); - if (false == key_exists($type, $this->types)) { - return PEAR::raiseError("No such type $type"); - } - - $name = strtolower($name); - $type_var = &$this->{'_' . $this->types[$type]}; - - if (key_exists($name, $type_var)) { - return $type_var[$name]; - } elseif (key_exists($name, $this->_oids) && $this->_oids[$name]['type'] == $type) { - return $this->_oids[$name]; - } else { - return PEAR::raiseError("Could not find $type $name"); - } - } else { - $return = null; - return $return; - } - } - - - /** - * Fetches attributes that MAY be present in the given objectclass - * - * @param string $oc Name or OID of objectclass - * - * @access public - * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error - */ - public function may($oc) - { - return $this->_getAttr($oc, 'may'); - } - - /** - * Fetches attributes that MUST be present in the given objectclass - * - * @param string $oc Name or OID of objectclass - * - * @access public - * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error - */ - public function must($oc) - { - return $this->_getAttr($oc, 'must'); - } - - /** - * Fetches the given attribute from the given objectclass - * - * @param string $oc Name or OID of objectclass - * @param string $attr Name of attribute to fetch - * - * @access protected - * @return array|Net_LDAP2_Error The attribute or Net_LDAP2_Error - */ - protected function _getAttr($oc, $attr) - { - $oc = strtolower($oc); - if (key_exists($oc, $this->_objectClasses) && key_exists($attr, $this->_objectClasses[$oc])) { - return $this->_objectClasses[$oc][$attr]; - } elseif (key_exists($oc, $this->_oids) && - $this->_oids[$oc]['type'] == 'objectclass' && - key_exists($attr, $this->_oids[$oc])) { - return $this->_oids[$oc][$attr]; - } else { - return PEAR::raiseError("Could not find $attr attributes for $oc "); - } - } - - /** - * Returns the name(s) of the immediate superclass(es) - * - * @param string $oc Name or OID of objectclass - * - * @access public - * @return array|Net_LDAP2_Error Array of names or Net_LDAP2_Error - */ - public function superclass($oc) - { - $o = $this->get('objectclass', $oc); - if (Net_LDAP2::isError($o)) { - return $o; - } - return (key_exists('sup', $o) ? $o['sup'] : array()); - } - - /** - * Parses the schema of the given Subschema entry - * - * @param Net_LDAP2_Entry &$entry Subschema entry - * - * @access public - * @return void - */ - public function parse(&$entry) - { - foreach ($this->types as $type => $attr) { - // initialize map type to entry - $type_var = '_' . $attr; - $this->{$type_var} = array(); - - // get values for this type - if ($entry->exists($attr)) { - $values = $entry->getValue($attr); - if (is_array($values)) { - foreach ($values as $value) { - - unset($schema_entry); // this was a real mess without it - - // get the schema entry - $schema_entry = $this->_parse_entry($value); - - // set the type - $schema_entry['type'] = $type; - - // save a ref in $_oids - $this->_oids[$schema_entry['oid']] = &$schema_entry; - - // save refs for all names in type map - $names = $schema_entry['aliases']; - array_push($names, $schema_entry['name']); - foreach ($names as $name) { - $this->{$type_var}[strtolower($name)] = &$schema_entry; - } - } - } - } - } - $this->_initialized = true; - } - - /** - * Parses an attribute value into a schema entry - * - * @param string $value Attribute value - * - * @access protected - * @return array|false Schema entry array or false - */ - protected function &_parse_entry($value) - { - // tokens that have no value associated - $noValue = array('single-value', - 'obsolete', - 'collective', - 'no-user-modification', - 'abstract', - 'structural', - 'auxiliary'); - - // tokens that can have multiple values - $multiValue = array('must', 'may', 'sup'); - - $schema_entry = array('aliases' => array()); // initilization - - $tokens = $this->_tokenize($value); // get an array of tokens - - // remove surrounding brackets - if ($tokens[0] == '(') array_shift($tokens); - if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); // -1 doesnt work on arrays :-( - - $schema_entry['oid'] = array_shift($tokens); // first token is the oid - - // cycle over the tokens until none are left - while (count($tokens) > 0) { - $token = strtolower(array_shift($tokens)); - if (in_array($token, $noValue)) { - $schema_entry[$token] = 1; // single value token - } else { - // this one follows a string or a list if it is multivalued - if (($schema_entry[$token] = array_shift($tokens)) == '(') { - // this creates the list of values and cycles through the tokens - // until the end of the list is reached ')' - $schema_entry[$token] = array(); - while ($tmp = array_shift($tokens)) { - if ($tmp == ')') break; - if ($tmp != '$') array_push($schema_entry[$token], $tmp); - } - } - // create a array if the value should be multivalued but was not - if (in_array($token, $multiValue) && !is_array($schema_entry[$token])) { - $schema_entry[$token] = array($schema_entry[$token]); - } - } - } - // get max length from syntax - if (key_exists('syntax', $schema_entry)) { - if (preg_match('/{(\d+)}/', $schema_entry['syntax'], $matches)) { - $schema_entry['max_length'] = $matches[1]; - } - } - // force a name - if (empty($schema_entry['name'])) { - $schema_entry['name'] = $schema_entry['oid']; - } - // make one name the default and put the other ones into aliases - if (is_array($schema_entry['name'])) { - $aliases = $schema_entry['name']; - $schema_entry['name'] = array_shift($aliases); - $schema_entry['aliases'] = $aliases; - } - return $schema_entry; - } - - /** - * Tokenizes the given value into an array of tokens - * - * @param string $value String to parse - * - * @access protected - * @return array Array of tokens - */ - protected function _tokenize($value) - { - $tokens = array(); // array of tokens - $matches = array(); // matches[0] full pattern match, [1,2,3] subpatterns - - // this one is taken from perl-ldap, modified for php - $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x"; - - /** - * This one matches one big pattern wherin only one of the three subpatterns matched - * We are interested in the subpatterns that matched. If it matched its value will be - * non-empty and so it is a token. Tokens may be round brackets, a string, or a string - * enclosed by ' - */ - preg_match_all($pattern, $value, $matches); - - for ($i = 0; $i < count($matches[0]); $i++) { // number of tokens (full pattern match) - for ($j = 1; $j < 4; $j++) { // each subpattern - if (null != trim($matches[$j][$i])) { // pattern match in this subpattern - $tokens[$i] = trim($matches[$j][$i]); // this is the token - } - } - } - return $tokens; - } - - /** - * Returns wether a attribute syntax is binary or not - * - * This method gets used by Net_LDAP2_Entry to decide which - * PHP function needs to be used to fetch the value in the - * proper format (e.g. binary or string) - * - * @param string $attribute The name of the attribute (eg.: 'sn') - * - * @access public - * @return boolean - */ - public function isBinary($attribute) - { - $return = false; // default to false - - // This list contains all syntax that should be treaten as - // containing binary values - // The Syntax Definitons go into constants at the top of this page - $syntax_binary = array( - NET_LDAP2_SYNTAX_OCTET_STRING, - NET_LDAP2_SYNTAX_JPEG - ); - - // Check Syntax - $attr_s = $this->get('attribute', $attribute); - if (Net_LDAP2::isError($attr_s)) { - // Attribute not found in schema - $return = false; // consider attr not binary - } elseif (isset($attr_s['syntax']) && in_array($attr_s['syntax'], $syntax_binary)) { - // Syntax is defined as binary in schema - $return = true; - } else { - // Syntax not defined as binary, or not found - // if attribute is a subtype, check superior attribute syntaxes - if (isset($attr_s['sup'])) { - foreach ($attr_s['sup'] as $superattr) { - $return = $this->isBinary($superattr); - if ($return) { - break; // stop checking parents since we are binary - } - } - } - } - - return $return; - } - - // [TODO] add method that allows us to see to which objectclasses a certain attribute belongs to - // it should return the result structured, e.g. sorted in "may" and "must". Optionally it should - // be able to return it just "flat", e.g. array_merge()d. - // We could use get_all() to achieve this easily, i think -} -?> diff --git a/extlib/Net/LDAP2/SchemaCache.interface.php b/extlib/Net/LDAP2/SchemaCache.interface.php deleted file mode 100644 index e0c3094c4..000000000 --- a/extlib/Net/LDAP2/SchemaCache.interface.php +++ /dev/null @@ -1,59 +0,0 @@ - -* @copyright 2009 Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: SchemaCache.interface.php 286718 2009-08-03 07:30:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Interface describing a custom schema cache object -* -* To implement a custom schema cache, one must implement this interface and -* pass the instanciated object to Net_LDAP2s registerSchemaCache() method. -*/ -interface Net_LDAP2_SchemaCache -{ - /** - * Return the schema object from the cache - * - * Net_LDAP2 will consider anything returned invalid, except - * a valid Net_LDAP2_Schema object. - * In case you return a Net_LDAP2_Error, this error will be routed - * to the return of the $ldap->schema() call. - * If you return something else, Net_LDAP2 will - * fetch a fresh Schema object from the LDAP server. - * - * You may want to implement a cache aging mechanism here too. - * - * @return Net_LDAP2_Schema|Net_LDAP2_Error|false - */ - public function loadSchema(); - - /** - * Store a schema object in the cache - * - * This method will be called, if Net_LDAP2 has fetched a fresh - * schema object from LDAP and wants to init or refresh the cache. - * - * In case of errors you may return a Net_LDAP2_Error which will - * be routet to the client. - * Note that doing this prevents, that the schema object fetched from LDAP - * will be given back to the client, so only return errors if storing - * of the cache is something crucial (e.g. for doing something else with it). - * Normaly you dont want to give back errors in which case Net_LDAP2 needs to - * fetch the schema once per script run and instead use the error - * returned from loadSchema(). - * - * @return true|Net_LDAP2_Error - */ - public function storeSchema($schema); -} diff --git a/extlib/Net/LDAP2/Search.php b/extlib/Net/LDAP2/Search.php deleted file mode 100644 index de4fde122..000000000 --- a/extlib/Net/LDAP2/Search.php +++ /dev/null @@ -1,614 +0,0 @@ - -* @author Benedikt Hallinger -* @copyright 2009 Tarjej Huse, Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: Search.php 286718 2009-08-03 07:30:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; - -/** -* Result set of an LDAP search -* -* @category Net -* @package Net_LDAP2 -* @author Tarjej Huse -* @author Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP22/ -*/ -class Net_LDAP2_Search extends PEAR implements Iterator -{ - /** - * Search result identifier - * - * @access protected - * @var resource - */ - protected $_search; - - /** - * LDAP resource link - * - * @access protected - * @var resource - */ - protected $_link; - - /** - * Net_LDAP2 object - * - * A reference of the Net_LDAP2 object for passing to Net_LDAP2_Entry - * - * @access protected - * @var object Net_LDAP2 - */ - protected $_ldap; - - /** - * Result entry identifier - * - * @access protected - * @var resource - */ - protected $_entry = null; - - /** - * The errorcode the search got - * - * Some errorcodes might be of interest, but might not be best handled as errors. - * examples: 4 - LDAP_SIZELIMIT_EXCEEDED - indicates a huge search. - * Incomplete results are returned. If you just want to check if there's anything in the search. - * than this is a point to handle. - * 32 - no such object - search here returns a count of 0. - * - * @access protected - * @var int - */ - protected $_errorCode = 0; // if not set - sucess! - - /** - * Cache for all entries already fetched from iterator interface - * - * @access protected - * @var array - */ - protected $_iteratorCache = array(); - - /** - * What attributes we searched for - * - * The $attributes array contains the names of the searched attributes and gets - * passed from $Net_LDAP2->search() so the Net_LDAP2_Search object can tell - * what attributes was searched for ({@link searchedAttrs()) - * - * This variable gets set from the constructor and returned - * from {@link searchedAttrs()} - * - * @access protected - * @var array - */ - protected $_searchedAttrs = array(); - - /** - * Cache variable for storing entries fetched internally - * - * This currently is only used by {@link pop_entry()} - * - * @access protected - * @var array - */ - protected $_entry_cache = false; - - /** - * Constructor - * - * @param resource &$search Search result identifier - * @param Net_LDAP2|resource &$ldap Net_LDAP2 object or just a LDAP-Link resource - * @param array $attributes (optional) Array with searched attribute names. (see {@link $_searchedAttrs}) - * - * @access public - */ - public function __construct(&$search, &$ldap, $attributes = array()) - { - $this->PEAR('Net_LDAP2_Error'); - - $this->setSearch($search); - - if ($ldap instanceof Net_LDAP2) { - $this->_ldap =& $ldap; - $this->setLink($this->_ldap->getLink()); - } else { - $this->setLink($ldap); - } - - $this->_errorCode = @ldap_errno($this->_link); - - if (is_array($attributes) && !empty($attributes)) { - $this->_searchedAttrs = $attributes; - } - } - - /** - * Returns an array of entry objects - * - * @return array Array of entry objects. - */ - public function entries() - { - $entries = array(); - - while ($entry = $this->shiftEntry()) { - $entries[] = $entry; - } - - return $entries; - } - - /** - * Get the next entry in the searchresult. - * - * This will return a valid Net_LDAP2_Entry object or false, so - * you can use this method to easily iterate over the entries inside - * a while loop. - * - * @return Net_LDAP2_Entry|false Reference to Net_LDAP2_Entry object or false - */ - public function &shiftEntry() - { - if ($this->count() == 0 ) { - $false = false; - return $false; - } - - if (is_null($this->_entry)) { - $this->_entry = @ldap_first_entry($this->_link, $this->_search); - $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry); - if ($entry instanceof Net_LDAP2_Error) $entry = false; - } else { - if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) { - $false = false; - return $false; - } - $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry); - if ($entry instanceof Net_LDAP2_Error) $entry = false; - } - return $entry; - } - - /** - * Alias function of shiftEntry() for perl-ldap interface - * - * @see shiftEntry() - * @return Net_LDAP2_Entry|false - */ - public function shift_entry() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'shiftEntry' ), $args); - } - - /** - * Retrieve the next entry in the searchresult, but starting from last entry - * - * This is the opposite to {@link shiftEntry()} and is also very useful - * to be used inside a while loop. - * - * @return Net_LDAP2_Entry|false - */ - public function popEntry() - { - if (false === $this->_entry_cache) { - // fetch entries into cache if not done so far - $this->_entry_cache = $this->entries(); - } - - $return = array_pop($this->_entry_cache); - return (null === $return)? false : $return; - } - - /** - * Alias function of popEntry() for perl-ldap interface - * - * @see popEntry() - * @return Net_LDAP2_Entry|false - */ - public function pop_entry() - { - $args = func_get_args(); - return call_user_func_array(array( &$this, 'popEntry' ), $args); - } - - /** - * Return entries sorted as array - * - * This returns a array with sorted entries and the values. - * Sorting is done with PHPs {@link array_multisort()}. - * This method relies on {@link as_struct()} to fetch the raw data of the entries. - * - * Please note that attribute names are case sensitive! - * - * Usage example: - * - * // to sort entries first by location, then by surename, but descending: - * $entries = $search->sorted_as_struct(array('locality','sn'), SORT_DESC); - * - * - * @param array $attrs Array of attribute names to sort; order from left to right. - * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC - * - * @return array|Net_LDAP2_Error Array with sorted entries or error - * @todo what about server side sorting as specified in http://www.ietf.org/rfc/rfc2891.txt? - */ - public function sorted_as_struct($attrs = array('cn'), $order = SORT_ASC) - { - /* - * Old Code, suitable and fast for single valued sorting - * This code should be used if we know that single valued sorting is desired, - * but we need some method to get that knowledge... - */ - /* - $attrs = array_reverse($attrs); - foreach ($attrs as $attribute) { - if (!ldap_sort($this->_link, $this->_search, $attribute)){ - $this->raiseError("Sorting failed for Attribute " . $attribute); - } - } - - $results = ldap_get_entries($this->_link, $this->_search); - - unset($results['count']); //for tidier output - if ($order) { - return array_reverse($results); - } else { - return $results; - }*/ - - /* - * New code: complete "client side" sorting - */ - // first some parameterchecks - if (!is_array($attrs)) { - return PEAR::raiseError("Sorting failed: Parameterlist must be an array!"); - } - if ($order != SORT_ASC && $order != SORT_DESC) { - return PEAR::raiseError("Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)"); - } - - // fetch the entries data - $entries = $this->as_struct(); - - // now sort each entries attribute values - // this is neccessary because later we can only sort by one value, - // so we need the highest or lowest attribute now, depending on the - // selected ordering for that specific attribute - foreach ($entries as $dn => $entry) { - foreach ($entry as $attr_name => $attr_values) { - sort($entries[$dn][$attr_name]); - if ($order == SORT_DESC) { - array_reverse($entries[$dn][$attr_name]); - } - } - } - - // reformat entrys array for later use with array_multisort() - $to_sort = array(); // <- will be a numeric array similar to ldap_get_entries - foreach ($entries as $dn => $entry_attr) { - $row = array(); - $row['dn'] = $dn; - foreach ($entry_attr as $attr_name => $attr_values) { - $row[$attr_name] = $attr_values; - } - $to_sort[] = $row; - } - - // Build columns for array_multisort() - // each requested attribute is one row - $columns = array(); - foreach ($attrs as $attr_name) { - foreach ($to_sort as $key => $row) { - $columns[$attr_name][$key] =& $to_sort[$key][$attr_name][0]; - } - } - - // sort the colums with array_multisort, if there is something - // to sort and if we have requested sort columns - if (!empty($to_sort) && !empty($columns)) { - $sort_params = ''; - foreach ($attrs as $attr_name) { - $sort_params .= '$columns[\''.$attr_name.'\'], '.$order.', '; - } - eval("array_multisort($sort_params \$to_sort);"); // perform sorting - } - - return $to_sort; - } - - /** - * Return entries sorted as objects - * - * This returns a array with sorted Net_LDAP2_Entry objects. - * The sorting is actually done with {@link sorted_as_struct()}. - * - * Please note that attribute names are case sensitive! - * Also note, that it is (depending on server capabilitys) possible to let - * the server sort your results. This happens through search controls - * and is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt} - * - * Usage example: - * - * // to sort entries first by location, then by surename, but descending: - * $entries = $search->sorted(array('locality','sn'), SORT_DESC); - * - * - * @param array $attrs Array of sort attributes to sort; order from left to right. - * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC - * - * @return array|Net_LDAP2_Error Array with sorted Net_LDAP2_Entries or error - * @todo Entry object construction could be faster. Maybe we could use one of the factorys instead of fetching the entry again - */ - public function sorted($attrs = array('cn'), $order = SORT_ASC) - { - $return = array(); - $sorted = $this->sorted_as_struct($attrs, $order); - if (PEAR::isError($sorted)) { - return $sorted; - } - foreach ($sorted as $key => $row) { - $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttrs()); - if (!PEAR::isError($entry)) { - array_push($return, $entry); - } else { - return $entry; - } - } - return $return; - } - - /** - * Return entries as array - * - * This method returns the entries and the selected attributes values as - * array. - * The first array level contains all found entries where the keys are the - * DNs of the entries. The second level arrays contian the entries attributes - * such that the keys is the lowercased name of the attribute and the values - * are stored in another indexed array. Note that the attribute values are stored - * in an array even if there is no or just one value. - * - * The array has the following structure: - * - * $return = array( - * 'cn=foo,dc=example,dc=com' => array( - * 'sn' => array('foo'), - * 'multival' => array('val1', 'val2', 'valN') - * ) - * 'cn=bar,dc=example,dc=com' => array( - * 'sn' => array('bar'), - * 'multival' => array('val1', 'valN') - * ) - * ) - * - * - * @return array associative result array as described above - */ - public function as_struct() - { - $return = array(); - $entries = $this->entries(); - foreach ($entries as $entry) { - $attrs = array(); - $entry_attributes = $entry->attributes(); - foreach ($entry_attributes as $attr_name) { - $attr_values = $entry->getValue($attr_name, 'all'); - if (!is_array($attr_values)) { - $attr_values = array($attr_values); - } - $attrs[$attr_name] = $attr_values; - } - $return[$entry->dn()] = $attrs; - } - return $return; - } - - /** - * Set the search objects resource link - * - * @param resource &$search Search result identifier - * - * @access public - * @return void - */ - public function setSearch(&$search) - { - $this->_search = $search; - } - - /** - * Set the ldap ressource link - * - * @param resource &$link Link identifier - * - * @access public - * @return void - */ - public function setLink(&$link) - { - $this->_link = $link; - } - - /** - * Returns the number of entries in the searchresult - * - * @return int Number of entries in search. - */ - public function count() - { - // this catches the situation where OL returned errno 32 = no such object! - if (!$this->_search) { - return 0; - } - return @ldap_count_entries($this->_link, $this->_search); - } - - /** - * Get the errorcode the object got in its search. - * - * @return int The ldap error number. - */ - public function getErrorCode() - { - return $this->_errorCode; - } - - /** - * Destructor - * - * @access protected - */ - public function _Net_LDAP2_Search() - { - @ldap_free_result($this->_search); - } - - /** - * Closes search result - * - * @return void - */ - public function done() - { - $this->_Net_LDAP2_Search(); - } - - /** - * Return the attribute names this search selected - * - * @return array - * @see $_searchedAttrs - * @access protected - */ - protected function searchedAttrs() - { - return $this->_searchedAttrs; - } - - /** - * Tells if this search exceeds a sizelimit - * - * @return boolean - */ - public function sizeLimitExceeded() - { - return ($this->getErrorCode() == 4); - } - - - /* - * SPL Iterator interface methods. - * This interface allows to use Net_LDAP2_Search - * objects directly inside a foreach loop! - */ - /** - * SPL Iterator interface: Return the current element. - * - * The SPL Iterator interface allows you to fetch entries inside - * a foreach() loop: foreach ($search as $dn => $entry) { ... - * - * Of course, you may call {@link current()}, {@link key()}, {@link next()}, - * {@link rewind()} and {@link valid()} yourself. - * - * If the search throwed an error, it returns false. - * False is also returned, if the end is reached - * In case no call to next() was made, we will issue one, - * thus returning the first entry. - * - * @return Net_LDAP2_Entry|false - */ - public function current() - { - if (count($this->_iteratorCache) == 0) { - $this->next(); - reset($this->_iteratorCache); - } - $entry = current($this->_iteratorCache); - return ($entry instanceof Net_LDAP2_Entry)? $entry : false; - } - - /** - * SPL Iterator interface: Return the identifying key (DN) of the current entry. - * - * @see current() - * @return string|false DN of the current entry; false in case no entry is returned by current() - */ - public function key() - { - $entry = $this->current(); - return ($entry instanceof Net_LDAP2_Entry)? $entry->dn() :false; - } - - /** - * SPL Iterator interface: Move forward to next entry. - * - * After a call to {@link next()}, {@link current()} will return - * the next entry in the result set. - * - * @see current() - * @return void - */ - public function next() - { - // fetch next entry. - // if we have no entrys anymore, we add false (which is - // returned by shiftEntry()) so current() will complain. - if (count($this->_iteratorCache) - 1 <= $this->count()) { - $this->_iteratorCache[] = $this->shiftEntry(); - } - - // move on array pointer to current element. - // even if we have added all entries, this will - // ensure proper operation in case we rewind() - next($this->_iteratorCache); - } - - /** - * SPL Iterator interface: Check if there is a current element after calls to {@link rewind()} or {@link next()}. - * - * Used to check if we've iterated to the end of the collection. - * - * @see current() - * @return boolean FALSE if there's nothing more to iterate over - */ - public function valid() - { - return ($this->current() instanceof Net_LDAP2_Entry); - } - - /** - * SPL Iterator interface: Rewind the Iterator to the first element. - * - * After rewinding, {@link current()} will return the first entry in the result set. - * - * @see current() - * @return void - */ - public function rewind() - { - reset($this->_iteratorCache); - } -} - -?> diff --git a/extlib/Net/LDAP2/SimpleFileSchemaCache.php b/extlib/Net/LDAP2/SimpleFileSchemaCache.php deleted file mode 100644 index 8019654ac..000000000 --- a/extlib/Net/LDAP2/SimpleFileSchemaCache.php +++ /dev/null @@ -1,97 +0,0 @@ - -* @copyright 2009 Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: SimpleFileSchemaCache.php 286718 2009-08-03 07:30:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* A simple file based schema cacher with cache aging. -* -* Once the cache is too old, the loadSchema() method will return false, so -* Net_LDAP2 will fetch a fresh object from the LDAP server that will -* overwrite the current (outdated) old cache. -*/ -class Net_LDAP2_SimpleFileSchemaCache implements Net_LDAP2_SchemaCache -{ - /** - * Internal config of this cache - * - * @see Net_LDAP2_SimpleFileSchemaCache() - * @var array - */ - protected $config = array( - 'path' => '/tmp/Net_LDAP_Schema.cache', - 'max_age' => 1200 - ); - - /** - * Initialize the simple cache - * - * Config is as following: - * path Complete path to the cache file. - * max_age Maximum age of cache in seconds, 0 means "endlessly". - * - * @param array $cfg Config array - */ - public function Net_LDAP2_SimpleFileSchemaCache($cfg) - { - foreach ($cfg as $key => $value) { - if (array_key_exists($key, $this->config)) { - if (gettype($this->config[$key]) != gettype($value)) { - $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key does not match type ".gettype($this->config[$key])."!"); - } - $this->config[$key] = $value; - } else { - $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key is not defined!"); - } - } - } - - /** - * Return the schema object from the cache - * - * If file is existent and cache has not expired yet, - * then the cache is deserialized and returned. - * - * @return Net_LDAP2_Schema|Net_LDAP2_Error|false - */ - public function loadSchema() - { - $return = false; // Net_LDAP2 will load schema from LDAP - if (file_exists($this->config['path'])) { - $cache_maxage = filemtime($this->config['path']) + $this->config['max_age']; - if (time() <= $cache_maxage || $this->config['max_age'] == 0) { - $return = unserialize(file_get_contents($this->config['path'])); - } - } - return $return; - } - - /** - * Store a schema object in the cache - * - * This method will be called, if Net_LDAP2 has fetched a fresh - * schema object from LDAP and wants to init or refresh the cache. - * - * To invalidate the cache and cause Net_LDAP2 to refresh the cache, - * you can call this method with null or false as value. - * The next call to $ldap->schema() will then refresh the caches object. - * - * @param mixed $schema The object that should be cached - * @return true|Net_LDAP2_Error|false - */ - public function storeSchema($schema) { - file_put_contents($this->config['path'], serialize($schema)); - return true; - } -} diff --git a/extlib/Net/LDAP2/Util.php b/extlib/Net/LDAP2/Util.php deleted file mode 100644 index 48b03f9f9..000000000 --- a/extlib/Net/LDAP2/Util.php +++ /dev/null @@ -1,572 +0,0 @@ - -* @copyright 2009 Benedikt Hallinger -* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 -* @version SVN: $Id: Util.php 286718 2009-08-03 07:30:49Z beni $ -* @link http://pear.php.net/package/Net_LDAP2/ -*/ - -/** -* Includes -*/ -require_once 'PEAR.php'; - -/** -* Utility Class for Net_LDAP2 -* -* This class servers some functionality to the other classes of Net_LDAP2 but most of -* the methods can be used separately as well. -* -* @category Net -* @package Net_LDAP2 -* @author Benedikt Hallinger -* @license http://www.gnu.org/copyleft/lesser.html LGPL -* @link http://pear.php.net/package/Net_LDAP22/ -*/ -class Net_LDAP2_Util extends PEAR -{ - /** - * Constructor - * - * @access public - */ - public function __construct() - { - // We do nothing here, since all methods can be called statically. - // In Net_LDAP <= 0.7, we needed a instance of Util, because - // it was possible to do utf8 encoding and decoding, but this - // has been moved to the LDAP class. The constructor remains only - // here to document the downward compatibility of creating an instance. - } - - /** - * Explodes the given DN into its elements - * - * {@link http://www.ietf.org/rfc/rfc2253.txt RFC 2253} says, a Distinguished Name is a sequence - * of Relative Distinguished Names (RDNs), which themselves - * are sets of Attributes. For each RDN a array is constructed where the RDN part is stored. - * - * For example, the DN 'OU=Sales+CN=J. Smith,DC=example,DC=net' is exploded to: - * array( [0] => array([0] => 'OU=Sales', [1] => 'CN=J. Smith'), [2] => 'DC=example', [3] => 'DC=net' ) - * - * [NOT IMPLEMENTED] DNs might also contain values, which are the bytes of the BER encoding of - * the X.500 AttributeValue rather than some LDAP string syntax. These values are hex-encoded - * and prefixed with a #. To distinguish such BER values, ldap_explode_dn uses references to - * the actual values, e.g. '1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com' is exploded to: - * [ { '1.3.6.1.4.1.1466.0' => "\004\002Hi" }, { 'DC' => 'example' }, { 'DC' => 'com' } ]; - * See {@link http://www.vijaymukhi.com/vmis/berldap.htm} for more information on BER. - * - * It also performs the following operations on the given DN: - * - Unescape "\" followed by ",", "+", """, "\", "<", ">", ";", "#", "=", " ", or a hexpair - * and strings beginning with "#". - * - Removes the leading 'OID.' characters if the type is an OID instead of a name. - * - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order. - * - * OPTIONS is a list of name/value pairs, valid options are: - * casefold Controls case folding of attribute types names. - * Attribute values are not affected by this option. - * The default is to uppercase. Valid values are: - * lower Lowercase attribute types names. - * upper Uppercase attribute type names. This is the default. - * none Do not change attribute type names. - * reverse If TRUE, the RDN sequence is reversed. - * onlyvalues If TRUE, then only attributes values are returned ('foo' instead of 'cn=foo') - * - - * @param string $dn The DN that should be exploded - * @param array $options Options to use - * - * @static - * @return array Parts of the exploded DN - * @todo implement BER - */ - public static function ldap_explode_dn($dn, $options = array('casefold' => 'upper')) - { - if (!isset($options['onlyvalues'])) $options['onlyvalues'] = false; - if (!isset($options['reverse'])) $options['reverse'] = false; - if (!isset($options['casefold'])) $options['casefold'] = 'upper'; - - // Escaping of DN and stripping of "OID." - $dn = self::canonical_dn($dn, array('casefold' => $options['casefold'])); - - // splitting the DN - $dn_array = preg_split('/(?<=[^\\\\]),/', $dn); - - // clear wrong splitting (possibly we have split too much) - // /!\ Not clear, if this is neccessary here - //$dn_array = self::correct_dn_splitting($dn_array, ','); - - // construct subarrays for multivalued RDNs and unescape DN value - // also convert to output format and apply casefolding - foreach ($dn_array as $key => $value) { - $value_u = self::unescape_dn_value($value); - $rdns = self::split_rdn_multival($value_u[0]); - if (count($rdns) > 1) { - // MV RDN! - foreach ($rdns as $subrdn_k => $subrdn_v) { - // Casefolding - if ($options['casefold'] == 'upper') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $subrdn_v); - if ($options['casefold'] == 'lower') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $subrdn_v); - - if ($options['onlyvalues']) { - preg_match('/(.+?)(?", ";", "#", "=" with a special meaning in RFC 2252 - * are preceeded by ba backslash. Control characters with an ASCII code < 32 are represented as \hexpair. - * Finally all leading and trailing spaces are converted to sequences of \20. - * - * @param array $values An array containing the DN values that should be escaped - * - * @static - * @return array The array $values, but escaped - */ - public static function escape_dn_value($values = array()) - { - // Parameter validation - if (!is_array($values)) { - $values = array($values); - } - - foreach ($values as $key => $val) { - // Escaping of filter meta characters - $val = str_replace('\\', '\\\\', $val); - $val = str_replace(',', '\,', $val); - $val = str_replace('+', '\+', $val); - $val = str_replace('"', '\"', $val); - $val = str_replace('<', '\<', $val); - $val = str_replace('>', '\>', $val); - $val = str_replace(';', '\;', $val); - $val = str_replace('#', '\#', $val); - $val = str_replace('=', '\=', $val); - - // ASCII < 32 escaping - $val = self::asc2hex32($val); - - // Convert all leading and trailing spaces to sequences of \20. - if (preg_match('/^(\s*)(.+?)(\s*)$/', $val, $matches)) { - $val = $matches[2]; - for ($i = 0; $i < strlen($matches[1]); $i++) { - $val = '\20'.$val; - } - for ($i = 0; $i < strlen($matches[3]); $i++) { - $val = $val.'\20'; - } - } - - if (null === $val) $val = '\0'; // apply escaped "null" if string is empty - - $values[$key] = $val; - } - - return $values; - } - - /** - * Undoes the conversion done by escape_dn_value(). - * - * Any escape sequence starting with a baskslash - hexpair or special character - - * will be transformed back to the corresponding character. - * - * @param array $values Array of DN Values - * - * @return array Same as $values, but unescaped - * @static - */ - public static function unescape_dn_value($values = array()) - { - // Parameter validation - if (!is_array($values)) { - $values = array($values); - } - - foreach ($values as $key => $val) { - // strip slashes from special chars - $val = str_replace('\\\\', '\\', $val); - $val = str_replace('\,', ',', $val); - $val = str_replace('\+', '+', $val); - $val = str_replace('\"', '"', $val); - $val = str_replace('\<', '<', $val); - $val = str_replace('\>', '>', $val); - $val = str_replace('\;', ';', $val); - $val = str_replace('\#', '#', $val); - $val = str_replace('\=', '=', $val); - - // Translate hex code into ascii - $values[$key] = self::hex2asc($val); - } - - return $values; - } - - /** - * Returns the given DN in a canonical form - * - * Returns false if DN is not a valid Distinguished Name. - * DN can either be a string or an array - * as returned by ldap_explode_dn, which is useful when constructing a DN. - * The DN array may have be indexed (each array value is a OCL=VALUE pair) - * or associative (array key is OCL and value is VALUE). - * - * It performs the following operations on the given DN: - * - Removes the leading 'OID.' characters if the type is an OID instead of a name. - * - Escapes all RFC 2253 special characters (",", "+", """, "\", "<", ">", ";", "#", "="), slashes ("/"), and any other character where the ASCII code is < 32 as \hexpair. - * - Converts all leading and trailing spaces in values to be \20. - * - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order. - * - * OPTIONS is a list of name/value pairs, valid options are: - * casefold Controls case folding of attribute type names. - * Attribute values are not affected by this option. The default is to uppercase. - * Valid values are: - * lower Lowercase attribute type names. - * upper Uppercase attribute type names. This is the default. - * none Do not change attribute type names. - * [NOT IMPLEMENTED] mbcescape If TRUE, characters that are encoded as a multi-octet UTF-8 sequence will be escaped as \(hexpair){2,*}. - * reverse If TRUE, the RDN sequence is reversed. - * separator Separator to use between RDNs. Defaults to comma (','). - * - * Note: The empty string "" is a valid DN, so be sure not to do a "$can_dn == false" test, - * because an empty string evaluates to false. Use the "===" operator instead. - * - * @param array|string $dn The DN - * @param array $options Options to use - * - * @static - * @return false|string The canonical DN or FALSE - * @todo implement option mbcescape - */ - public static function canonical_dn($dn, $options = array('casefold' => 'upper', 'separator' => ',')) - { - if ($dn === '') return $dn; // empty DN is valid! - - // options check - if (!isset($options['reverse'])) { - $options['reverse'] = false; - } else { - $options['reverse'] = true; - } - if (!isset($options['casefold'])) $options['casefold'] = 'upper'; - if (!isset($options['separator'])) $options['separator'] = ','; - - - if (!is_array($dn)) { - // It is not clear to me if the perl implementation splits by the user defined - // separator or if it just uses this separator to construct the new DN - $dn = preg_split('/(?<=[^\\\\])'.$options['separator'].'/', $dn); - - // clear wrong splitting (possibly we have split too much) - $dn = self::correct_dn_splitting($dn, $options['separator']); - } else { - // Is array, check, if the array is indexed or associative - $assoc = false; - foreach ($dn as $dn_key => $dn_part) { - if (!is_int($dn_key)) { - $assoc = true; - } - } - // convert to indexed, if associative array detected - if ($assoc) { - $newdn = array(); - foreach ($dn as $dn_key => $dn_part) { - if (is_array($dn_part)) { - ksort($dn_part, SORT_STRING); // we assume here, that the rdn parts are also associative - $newdn[] = $dn_part; // copy array as-is, so we can resolve it later - } else { - $newdn[] = $dn_key.'='.$dn_part; - } - } - $dn =& $newdn; - } - } - - // Escaping and casefolding - foreach ($dn as $pos => $dnval) { - if (is_array($dnval)) { - // subarray detected, this means very surely, that we had - // a multivalued dn part, which must be resolved - $dnval_new = ''; - foreach ($dnval as $subkey => $subval) { - // build RDN part - if (!is_int($subkey)) { - $subval = $subkey.'='.$subval; - } - $subval_processed = self::canonical_dn($subval); - if (false === $subval_processed) return false; - $dnval_new .= $subval_processed.'+'; - } - $dn[$pos] = substr($dnval_new, 0, -1); // store RDN part, strip last plus - } else { - // try to split multivalued RDNS into array - $rdns = self::split_rdn_multival($dnval); - if (count($rdns) > 1) { - // Multivalued RDN was detected! - // The RDN value is expected to be correctly split by split_rdn_multival(). - // It's time to sort the RDN and build the DN! - $rdn_string = ''; - sort($rdns, SORT_STRING); // Sort RDN keys alphabetically - foreach ($rdns as $rdn) { - $subval_processed = self::canonical_dn($rdn); - if (false === $subval_processed) return false; - $rdn_string .= $subval_processed.'+'; - } - - $dn[$pos] = substr($rdn_string, 0, -1); // store RDN part, strip last plus - - } else { - // no multivalued RDN! - // split at first unescaped "=" - $dn_comp = preg_split('/(?<=[^\\\\])=/', $rdns[0], 2); - $ocl = ltrim($dn_comp[0]); // trim left whitespaces 'cause of "cn=foo, l=bar" syntax (whitespace after comma) - $val = $dn_comp[1]; - - // strip 'OID.', otherwise apply casefolding and escaping - if (substr(strtolower($ocl), 0, 4) == 'oid.') { - $ocl = substr($ocl, 4); - } else { - if ($options['casefold'] == 'upper') $ocl = strtoupper($ocl); - if ($options['casefold'] == 'lower') $ocl = strtolower($ocl); - $ocl = self::escape_dn_value(array($ocl)); - $ocl = $ocl[0]; - } - - // escaping of dn-value - $val = self::escape_dn_value(array($val)); - $val = str_replace('/', '\/', $val[0]); - - $dn[$pos] = $ocl.'='.$val; - } - } - } - - if ($options['reverse']) $dn = array_reverse($dn); - return implode($options['separator'], $dn); - } - - /** - * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters. - * - * Any control characters with an ACII code < 32 as well as the characters with special meaning in - * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a - * backslash followed by two hex digits representing the hexadecimal value of the character. - * - * @param array $values Array of values to escape - * - * @static - * @return array Array $values, but escaped - */ - public static function escape_filter_value($values = array()) - { - // Parameter validation - if (!is_array($values)) { - $values = array($values); - } - - foreach ($values as $key => $val) { - // Escaping of filter meta characters - $val = str_replace('\\', '\5c', $val); - $val = str_replace('*', '\2a', $val); - $val = str_replace('(', '\28', $val); - $val = str_replace(')', '\29', $val); - - // ASCII < 32 escaping - $val = self::asc2hex32($val); - - if (null === $val) $val = '\0'; // apply escaped "null" if string is empty - - $values[$key] = $val; - } - - return $values; - } - - /** - * Undoes the conversion done by {@link escape_filter_value()}. - * - * Converts any sequences of a backslash followed by two hex digits into the corresponding character. - * - * @param array $values Array of values to escape - * - * @static - * @return array Array $values, but unescaped - */ - public static function unescape_filter_value($values = array()) - { - // Parameter validation - if (!is_array($values)) { - $values = array($values); - } - - foreach ($values as $key => $value) { - // Translate hex code into ascii - $values[$key] = self::hex2asc($value); - } - - return $values; - } - - /** - * Converts all ASCII chars < 32 to "\HEX" - * - * @param string $string String to convert - * - * @static - * @return string - */ - public static function asc2hex32($string) - { - for ($i = 0; $i < strlen($string); $i++) { - $char = substr($string, $i, 1); - if (ord($char) < 32) { - $hex = dechex(ord($char)); - if (strlen($hex) == 1) $hex = '0'.$hex; - $string = str_replace($char, '\\'.$hex, $string); - } - } - return $string; - } - - /** - * Converts all Hex expressions ("\HEX") to their original ASCII characters - * - * @param string $string String to convert - * - * @static - * @author beni@php.net, heavily based on work from DavidSmith@byu.net - * @return string - */ - public static function hex2asc($string) - { - $string = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $string); - return $string; - } - - /** - * Split an multivalued RDN value into an Array - * - * A RDN can contain multiple values, spearated by a plus sign. - * This function returns each separate ocl=value pair of the RDN part. - * - * If no multivalued RDN is detected, an array containing only - * the original rdn part is returned. - * - * For example, the multivalued RDN 'OU=Sales+CN=J. Smith' is exploded to: - * array([0] => 'OU=Sales', [1] => 'CN=J. Smith') - * - * The method trys to be smart if it encounters unescaped "+" characters, but may fail, - * so ensure escaped "+"es in attr names and attr values. - * - * [BUG] If you have a multivalued RDN with unescaped plus characters - * and there is a unescaped plus sign at the end of an value followed by an - * attribute name containing an unescaped plus, then you will get wrong splitting: - * $rdn = 'OU=Sales+C+N=J. Smith'; - * returns: - * array('OU=Sales+C', 'N=J. Smith'); - * The "C+" is treaten as value of the first pair instead as attr name of the second pair. - * To prevent this, escape correctly. - * - * @param string $rdn Part of an (multivalued) escaped RDN (eg. ou=foo OR ou=foo+cn=bar) - * - * @static - * @return array Array with the components of the multivalued RDN or Error - */ - public static function split_rdn_multival($rdn) - { - $rdns = preg_split('/(? $dn_value) { - $dn_value = $dn[$key]; // refresh value (foreach caches!) - // if the dn_value is not in attr=value format, then we had an - // unescaped separator character inside the attr name or the value. - // We assume, that it was the attribute value. - // [TODO] To solve this, we might ask the schema. Keep in mind, that UTIL class - // must remain independent from the other classes or connections. - if (!preg_match('/.+(? diff --git a/plugins/LdapCommon/LdapCommon.php b/plugins/LdapCommon/LdapCommon.php index e2ca569f3..ee436d824 100644 --- a/plugins/LdapCommon/LdapCommon.php +++ b/plugins/LdapCommon/LdapCommon.php @@ -31,6 +31,9 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +// We bundle the Net/LDAP2 library... +set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib'); + class LdapCommon { protected static $ldap_connections = array(); diff --git a/plugins/LdapCommon/extlib/Net/LDAP2.php b/plugins/LdapCommon/extlib/Net/LDAP2.php new file mode 100644 index 000000000..26f5e7560 --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2.php @@ -0,0 +1,1791 @@ + +* @author Jan Wagner +* @author Del +* @author Benedikt Hallinger +* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: LDAP2.php 286788 2009-08-04 06:05:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Package includes. +*/ +require_once 'PEAR.php'; +require_once 'Net/LDAP2/RootDSE.php'; +require_once 'Net/LDAP2/Schema.php'; +require_once 'Net/LDAP2/Entry.php'; +require_once 'Net/LDAP2/Search.php'; +require_once 'Net/LDAP2/Util.php'; +require_once 'Net/LDAP2/Filter.php'; +require_once 'Net/LDAP2/LDIF.php'; +require_once 'Net/LDAP2/SchemaCache.interface.php'; +require_once 'Net/LDAP2/SimpleFileSchemaCache.php'; + +/** +* Error constants for errors that are not LDAP errors. +*/ +define('NET_LDAP2_ERROR', 1000); + +/** +* Net_LDAP2 Version +*/ +define('NET_LDAP2_VERSION', '2.0.7'); + +/** +* Net_LDAP2 - manipulate LDAP servers the right way! +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse +* @author Jan Wagner +* @author Del +* @author Benedikt Hallinger +* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP2/ +*/ +class Net_LDAP2 extends PEAR +{ + /** + * Class configuration array + * + * host = the ldap host to connect to + * (may be an array of several hosts to try) + * port = the server port + * version = ldap version (defaults to v 3) + * starttls = when set, ldap_start_tls() is run after connecting. + * bindpw = no explanation needed + * binddn = the DN to bind as. + * basedn = ldap base + * options = hash of ldap options to set (opt => val) + * filter = default search filter + * scope = default search scope + * + * Newly added in 2.0.0RC4, for auto-reconnect: + * auto_reconnect = if set to true then the class will automatically + * attempt to reconnect to the LDAP server in certain + * failure conditionswhen attempting a search, or other + * LDAP operation. Defaults to false. Note that if you + * set this to true, calls to search() may block + * indefinitely if there is a catastrophic server failure. + * min_backoff = minimum reconnection delay period (in seconds). + * current_backoff = initial reconnection delay period (in seconds). + * max_backoff = maximum reconnection delay period (in seconds). + * + * @access protected + * @var array + */ + protected $_config = array('host' => 'localhost', + 'port' => 389, + 'version' => 3, + 'starttls' => false, + 'binddn' => '', + 'bindpw' => '', + 'basedn' => '', + 'options' => array(), + 'filter' => '(objectClass=*)', + 'scope' => 'sub', + 'auto_reconnect' => false, + 'min_backoff' => 1, + 'current_backoff' => 1, + 'max_backoff' => 32); + + /** + * List of hosts we try to establish a connection to + * + * @access protected + * @var array + */ + protected $_host_list = array(); + + /** + * List of hosts that are known to be down. + * + * @access protected + * @var array + */ + protected $_down_host_list = array(); + + /** + * LDAP resource link. + * + * @access protected + * @var resource + */ + protected $_link = false; + + /** + * Net_LDAP2_Schema object + * + * This gets set and returned by {@link schema()} + * + * @access protected + * @var object Net_LDAP2_Schema + */ + protected $_schema = null; + + /** + * Schema cacher function callback + * + * @see registerSchemaCache() + * @var string + */ + protected $_schema_cache = null; + + /** + * Cache for attribute encoding checks + * + * @access protected + * @var array Hash with attribute names as key and boolean value + * to determine whether they should be utf8 encoded or not. + */ + protected $_schemaAttrs = array(); + + /** + * Cache for rootDSE objects + * + * Hash with requested rootDSE attr names as key and rootDSE object as value + * + * Since the RootDSE object itself may request a rootDSE object, + * {@link rootDse()} caches successful requests. + * Internally, Net_LDAP2 needs several lookups to this object, so + * caching increases performance significally. + * + * @access protected + * @var array + */ + protected $_rootDSE_cache = array(); + + /** + * Returns the Net_LDAP2 Release version, may be called statically + * + * @static + * @return string Net_LDAP2 version + */ + public static function getVersion() + { + return NET_LDAP2_VERSION; + } + + /** + * Configure Net_LDAP2, connect and bind + * + * Use this method as starting point of using Net_LDAP2 + * to establish a connection to your LDAP server. + * + * Static function that returns either an error object or the new Net_LDAP2 + * object. Something like a factory. Takes a config array with the needed + * parameters. + * + * @param array $config Configuration array + * + * @access public + * @return Net_LDAP2_Error|Net_LDAP2 Net_LDAP2_Error or Net_LDAP2 object + */ + public static function &connect($config = array()) + { + $ldap_check = self::checkLDAPExtension(); + if (self::iserror($ldap_check)) { + return $ldap_check; + } + + @$obj = new Net_LDAP2($config); + + // todo? better errorhandling for setConfig()? + + // connect and bind with credentials in config + $err = $obj->bind(); + if (self::isError($err)) { + return $err; + } + + return $obj; + } + + /** + * Net_LDAP2 constructor + * + * Sets the config array + * + * Please note that the usual way of getting Net_LDAP2 to work is + * to call something like: + * $ldap = Net_LDAP2::connect($ldap_config); + * + * @param array $config Configuration array + * + * @access protected + * @return void + * @see $_config + */ + public function __construct($config = array()) + { + $this->PEAR('Net_LDAP2_Error'); + $this->setConfig($config); + } + + /** + * Sets the internal configuration array + * + * @param array $config Configuration array + * + * @access protected + * @return void + */ + protected function setConfig($config) + { + // + // Parameter check -- probably should raise an error here if config + // is not an array. + // + if (! is_array($config)) { + return; + } + + foreach ($config as $k => $v) { + if (isset($this->_config[$k])) { + $this->_config[$k] = $v; + } else { + // map old (Net_LDAP2) parms to new ones + switch($k) { + case "dn": + $this->_config["binddn"] = $v; + break; + case "password": + $this->_config["bindpw"] = $v; + break; + case "tls": + $this->_config["starttls"] = $v; + break; + case "base": + $this->_config["basedn"] = $v; + break; + } + } + } + + // + // Ensure the host list is an array. + // + if (is_array($this->_config['host'])) { + $this->_host_list = $this->_config['host']; + } else { + if (strlen($this->_config['host']) > 0) { + $this->_host_list = array($this->_config['host']); + } else { + $this->_host_list = array(); + // ^ this will cause an error in performConnect(), + // so the user is notified about the failure + } + } + + // + // Reset the down host list, which seems like a sensible thing to do + // if the config is being reset for some reason. + // + $this->_down_host_list = array(); + } + + /** + * Bind or rebind to the ldap-server + * + * This function binds with the given dn and password to the server. In case + * no connection has been made yet, it will be started and startTLS issued + * if appropiate. + * + * The internal bind configuration is not being updated, so if you call + * bind() without parameters, you can rebind with the credentials + * provided at first connecting to the server. + * + * @param string $dn Distinguished name for binding + * @param string $password Password for binding + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function bind($dn = null, $password = null) + { + // fetch current bind credentials + if (is_null($dn)) { + $dn = $this->_config["binddn"]; + } + if (is_null($password)) { + $password = $this->_config["bindpw"]; + } + + // Connect first, if we haven't so far. + // This will also bind us to the server. + if ($this->_link === false) { + // store old credentials so we can revert them later + // then overwrite config with new bind credentials + $olddn = $this->_config["binddn"]; + $oldpw = $this->_config["bindpw"]; + + // overwrite bind credentials in config + // so performConnect() knows about them + $this->_config["binddn"] = $dn; + $this->_config["bindpw"] = $password; + + // try to connect with provided credentials + $msg = $this->performConnect(); + + // reset to previous config + $this->_config["binddn"] = $olddn; + $this->_config["bindpw"] = $oldpw; + + // see if bind worked + if (self::isError($msg)) { + return $msg; + } + } else { + // do the requested bind as we are + // asked to bind manually + if (is_null($dn)) { + // anonymous bind + $msg = @ldap_bind($this->_link); + } else { + // privileged bind + $msg = @ldap_bind($this->_link, $dn, $password); + } + if (false === $msg) { + return PEAR::raiseError("Bind failed: " . + @ldap_error($this->_link), + @ldap_errno($this->_link)); + } + } + return true; + } + + /** + * Connect to the ldap-server + * + * This function connects to the LDAP server specified in + * the configuration, binds and set up the LDAP protocol as needed. + * + * @access protected + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + protected function performConnect() + { + // Note: Connecting is briefly described in RFC1777. + // Basicly it works like this: + // 1. set up TCP connection + // 2. secure that connection if neccessary + // 3a. setLDAPVersion to tell server which version we want to speak + // 3b. perform bind + // 3c. setLDAPVersion to tell server which version we want to speak + // together with a test for supported versions + // 4. set additional protocol options + + // Return true if we are already connected. + if ($this->_link !== false) { + return true; + } + + // Connnect to the LDAP server if we are not connected. Note that + // with some LDAP clients, ldapperformConnect returns a link value even + // if no connection is made. We need to do at least one anonymous + // bind to ensure that a connection is actually valid. + // + // Ref: http://www.php.net/manual/en/function.ldap-connect.php + + // Default error message in case all connection attempts + // fail but no message is set + $current_error = new PEAR_Error('Unknown connection error'); + + // Catch empty $_host_list arrays. + if (!is_array($this->_host_list) || count($this->_host_list) == 0) { + $current_error = PEAR::raiseError('No Servers configured! Please '. + 'pass in an array of servers to Net_LDAP2'); + return $current_error; + } + + // Cycle through the host list. + foreach ($this->_host_list as $host) { + + // Ensure we have a valid string for host name + if (is_array($host)) { + $current_error = PEAR::raiseError('No Servers configured! '. + 'Please pass in an one dimensional array of servers to '. + 'Net_LDAP2! (multidimensional array detected!)'); + continue; + } + + // Skip this host if it is known to be down. + if (in_array($host, $this->_down_host_list)) { + continue; + } + + // Record the host that we are actually connecting to in case + // we need it later. + $this->_config['host'] = $host; + + // Attempt a connection. + $this->_link = @ldap_connect($host, $this->_config['port']); + if (false === $this->_link) { + $current_error = PEAR::raiseError('Could not connect to ' . + $host . ':' . $this->_config['port']); + $this->_down_host_list[] = $host; + continue; + } + + // If we're supposed to use TLS, do so before we try to bind, + // as some strict servers only allow binding via secure connections + if ($this->_config["starttls"] === true) { + if (self::isError($msg = $this->startTLS())) { + $current_error = $msg; + $this->_link = false; + $this->_down_host_list[] = $host; + continue; + } + } + + // Try to set the configured LDAP version on the connection if LDAP + // server needs that before binding (eg OpenLDAP). + // This could be necessary since rfc-1777 states that the protocol version + // has to be set at the bind request. + // We use force here which means that the test in the rootDSE is skipped; + // this is neccessary, because some strict LDAP servers only allow to + // read the LDAP rootDSE (which tells us the supported protocol versions) + // with authenticated clients. + // This may fail in which case we try again after binding. + // In this case, most probably the bind() or setLDAPVersion()-call + // below will also fail, providing error messages. + $version_set = false; + $ignored_err = $this->setLDAPVersion(0, true); + if (!self::isError($ignored_err)) { + $version_set = true; + } + + // Attempt to bind to the server. If we have credentials configured, + // we try to use them, otherwise its an anonymous bind. + // As stated by RFC-1777, the bind request should be the first + // operation to be performed after the connection is established. + // This may give an protocol error if the server does not support + // V2 binds and the above call to setLDAPVersion() failed. + // In case the above call failed, we try an V2 bind here and set the + // version afterwards (with checking to the rootDSE). + $msg = $this->bind(); + if (self::isError($msg)) { + // The bind failed, discard link and save error msg. + // Then record the host as down and try next one + if ($msg->getCode() == 0x02 && !$version_set) { + // provide a finer grained error message + // if protocol error arieses because of invalid version + $msg = new Net_LDAP2_Error($msg->getMessage(). + " (could not set LDAP protocol version to ". + $this->_config['version'].")", + $msg->getCode()); + } + $this->_link = false; + $current_error = $msg; + $this->_down_host_list[] = $host; + continue; + } + + // Set desired LDAP version if not successfully set before. + // Here, a check against the rootDSE is performed, so we get a + // error message if the server does not support the version. + // The rootDSE entry should tell us which LDAP versions are + // supported. However, some strict LDAP servers only allow + // bound suers to read the rootDSE. + if (!$version_set) { + if (self::isError($msg = $this->setLDAPVersion())) { + $current_error = $msg; + $this->_link = false; + $this->_down_host_list[] = $host; + continue; + } + } + + // Set LDAP parameters, now we know we have a valid connection. + if (isset($this->_config['options']) && + is_array($this->_config['options']) && + count($this->_config['options'])) { + foreach ($this->_config['options'] as $opt => $val) { + $err = $this->setOption($opt, $val); + if (self::isError($err)) { + $current_error = $err; + $this->_link = false; + $this->_down_host_list[] = $host; + continue 2; + } + } + } + + // At this stage we have connected, bound, and set up options, + // so we have a known good LDAP server. Time to go home. + return true; + } + + + // All connection attempts have failed, return the last error. + return $current_error; + } + + /** + * Reconnect to the ldap-server. + * + * In case the connection to the LDAP + * service has dropped out for some reason, this function will reconnect, + * and re-bind if a bind has been attempted in the past. It is probably + * most useful when the server list provided to the new() or connect() + * function is an array rather than a single host name, because in that + * case it will be able to connect to a failover or secondary server in + * case the primary server goes down. + * + * This doesn't return anything, it just tries to re-establish + * the current connection. It will sleep for the current backoff + * period (seconds) before attempting the connect, and if the + * connection fails it will double the backoff period, but not + * try again. If you want to ensure a reconnection during a + * transient period of server downtime then you need to call this + * function in a loop. + * + * @access protected + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + protected function performReconnect() + { + + // Return true if we are already connected. + if ($this->_link !== false) { + return true; + } + + // Default error message in case all connection attempts + // fail but no message is set + $current_error = new PEAR_Error('Unknown connection error'); + + // Sleep for a backoff period in seconds. + sleep($this->_config['current_backoff']); + + // Retry all available connections. + $this->_down_host_list = array(); + $msg = $this->performConnect(); + + // Bail out if that fails. + if (self::isError($msg)) { + $this->_config['current_backoff'] = + $this->_config['current_backoff'] * 2; + if ($this->_config['current_backoff'] > $this->_config['max_backoff']) { + $this->_config['current_backoff'] = $this->_config['max_backoff']; + } + return $msg; + } + + // Now we should be able to safely (re-)bind. + $msg = $this->bind(); + if (self::isError($msg)) { + $this->_config['current_backoff'] = $this->_config['current_backoff'] * 2; + if ($this->_config['current_backoff'] > $this->_config['max_backoff']) { + $this->_config['current_backoff'] = $this->_config['max_backoff']; + } + + // _config['host'] should have had the last connected host stored in it + // by performConnect(). Since we are unable to bind to that host we can safely + // assume that it is down or has some other problem. + $this->_down_host_list[] = $this->_config['host']; + return $msg; + } + + // At this stage we have connected, bound, and set up options, + // so we have a known good LDAP server. Time to go home. + $this->_config['current_backoff'] = $this->_config['min_backoff']; + return true; + } + + /** + * Starts an encrypted session + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function startTLS() + { + // Test to see if the server supports TLS first. + // This is done via testing the extensions offered by the server. + // The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported. + $rootDSE = $this->rootDse(); + if (self::isError($rootDSE)) { + return $this->raiseError("Unable to fetch rootDSE entry ". + "to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode()); + } + + $supported_extensions = $rootDSE->getValue('supportedExtension'); + if (self::isError($supported_extensions)) { + return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ". + "to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode()); + } + + if (in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) { + if (false === @ldap_start_tls($this->_link)) { + return $this->raiseError("TLS not started: " . + @ldap_error($this->_link), + @ldap_errno($this->_link)); + } + return true; + } else { + return $this->raiseError("Server reports that it does not support TLS"); + } + } + + /** + * alias function of startTLS() for perl-ldap interface + * + * @return void + * @see startTLS() + */ + public function start_tls() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'startTLS' ), $args); + } + + /** + * Close LDAP connection. + * + * Closes the connection. Use this when the session is over. + * + * @return void + */ + public function done() + { + $this->_Net_LDAP2(); + } + + /** + * Alias for {@link done()} + * + * @return void + * @see done() + */ + public function disconnect() + { + $this->done(); + } + + /** + * Destructor + * + * @access protected + */ + public function _Net_LDAP2() + { + @ldap_close($this->_link); + } + + /** + * Add a new entryobject to a directory. + * + * Use add to add a new Net_LDAP2_Entry object to the directory. + * This also links the entry to the connection used for the add, + * if it was a fresh entry ({@link Net_LDAP2_Entry::createFresh()}) + * + * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry + * + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function add(&$entry) + { + if (!$entry instanceof Net_LDAP2_Entry) { + return PEAR::raiseError('Parameter to Net_LDAP2::add() must be a Net_LDAP2_Entry object.'); + } + + // Continue attempting the add operation in a loop until we + // get a success, a definitive failure, or the world ends. + $foo = 0; + while (true) { + $link = $this->getLink(); + + if ($link === false) { + // We do not have a successful connection yet. The call to + // getLink() would have kept trying if we wanted one. Go + // home now. + return PEAR::raiseError("Could not add entry " . $entry->dn() . + " no valid LDAP connection could be found."); + } + + if (@ldap_add($link, $entry->dn(), $entry->getValues())) { + // entry successfully added, we should update its $ldap reference + // in case it is not set so far (fresh entry) + if (!$entry->getLDAP() instanceof Net_LDAP2) { + $entry->setLDAP($this); + } + // store, that the entry is present inside the directory + $entry->markAsNew(false); + return true; + } else { + // We have a failure. What type? We may be able to reconnect + // and try again. + $error_code = @ldap_errno($link); + $error_name = $this->errorMessage($error_code); + + if (($error_name === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + + // The server has become disconnected before trying the + // operation. We should try again, possibly with a different + // server. + $this->_link = false; + $this->performReconnect(); + } else { + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return PEAR::raiseError("Could not add entry " . $entry->dn() . " " . + $error_name, + $error_code); + } + } + } + } + + /** + * Delete an entry from the directory + * + * The object may either be a string representing the dn or a Net_LDAP2_Entry + * object. When the boolean paramter recursive is set, all subentries of the + * entry will be deleted as well. + * + * @param string|Net_LDAP2_Entry $dn DN-string or Net_LDAP2_Entry + * @param boolean $recursive Should we delete all children recursive as well? + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function delete($dn, $recursive = false) + { + if ($dn instanceof Net_LDAP2_Entry) { + $dn = $dn->dn(); + } + if (false === is_string($dn)) { + return PEAR::raiseError("Parameter is not a string nor an entry object!"); + } + // Recursive delete searches for children and calls delete for them + if ($recursive) { + $result = @ldap_list($this->_link, $dn, '(objectClass=*)', array(null), 0, 0); + if (@ldap_count_entries($this->_link, $result)) { + $subentry = @ldap_first_entry($this->_link, $result); + $this->delete(@ldap_get_dn($this->_link, $subentry), true); + while ($subentry = @ldap_next_entry($this->_link, $subentry)) { + $this->delete(@ldap_get_dn($this->_link, $subentry), true); + } + } + } + + // Continue attempting the delete operation in a loop until we + // get a success, a definitive failure, or the world ends. + while (true) { + $link = $this->getLink(); + + if ($link === false) { + // We do not have a successful connection yet. The call to + // getLink() would have kept trying if we wanted one. Go + // home now. + return PEAR::raiseError("Could not add entry " . $dn . + " no valid LDAP connection could be found."); + } + + if (@ldap_delete($link, $dn)) { + // entry successfully deleted. + return true; + } else { + // We have a failure. What type? + // We may be able to reconnect and try again. + $error_code = @ldap_errno($link); + $error_name = $this->errorMessage($error_code); + + if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + // The server has become disconnected before trying the + // operation. We should try again, possibly with a + // different server. + $this->_link = false; + $this->performReconnect(); + + } elseif ($error_code == 66) { + // Subentries present, server refused to delete. + // Deleting subentries is the clients responsibility, but + // since the user may not know of the subentries, we do not + // force that here but instead notify the developer so he + // may take actions himself. + return PEAR::raiseError("Could not delete entry $dn because of subentries. Use the recursive parameter to delete them."); + + } else { + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return PEAR::raiseError("Could not delete entry " . $dn . " " . + $error_name, + $error_code); + } + } + } + } + + /** + * Modify an ldapentry directly on the server + * + * This one takes the DN or a Net_LDAP2_Entry object and an array of actions. + * This array should be something like this: + * + * array('add' => array('attribute1' => array('val1', 'val2'), + * 'attribute2' => array('val1')), + * 'delete' => array('attribute1'), + * 'replace' => array('attribute1' => array('val1')), + * 'changes' => array('add' => ..., + * 'replace' => ..., + * 'delete' => array('attribute1', 'attribute2' => array('val1'))) + * + * The changes array is there so the order of operations can be influenced + * (the operations are done in order of appearance). + * The order of execution is as following: + * 1. adds from 'add' array + * 2. deletes from 'delete' array + * 3. replaces from 'replace' array + * 4. changes (add, replace, delete) in order of appearance + * All subarrays (add, replace, delete, changes) may be given at the same time. + * + * The function calls the corresponding functions of an Net_LDAP2_Entry + * object. A detailed description of array structures can be found there. + * + * Unlike the modification methods provided by the Net_LDAP2_Entry object, + * this method will instantly carry out an update() after each operation, + * thus modifying "directly" on the server. + * + * @param string|Net_LDAP2_Entry $entry DN-string or Net_LDAP2_Entry + * @param array $parms Array of changes + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function modify($entry, $parms = array()) + { + if (is_string($entry)) { + $entry = $this->getEntry($entry); + if (self::isError($entry)) { + return $entry; + } + } + if (!$entry instanceof Net_LDAP2_Entry) { + return PEAR::raiseError("Parameter is not a string nor an entry object!"); + } + + // Perform changes mentioned separately + foreach (array('add', 'delete', 'replace') as $action) { + if (isset($parms[$action])) { + $msg = $entry->$action($parms[$action]); + if (self::isError($msg)) { + return $msg; + } + $entry->setLDAP($this); + + // Because the @ldap functions are called inside Net_LDAP2_Entry::update(), + // we have to trap the error codes issued from that if we want to support + // reconnection. + while (true) { + $msg = $entry->update(); + + if (self::isError($msg)) { + // We have a failure. What type? We may be able to reconnect + // and try again. + $error_code = $msg->getCode(); + $error_name = $this->errorMessage($error_code); + + if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + + // The server has become disconnected before trying the + // operation. We should try again, possibly with a different + // server. + $this->_link = false; + $this->performReconnect(); + + } else { + + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return PEAR::raiseError("Could not modify entry: ".$msg->getMessage()); + } + } else { + // modification succeedet, evaluate next change + break; + } + } + } + } + + // perform combined changes in 'changes' array + if (isset($parms['changes']) && is_array($parms['changes'])) { + foreach ($parms['changes'] as $action => $value) { + + // Because the @ldap functions are called inside Net_LDAP2_Entry::update, + // we have to trap the error codes issued from that if we want to support + // reconnection. + while (true) { + $msg = $this->modify($entry, array($action => $value)); + + if (self::isError($msg)) { + // We have a failure. What type? We may be able to reconnect + // and try again. + $error_code = $msg->getCode(); + $error_name = $this->errorMessage($error_code); + + if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + + // The server has become disconnected before trying the + // operation. We should try again, possibly with a different + // server. + $this->_link = false; + $this->performReconnect(); + + } else { + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return $msg; + } + } else { + // modification succeedet, evaluate next change + break; + } + } + } + } + + return true; + } + + /** + * Run a ldap search query + * + * Search is used to query the ldap-database. + * $base and $filter may be ommitted. The one from config will + * then be used. $base is either a DN-string or an Net_LDAP2_Entry + * object in which case its DN willb e used. + * + * Params may contain: + * + * scope: The scope which will be used for searching + * base - Just one entry + * sub - The whole tree + * one - Immediately below $base + * sizelimit: Limit the number of entries returned (default: 0 = unlimited), + * timelimit: Limit the time spent for searching (default: 0 = unlimited), + * attrsonly: If true, the search will only return the attribute names, + * attributes: Array of attribute names, which the entry should contain. + * It is good practice to limit this to just the ones you need. + * [NOT IMPLEMENTED] + * deref: By default aliases are dereferenced to locate the base object for the search, but not when + * searching subordinates of the base object. This may be changed by specifying one of the + * following values: + * + * never - Do not dereference aliases in searching or in locating the base object of the search. + * search - Dereference aliases in subordinates of the base object in searching, but not in + * locating the base object of the search. + * find + * always + * + * Please note, that you cannot override server side limitations to sizelimit + * and timelimit: You can always only lower a given limit. + * + * @param string|Net_LDAP2_Entry $base LDAP searchbase + * @param string|Net_LDAP2_Filter $filter LDAP search filter or a Net_LDAP2_Filter object + * @param array $params Array of options + * + * @access public + * @return Net_LDAP2_Search|Net_LDAP2_Error Net_LDAP2_Search object or Net_LDAP2_Error object + * @todo implement search controls (sorting etc) + */ + public function search($base = null, $filter = null, $params = array()) + { + if (is_null($base)) { + $base = $this->_config['basedn']; + } + if ($base instanceof Net_LDAP2_Entry) { + $base = $base->dn(); // fetch DN of entry, making searchbase relative to the entry + } + if (is_null($filter)) { + $filter = $this->_config['filter']; + } + if ($filter instanceof Net_LDAP2_Filter) { + $filter = $filter->asString(); // convert Net_LDAP2_Filter to string representation + } + if (PEAR::isError($filter)) { + return $filter; + } + if (PEAR::isError($base)) { + return $base; + } + + /* setting searchparameters */ + (isset($params['sizelimit'])) ? $sizelimit = $params['sizelimit'] : $sizelimit = 0; + (isset($params['timelimit'])) ? $timelimit = $params['timelimit'] : $timelimit = 0; + (isset($params['attrsonly'])) ? $attrsonly = $params['attrsonly'] : $attrsonly = 0; + (isset($params['attributes'])) ? $attributes = $params['attributes'] : $attributes = array(); + + // Ensure $attributes to be an array in case only one + // attribute name was given as string + if (!is_array($attributes)) { + $attributes = array($attributes); + } + + // reorganize the $attributes array index keys + // sometimes there are problems with not consecutive indexes + $attributes = array_values($attributes); + + // scoping makes searches faster! + $scope = (isset($params['scope']) ? $params['scope'] : $this->_config['scope']); + + switch ($scope) { + case 'one': + $search_function = 'ldap_list'; + break; + case 'base': + $search_function = 'ldap_read'; + break; + default: + $search_function = 'ldap_search'; + } + + // Continue attempting the search operation until we get a success + // or a definitive failure. + while (true) { + $link = $this->getLink(); + $search = @call_user_func($search_function, + $link, + $base, + $filter, + $attributes, + $attrsonly, + $sizelimit, + $timelimit); + + if ($err = @ldap_errno($link)) { + if ($err == 32) { + // Errorcode 32 = no such object, i.e. a nullresult. + return $obj = new Net_LDAP2_Search ($search, $this, $attributes); + } elseif ($err == 4) { + // Errorcode 4 = sizelimit exeeded. + return $obj = new Net_LDAP2_Search ($search, $this, $attributes); + } elseif ($err == 87) { + // bad search filter + return $this->raiseError($this->errorMessage($err) . "($filter)", $err); + } elseif (($err == 1) && ($this->_config['auto_reconnect'])) { + // Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect. + $this->_link = false; + $this->performReconnect(); + } else { + $msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope"; + return $this->raiseError($this->errorMessage($err) . $msg, $err); + } + } else { + return $obj = new Net_LDAP2_Search($search, $this, $attributes); + } + } + } + + /** + * Set an LDAP option + * + * @param string $option Option to set + * @param mixed $value Value to set Option to + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function setOption($option, $value) + { + if ($this->_link) { + if (defined($option)) { + if (@ldap_set_option($this->_link, constant($option), $value)) { + return true; + } else { + $err = @ldap_errno($this->_link); + if ($err) { + $msg = @ldap_err2str($err); + } else { + $err = NET_LDAP2_ERROR; + $msg = $this->errorMessage($err); + } + return $this->raiseError($msg, $err); + } + } else { + return $this->raiseError("Unkown Option requested"); + } + } else { + return $this->raiseError("Could not set LDAP option: No LDAP connection"); + } + } + + /** + * Get an LDAP option value + * + * @param string $option Option to get + * + * @access public + * @return Net_LDAP2_Error|string Net_LDAP2_Error or option value + */ + public function getOption($option) + { + if ($this->_link) { + if (defined($option)) { + if (@ldap_get_option($this->_link, constant($option), $value)) { + return $value; + } else { + $err = @ldap_errno($this->_link); + if ($err) { + $msg = @ldap_err2str($err); + } else { + $err = NET_LDAP2_ERROR; + $msg = $this->errorMessage($err); + } + return $this->raiseError($msg, $err); + } + } else { + $this->raiseError("Unkown Option requested"); + } + } else { + $this->raiseError("No LDAP connection"); + } + } + + /** + * Get the LDAP_PROTOCOL_VERSION that is used on the connection. + * + * A lot of ldap functionality is defined by what protocol version the ldap server speaks. + * This might be 2 or 3. + * + * @return int + */ + public function getLDAPVersion() + { + if ($this->_link) { + $version = $this->getOption("LDAP_OPT_PROTOCOL_VERSION"); + } else { + $version = $this->_config['version']; + } + return $version; + } + + /** + * Set the LDAP_PROTOCOL_VERSION that is used on the connection. + * + * @param int $version LDAP-version that should be used + * @param boolean $force If set to true, the check against the rootDSE will be skipped + * + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + * @todo Checking via the rootDSE takes much time - why? fetching and instanciation is quick! + */ + public function setLDAPVersion($version = 0, $force = false) + { + if (!$version) { + $version = $this->_config['version']; + } + + // + // Check to see if the server supports this version first. + // + // Todo: Why is this so horribly slow? + // $this->rootDse() is very fast, as well as Net_LDAP2_RootDSE::fetch() + // seems like a problem at copiyng the object inside PHP?? + // Additionally, this is not always reproducable... + // + if (!$force) { + $rootDSE = $this->rootDse(); + if ($rootDSE instanceof Net_LDAP2_Error) { + return $rootDSE; + } else { + $supported_versions = $rootDSE->getValue('supportedLDAPVersion'); + if (is_string($supported_versions)) { + $supported_versions = array($supported_versions); + } + $check_ok = in_array($version, $supported_versions); + } + } + + if ($force || $check_ok) { + return $this->setOption("LDAP_OPT_PROTOCOL_VERSION", $version); + } else { + return $this->raiseError("LDAP Server does not support protocol version " . $version); + } + } + + + /** + * Tells if a DN does exist in the directory + * + * @param string|Net_LDAP2_Entry $dn The DN of the object to test + * + * @return boolean|Net_LDAP2_Error + */ + public function dnExists($dn) + { + if (PEAR::isError($dn)) { + return $dn; + } + if ($dn instanceof Net_LDAP2_Entry) { + $dn = $dn->dn(); + } + if (false === is_string($dn)) { + return PEAR::raiseError('Parameter $dn is not a string nor an entry object!'); + } + + // make dn relative to parent + $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false)); + if (self::isError($base)) { + return $base; + } + $entry_rdn = array_shift($base); + if (is_array($entry_rdn)) { + // maybe the dn consist of a multivalued RDN, we must build the dn in this case + // because the $entry_rdn is an array! + $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn); + } + $base = Net_LDAP2_Util::canonical_dn($base); + + $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1); + if (@ldap_count_entries($this->_link, $result)) { + return true; + } + if (ldap_errno($this->_link) == 32) { + return false; + } + if (ldap_errno($this->_link) != 0) { + return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link)); + } + return false; + } + + + /** + * Get a specific entry based on the DN + * + * @param string $dn DN of the entry that should be fetched + * @param array $attr Array of Attributes to select. If ommitted, all attributes are fetched. + * + * @return Net_LDAP2_Entry|Net_LDAP2_Error Reference to a Net_LDAP2_Entry object or Net_LDAP2_Error object + * @todo Maybe check against the shema should be done to be sure the attribute type exists + */ + public function &getEntry($dn, $attr = array()) + { + if (!is_array($attr)) { + $attr = array($attr); + } + $result = $this->search($dn, '(objectClass=*)', + array('scope' => 'base', 'attributes' => $attr)); + if (self::isError($result)) { + return $result; + } elseif ($result->count() == 0) { + return PEAR::raiseError('Could not fetch entry '.$dn.': no entry found'); + } + $entry = $result->shiftEntry(); + if (false == $entry) { + return PEAR::raiseError('Could not fetch entry (error retrieving entry from search result)'); + } + return $entry; + } + + /** + * Rename or move an entry + * + * This method will instantly carry out an update() after the move, + * so the entry is moved instantly. + * You can pass an optional Net_LDAP2 object. In this case, a cross directory + * move will be performed which deletes the entry in the source (THIS) directory + * and adds it in the directory $target_ldap. + * A cross directory move will switch the Entrys internal LDAP reference so + * updates to the entry will go to the new directory. + * + * Note that if you want to do a cross directory move, you need to + * pass an Net_LDAP2_Entry object, otherwise the attributes will be empty. + * + * @param string|Net_LDAP2_Entry $entry Entry DN or Entry object + * @param string $newdn New location + * @param Net_LDAP2 $target_ldap (optional) Target directory for cross server move; should be passed via reference + * + * @return Net_LDAP2_Error|true + */ + public function move($entry, $newdn, $target_ldap = null) + { + if (is_string($entry)) { + $entry_o = $this->getEntry($entry); + } else { + $entry_o =& $entry; + } + if (!$entry_o instanceof Net_LDAP2_Entry) { + return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object! (If DN was passed, conversion failed)'); + } + if (null !== $target_ldap && !$target_ldap instanceof Net_LDAP2) { + return PEAR::raiseError('Parameter $target_ldap is expected to be a Net_LDAP2 object!'); + } + + if ($target_ldap && $target_ldap !== $this) { + // cross directory move + if (is_string($entry)) { + return PEAR::raiseError('Unable to perform cross directory move: operation requires a Net_LDAP2_Entry object'); + } + if ($target_ldap->dnExists($newdn)) { + return PEAR::raiseError('Unable to perform cross directory move: entry does exist in target directory'); + } + $entry_o->dn($newdn); + $res = $target_ldap->add($entry_o); + if (self::isError($res)) { + return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in target directory'); + } + $res = $this->delete($entry_o->currentDN()); + if (self::isError($res)) { + $res2 = $target_ldap->delete($entry_o); // undo add + if (self::isError($res2)) { + $add_error_string = 'Additionally, the deletion (undo add) of $entry in target directory failed.'; + } + return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in source directory. '.$add_error_string); + } + $entry_o->setLDAP($target_ldap); + return true; + } else { + // local move + $entry_o->dn($newdn); + $entry_o->setLDAP($this); + return $entry_o->update(); + } + } + + /** + * Copy an entry to a new location + * + * The entry will be immediately copied. + * Please note that only attributes you have + * selected will be copied. + * + * @param Net_LDAP2_Entry &$entry Entry object + * @param string $newdn New FQF-DN of the entry + * + * @return Net_LDAP2_Error|Net_LDAP2_Entry Error Message or reference to the copied entry + */ + public function ©(&$entry, $newdn) + { + if (!$entry instanceof Net_LDAP2_Entry) { + return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object!'); + } + + $newentry = Net_LDAP2_Entry::createFresh($newdn, $entry->getValues()); + $result = $this->add($newentry); + + if ($result instanceof Net_LDAP2_Error) { + return $result; + } else { + return $newentry; + } + } + + + /** + * Returns the string for an ldap errorcode. + * + * Made to be able to make better errorhandling + * Function based on DB::errorMessage() + * Tip: The best description of the errorcodes is found here: + * http://www.directory-info.com/LDAP2/LDAPErrorCodes.html + * + * @param int $errorcode Error code + * + * @return string The errorstring for the error. + */ + public function errorMessage($errorcode) + { + $errorMessages = array( + 0x00 => "LDAP_SUCCESS", + 0x01 => "LDAP_OPERATIONS_ERROR", + 0x02 => "LDAP_PROTOCOL_ERROR", + 0x03 => "LDAP_TIMELIMIT_EXCEEDED", + 0x04 => "LDAP_SIZELIMIT_EXCEEDED", + 0x05 => "LDAP_COMPARE_FALSE", + 0x06 => "LDAP_COMPARE_TRUE", + 0x07 => "LDAP_AUTH_METHOD_NOT_SUPPORTED", + 0x08 => "LDAP_STRONG_AUTH_REQUIRED", + 0x09 => "LDAP_PARTIAL_RESULTS", + 0x0a => "LDAP_REFERRAL", + 0x0b => "LDAP_ADMINLIMIT_EXCEEDED", + 0x0c => "LDAP_UNAVAILABLE_CRITICAL_EXTENSION", + 0x0d => "LDAP_CONFIDENTIALITY_REQUIRED", + 0x0e => "LDAP_SASL_BIND_INPROGRESS", + 0x10 => "LDAP_NO_SUCH_ATTRIBUTE", + 0x11 => "LDAP_UNDEFINED_TYPE", + 0x12 => "LDAP_INAPPROPRIATE_MATCHING", + 0x13 => "LDAP_CONSTRAINT_VIOLATION", + 0x14 => "LDAP_TYPE_OR_VALUE_EXISTS", + 0x15 => "LDAP_INVALID_SYNTAX", + 0x20 => "LDAP_NO_SUCH_OBJECT", + 0x21 => "LDAP_ALIAS_PROBLEM", + 0x22 => "LDAP_INVALID_DN_SYNTAX", + 0x23 => "LDAP_IS_LEAF", + 0x24 => "LDAP_ALIAS_DEREF_PROBLEM", + 0x30 => "LDAP_INAPPROPRIATE_AUTH", + 0x31 => "LDAP_INVALID_CREDENTIALS", + 0x32 => "LDAP_INSUFFICIENT_ACCESS", + 0x33 => "LDAP_BUSY", + 0x34 => "LDAP_UNAVAILABLE", + 0x35 => "LDAP_UNWILLING_TO_PERFORM", + 0x36 => "LDAP_LOOP_DETECT", + 0x3C => "LDAP_SORT_CONTROL_MISSING", + 0x3D => "LDAP_INDEX_RANGE_ERROR", + 0x40 => "LDAP_NAMING_VIOLATION", + 0x41 => "LDAP_OBJECT_CLASS_VIOLATION", + 0x42 => "LDAP_NOT_ALLOWED_ON_NONLEAF", + 0x43 => "LDAP_NOT_ALLOWED_ON_RDN", + 0x44 => "LDAP_ALREADY_EXISTS", + 0x45 => "LDAP_NO_OBJECT_CLASS_MODS", + 0x46 => "LDAP_RESULTS_TOO_LARGE", + 0x47 => "LDAP_AFFECTS_MULTIPLE_DSAS", + 0x50 => "LDAP_OTHER", + 0x51 => "LDAP_SERVER_DOWN", + 0x52 => "LDAP_LOCAL_ERROR", + 0x53 => "LDAP_ENCODING_ERROR", + 0x54 => "LDAP_DECODING_ERROR", + 0x55 => "LDAP_TIMEOUT", + 0x56 => "LDAP_AUTH_UNKNOWN", + 0x57 => "LDAP_FILTER_ERROR", + 0x58 => "LDAP_USER_CANCELLED", + 0x59 => "LDAP_PARAM_ERROR", + 0x5a => "LDAP_NO_MEMORY", + 0x5b => "LDAP_CONNECT_ERROR", + 0x5c => "LDAP_NOT_SUPPORTED", + 0x5d => "LDAP_CONTROL_NOT_FOUND", + 0x5e => "LDAP_NO_RESULTS_RETURNED", + 0x5f => "LDAP_MORE_RESULTS_TO_RETURN", + 0x60 => "LDAP_CLIENT_LOOP", + 0x61 => "LDAP_REFERRAL_LIMIT_EXCEEDED", + 1000 => "Unknown Net_LDAP2 Error" + ); + + return isset($errorMessages[$errorcode]) ? + $errorMessages[$errorcode] : + $errorMessages[NET_LDAP2_ERROR] . ' (' . $errorcode . ')'; + } + + /** + * Gets a rootDSE object + * + * This either fetches a fresh rootDSE object or returns it from + * the internal cache for performance reasons, if possible. + * + * @param array $attrs Array of attributes to search for + * + * @access public + * @return Net_LDAP2_Error|Net_LDAP2_RootDSE Net_LDAP2_Error or Net_LDAP2_RootDSE object + */ + public function &rootDse($attrs = null) + { + if ($attrs !== null && !is_array($attrs)) { + return PEAR::raiseError('Parameter $attr is expected to be an array!'); + } + + $attrs_signature = serialize($attrs); + + // see if we need to fetch a fresh object, or if we already + // requested this object with the same attributes + if (true || !array_key_exists($attrs_signature, $this->_rootDSE_cache)) { + $rootdse =& Net_LDAP2_RootDSE::fetch($this, $attrs); + if ($rootdse instanceof Net_LDAP2_Error) { + return $rootdse; + } + + // search was ok, store rootDSE in cache + $this->_rootDSE_cache[$attrs_signature] = $rootdse; + } + return $this->_rootDSE_cache[$attrs_signature]; + } + + /** + * Alias function of rootDse() for perl-ldap interface + * + * @access public + * @see rootDse() + * @return Net_LDAP2_Error|Net_LDAP2_RootDSE + */ + public function &root_dse() + { + $args = func_get_args(); + return call_user_func_array(array(&$this, 'rootDse'), $args); + } + + /** + * Get a schema object + * + * @param string $dn (optional) Subschema entry dn + * + * @access public + * @return Net_LDAP2_Schema|Net_LDAP2_Error Net_LDAP2_Schema or Net_LDAP2_Error object + */ + public function &schema($dn = null) + { + // Schema caching by Knut-Olav Hoven + // If a schema caching object is registered, we use that to fetch + // a schema object. + // See registerSchemaCache() for more info on this. + if ($this->_schema === null) { + if ($this->_schema_cache) { + $cached_schema = $this->_schema_cache->loadSchema(); + if ($cached_schema instanceof Net_LDAP2_Error) { + return $cached_schema; // route error to client + } else { + if ($cached_schema instanceof Net_LDAP2_Schema) { + $this->_schema = $cached_schema; + } + } + } + } + + // Fetch schema, if not tried before and no cached version available. + // If we are already fetching the schema, we will skip fetching. + if ($this->_schema === null) { + // store a temporary error message so subsequent calls to schema() can + // detect, that we are fetching the schema already. + // Otherwise we will get an infinite loop at Net_LDAP2_Schema::fetch() + $this->_schema = new Net_LDAP2_Error('Schema not initialized'); + $this->_schema = Net_LDAP2_Schema::fetch($this, $dn); + + // If schema caching is active, advise the cache to store the schema + if ($this->_schema_cache) { + $caching_result = $this->_schema_cache->storeSchema($this->_schema); + if ($caching_result instanceof Net_LDAP2_Error) { + return $caching_result; // route error to client + } + } + } + return $this->_schema; + } + + /** + * Enable/disable persistent schema caching + * + * Sometimes it might be useful to allow your scripts to cache + * the schema information on disk, so the schema is not fetched + * every time the script runs which could make your scripts run + * faster. + * + * This method allows you to register a custom object that + * implements your schema cache. Please see the SchemaCache interface + * (SchemaCache.interface.php) for informations on how to implement this. + * To unregister the cache, pass null as $cache parameter. + * + * For ease of use, Net_LDAP2 provides a simple file based cache + * which is used in the example below. You may use this, for example, + * to store the schema in a linux tmpfs which results in the schema + * beeing cached inside the RAM which allows nearly instant access. + * + * // Create the simple file cache object that comes along with Net_LDAP2 + * $mySchemaCache_cfg = array( + * 'path' => '/tmp/Net_LDAP2_Schema.cache', + * 'max_age' => 86400 // max age is 24 hours (in seconds) + * ); + * $mySchemaCache = new Net_LDAP2_SimpleFileSchemaCache($mySchemaCache_cfg); + * $ldap = new Net_LDAP2::connect(...); + * $ldap->registerSchemaCache($mySchemaCache); // enable caching + * // now each call to $ldap->schema() will get the schema from disk! + * + * + * @param Net_LDAP2_SchemaCache|null $cache Object implementing the Net_LDAP2_SchemaCache interface + * + * @return true|Net_LDAP2_Error + */ + public function registerSchemaCache($cache) { + if (is_null($cache) + || (is_object($cache) && in_array('Net_LDAP2_SchemaCache', class_implements($cache))) ) { + $this->_schema_cache = $cache; + return true; + } else { + return new Net_LDAP2_Error('Custom schema caching object is either no '. + 'valid object or does not implement the Net_LDAP2_SchemaCache interface!'); + } + } + + + /** + * Checks if phps ldap-extension is loaded + * + * If it is not loaded, it tries to load it manually using PHPs dl(). + * It knows both windows-dll and *nix-so. + * + * @static + * @return Net_LDAP2_Error|true + */ + public static function checkLDAPExtension() + { + if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { + return new Net_LDAP2_Error("It seems that you do not have the ldap-extension installed. Please install it before using the Net_LDAP2 package."); + } else { + return true; + } + } + + /** + * Encodes given attributes to UTF8 if needed by schema + * + * This function takes attributes in an array and then checks against the schema if they need + * UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and + * can be used for adding or modifying. + * + * $attributes is expected to be an array with keys describing + * the attribute names and the values as the value of this attribute: + * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); + * + * @param array $attributes Array of attributes + * + * @access public + * @return array|Net_LDAP2_Error Array of UTF8 encoded attributes or Error + */ + public function utf8Encode($attributes) + { + return $this->utf8($attributes, 'utf8_encode'); + } + + /** + * Decodes the given attribute values if needed by schema + * + * $attributes is expected to be an array with keys describing + * the attribute names and the values as the value of this attribute: + * $attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2')); + * + * @param array $attributes Array of attributes + * + * @access public + * @see utf8Encode() + * @return array|Net_LDAP2_Error Array with decoded attribute values or Error + */ + public function utf8Decode($attributes) + { + return $this->utf8($attributes, 'utf8_decode'); + } + + /** + * Encodes or decodes attribute values if needed + * + * @param array $attributes Array of attributes + * @param array $function Function to apply to attribute values + * + * @access protected + * @return array|Net_LDAP2_Error Array of attributes with function applied to values or Error + */ + protected function utf8($attributes, $function) + { + if (!is_array($attributes) || array_key_exists(0, $attributes)) { + return PEAR::raiseError('Parameter $attributes is expected to be an associative array'); + } + + if (!$this->_schema) { + $this->_schema = $this->schema(); + } + + if (!$this->_link || self::isError($this->_schema) || !function_exists($function)) { + return $attributes; + } + + if (is_array($attributes) && count($attributes) > 0) { + + foreach ($attributes as $k => $v) { + + if (!isset($this->_schemaAttrs[$k])) { + + $attr = $this->_schema->get('attribute', $k); + if (self::isError($attr)) { + continue; + } + + if (false !== strpos($attr['syntax'], '1.3.6.1.4.1.1466.115.121.1.15')) { + $encode = true; + } else { + $encode = false; + } + $this->_schemaAttrs[$k] = $encode; + + } else { + $encode = $this->_schemaAttrs[$k]; + } + + if ($encode) { + if (is_array($v)) { + foreach ($v as $ak => $av) { + $v[$ak] = call_user_func($function, $av); + } + } else { + $v = call_user_func($function, $v); + } + } + $attributes[$k] = $v; + } + } + return $attributes; + } + + /** + * Get the LDAP link resource. It will loop attempting to + * re-establish the connection if the connection attempt fails and + * auto_reconnect has been turned on (see the _config array documentation). + * + * @access public + * @return resource LDAP link + */ + public function &getLink() + { + if ($this->_config['auto_reconnect']) { + while (true) { + // + // Return the link handle if we are already connected. Otherwise + // try to reconnect. + // + if ($this->_link !== false) { + return $this->_link; + } else { + $this->performReconnect(); + } + } + } + return $this->_link; + } +} + +/** +* Net_LDAP2_Error implements a class for reporting portable LDAP error messages. +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Error extends PEAR_Error +{ + /** + * Net_LDAP2_Error constructor. + * + * @param string $message String with error message. + * @param integer $code Net_LDAP2 error code + * @param integer $mode what "error mode" to operate in + * @param mixed $level what error level to use for $mode & PEAR_ERROR_TRIGGER + * @param mixed $debuginfo additional debug info, such as the last query + * + * @access public + * @see PEAR_Error + */ + public function __construct($message = 'Net_LDAP2_Error', $code = NET_LDAP2_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null) + { + if (is_int($code)) { + $this->PEAR_Error($message . ': ' . Net_LDAP2::errorMessage($code), $code, $mode, $level, $debuginfo); + } else { + $this->PEAR_Error("$message: $code", NET_LDAP2_ERROR, $mode, $level, $debuginfo); + } + } +} + +?> diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Entry.php b/plugins/LdapCommon/extlib/Net/LDAP2/Entry.php new file mode 100644 index 000000000..66de96678 --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/Entry.php @@ -0,0 +1,1055 @@ + +* @author Tarjej Huse +* @author Benedikt Hallinger +* @copyright 2009 Tarjej Huse, Jan Wagner, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: Entry.php 286787 2009-08-04 06:03:12Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; +require_once 'Util.php'; + +/** +* Object representation of a directory entry +* +* This class represents a directory entry. You can add, delete, replace +* attributes and their values, rename the entry, delete the entry. +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner +* @author Tarjej Huse +* @author Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP2/ +*/ +class Net_LDAP2_Entry extends PEAR +{ + /** + * Entry ressource identifier + * + * @access protected + * @var ressource + */ + protected $_entry = null; + + /** + * LDAP ressource identifier + * + * @access protected + * @var ressource + */ + protected $_link = null; + + /** + * Net_LDAP2 object + * + * This object will be used for updating and schema checking + * + * @access protected + * @var object Net_LDAP2 + */ + protected $_ldap = null; + + /** + * Distinguished name of the entry + * + * @access protected + * @var string + */ + protected $_dn = null; + + /** + * Attributes + * + * @access protected + * @var array + */ + protected $_attributes = array(); + + /** + * Original attributes before any modification + * + * @access protected + * @var array + */ + protected $_original = array(); + + + /** + * Map of attribute names + * + * @access protected + * @var array + */ + protected $_map = array(); + + + /** + * Is this a new entry? + * + * @access protected + * @var boolean + */ + protected $_new = true; + + /** + * New distinguished name + * + * @access protected + * @var string + */ + protected $_newdn = null; + + /** + * Shall the entry be deleted? + * + * @access protected + * @var boolean + */ + protected $_delete = false; + + /** + * Map with changes to the entry + * + * @access protected + * @var array + */ + protected $_changes = array("add" => array(), + "delete" => array(), + "replace" => array() + ); + /** + * Internal Constructor + * + * Constructor of the entry. Sets up the distinguished name and the entries + * attributes. + * You should not call this method manually! Use {@link Net_LDAP2_Entry::createFresh()} + * or {@link Net_LDAP2_Entry::createConnected()} instead! + * + * @param Net_LDAP2|ressource|array &$ldap Net_LDAP2 object, ldap-link ressource or array of attributes + * @param string|ressource $entry Either a DN or a LDAP-Entry ressource + * + * @access protected + * @return none + */ + protected function __construct(&$ldap, $entry = null) + { + $this->PEAR('Net_LDAP2_Error'); + + // set up entry resource or DN + if (is_resource($entry)) { + $this->_entry = &$entry; + } else { + $this->_dn = $entry; + } + + // set up LDAP link + if ($ldap instanceof Net_LDAP2) { + $this->_ldap = &$ldap; + $this->_link = $ldap->getLink(); + } elseif (is_resource($ldap)) { + $this->_link = $ldap; + } elseif (is_array($ldap)) { + // Special case: here $ldap is an array of attributes, + // this means, we have no link. This is a "virtual" entry. + // We just set up the attributes so one can work with the object + // as expected, but an update() fails unless setLDAP() is called. + $this->setAttributes($ldap); + } + + // if this is an entry existing in the directory, + // then set up as old and fetch attrs + if (is_resource($this->_entry) && is_resource($this->_link)) { + $this->_new = false; + $this->_dn = @ldap_get_dn($this->_link, $this->_entry); + $this->setAttributes(); // fetch attributes from server + } + } + + /** + * Creates a fresh entry that may be added to the directory later on + * + * Use this method, if you want to initialize a fresh entry. + * + * The method should be called statically: $entry = Net_LDAP2_Entry::createFresh(); + * You should put a 'objectClass' attribute into the $attrs so the directory server + * knows which object you want to create. However, you may omit this in case you + * don't want to add this entry to a directory server. + * + * The attributes parameter is as following: + * + * $attrs = array( 'attribute1' => array('value1', 'value2'), + * 'attribute2' => 'single value' + * ); + * + * + * @param string $dn DN of the Entry + * @param array $attrs Attributes of the entry + * + * @static + * @return Net_LDAP2_Entry|Net_LDAP2_Error + */ + public static function createFresh($dn, $attrs = array()) + { + if (!is_array($attrs)) { + return PEAR::raiseError("Unable to create fresh entry: Parameter \$attrs needs to be an array!"); + } + + $entry = new Net_LDAP2_Entry($attrs, $dn); + return $entry; + } + + /** + * Creates a Net_LDAP2_Entry object out of an ldap entry resource + * + * Use this method, if you want to initialize an entry object that is + * already present in some directory and that you have read manually. + * + * Please note, that if you want to create an entry object that represents + * some already existing entry, you should use {@link createExisting()}. + * + * The method should be called statically: $entry = Net_LDAP2_Entry::createConnected(); + * + * @param Net_LDAP2 $ldap Net_LDA2 object + * @param resource $entry PHP LDAP entry resource + * + * @static + * @return Net_LDAP2_Entry|Net_LDAP2_Error + */ + public static function createConnected($ldap, $entry) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("Unable to create connected entry: Parameter \$ldap needs to be a Net_LDAP2 object!"); + } + if (!is_resource($entry)) { + return PEAR::raiseError("Unable to create connected entry: Parameter \$entry needs to be a ldap entry resource!"); + } + + $entry = new Net_LDAP2_Entry($ldap, $entry); + return $entry; + } + + /** + * Creates an Net_LDAP2_Entry object that is considered already existing + * + * Use this method, if you want to modify an already existing entry + * without fetching it first. + * In most cases however, it is better to fetch the entry via Net_LDAP2->getEntry()! + * + * Please note that you should take care if you construct entries manually with this + * because you may get weird synchronisation problems. + * The attributes and values as well as the entry itself are considered existent + * which may produce errors if you try to modify an entry which doesn't really exist + * or if you try to overwrite some attribute with an value already present. + * + * This method is equal to calling createFresh() and after that markAsNew(FALSE). + * + * The method should be called statically: $entry = Net_LDAP2_Entry::createExisting(); + * + * The attributes parameter is as following: + * + * $attrs = array( 'attribute1' => array('value1', 'value2'), + * 'attribute2' => 'single value' + * ); + * + * + * @param string $dn DN of the Entry + * @param array $attrs Attributes of the entry + * + * @static + * @return Net_LDAP2_Entry|Net_LDAP2_Error + */ + public static function createExisting($dn, $attrs = array()) + { + if (!is_array($attrs)) { + return PEAR::raiseError("Unable to create entry object: Parameter \$attrs needs to be an array!"); + } + + $entry = Net_LDAP2_Entry::createFresh($dn, $attrs); + if ($entry instanceof Net_LDAP2_Error) { + return $entry; + } else { + $entry->markAsNew(false); + return $entry; + } + } + + /** + * Get or set the distinguished name of the entry + * + * If called without an argument the current (or the new DN if set) DN gets returned. + * If you provide an DN, this entry is moved to the new location specified if a DN existed. + * If the DN was not set, the DN gets initialized. Call {@link update()} to actually create + * the new Entry in the directory. + * To fetch the current active DN after setting a new DN but before an update(), you can use + * {@link currentDN()} to retrieve the DN that is currently active. + * + * Please note that special characters (eg german umlauts) should be encoded using utf8_encode(). + * You may use {@link Net_LDAP2_Util::canonical_dn()} for properly encoding of the DN. + * + * @param string $dn New distinguished name + * + * @access public + * @return string|true Distinguished name (or true if a new DN was provided) + */ + public function dn($dn = null) + { + if (false == is_null($dn)) { + if (is_null($this->_dn)) { + $this->_dn = $dn; + } else { + $this->_newdn = $dn; + } + return true; + } + return (isset($this->_newdn) ? $this->_newdn : $this->currentDN()); + } + + /** + * Renames or moves the entry + * + * This is just a convinience alias to {@link dn()} + * to make your code more meaningful. + * + * @param string $newdn The new DN + * + * @return true + */ + public function move($newdn) + { + return $this->dn($newdn); + } + + /** + * Sets the internal attributes array + * + * This fetches the values for the attributes from the server. + * The attribute Syntax will be checked so binary attributes will be returned + * as binary values. + * + * Attributes may be passed directly via the $attributes parameter to setup this + * entry manually. This overrides attribute fetching from the server. + * + * @param array $attributes Attributes to set for this entry + * + * @access protected + * @return void + */ + protected function setAttributes($attributes = null) + { + /* + * fetch attributes from the server + */ + if (is_null($attributes) && is_resource($this->_entry) && is_resource($this->_link)) { + // fetch schema + if ($this->_ldap instanceof Net_LDAP2) { + $schema =& $this->_ldap->schema(); + } + // fetch attributes + $attributes = array(); + do { + if (empty($attr)) { + $ber = null; + $attr = @ldap_first_attribute($this->_link, $this->_entry, $ber); + } else { + $attr = @ldap_next_attribute($this->_link, $this->_entry, $ber); + } + if ($attr) { + $func = 'ldap_get_values'; // standard function to fetch value + + // Try to get binary values as binary data + if ($schema instanceof Net_LDAP2_Schema) { + if ($schema->isBinary($attr)) { + $func = 'ldap_get_values_len'; + } + } + // fetch attribute value (needs error checking?) + $attributes[$attr] = $func($this->_link, $this->_entry, $attr); + } + } while ($attr); + } + + /* + * set attribute data directly, if passed + */ + if (is_array($attributes) && count($attributes) > 0) { + if (isset($attributes["count"]) && is_numeric($attributes["count"])) { + unset($attributes["count"]); + } + foreach ($attributes as $k => $v) { + // attribute names should not be numeric + if (is_numeric($k)) { + continue; + } + // map generic attribute name to real one + $this->_map[strtolower($k)] = $k; + // attribute values should be in an array + if (false == is_array($v)) { + $v = array($v); + } + // remove the value count (comes from ldap server) + if (isset($v["count"])) { + unset($v["count"]); + } + $this->_attributes[$k] = $v; + } + } + + // save a copy for later use + $this->_original = $this->_attributes; + } + + /** + * Get the values of all attributes in a hash + * + * The returned hash has the form + * array('attributename' => 'single value', + * 'attributename' => array('value1', value2', value3')) + * + * @access public + * @return array Hash of all attributes with their values + */ + public function getValues() + { + $attrs = array(); + foreach ($this->_attributes as $attr => $value) { + $attrs[$attr] = $this->getValue($attr); + } + return $attrs; + } + + /** + * Get the value of a specific attribute + * + * The first parameter is the name of the attribute + * The second parameter influences the way the value is returned: + * 'single': only the first value is returned as string + * 'all': all values including the value count are returned in an + * array + * 'default': in all other cases an attribute value with a single value is + * returned as string, if it has multiple values it is returned + * as an array (without value count) + * + * @param string $attr Attribute name + * @param string $option Option + * + * @access public + * @return string|array|PEAR_Error string, array or PEAR_Error + */ + public function getValue($attr, $option = null) + { + $attr = $this->getAttrName($attr); + + if (false == array_key_exists($attr, $this->_attributes)) { + return PEAR::raiseError("Unknown attribute ($attr) requested"); + } + + $value = $this->_attributes[$attr]; + + if ($option == "single" || (count($value) == 1 && $option != 'all')) { + $value = array_shift($value); + } + + return $value; + } + + /** + * Alias function of getValue for perl-ldap interface + * + * @see getValue() + * @return string|array|PEAR_Error + */ + public function get_value() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'getValue' ), $args); + } + + /** + * Returns an array of attributes names + * + * @access public + * @return array Array of attribute names + */ + public function attributes() + { + return array_keys($this->_attributes); + } + + /** + * Returns whether an attribute exists or not + * + * @param string $attr Attribute name + * + * @access public + * @return boolean + */ + public function exists($attr) + { + $attr = $this->getAttrName($attr); + return array_key_exists($attr, $this->_attributes); + } + + /** + * Adds a new attribute or a new value to an existing attribute + * + * The paramter has to be an array of the form: + * array('attributename' => 'single value', + * 'attributename' => array('value1', 'value2)) + * When the attribute already exists the values will be added, else the + * attribute will be created. These changes are local to the entry and do + * not affect the entry on the server until update() is called. + * + * Note, that you can add values of attributes that you haven't selected, but if + * you do so, {@link getValue()} and {@link getValues()} will only return the + * values you added, _NOT_ all values present on the server. To avoid this, just refetch + * the entry after calling {@link update()} or select the attribute. + * + * @param array $attr Attributes to add + * + * @access public + * @return true|Net_LDAP2_Error + */ + public function add($attr = array()) + { + if (false == is_array($attr)) { + return PEAR::raiseError("Parameter must be an array"); + } + foreach ($attr as $k => $v) { + $k = $this->getAttrName($k); + if (false == is_array($v)) { + // Do not add empty values + if ($v == null) { + continue; + } else { + $v = array($v); + } + } + // add new values to existing attribute or add new attribute + if ($this->exists($k)) { + $this->_attributes[$k] = array_unique(array_merge($this->_attributes[$k], $v)); + } else { + $this->_map[strtolower($k)] = $k; + $this->_attributes[$k] = $v; + } + // save changes for update() + if (empty($this->_changes["add"][$k])) { + $this->_changes["add"][$k] = array(); + } + $this->_changes["add"][$k] = array_unique(array_merge($this->_changes["add"][$k], $v)); + } + $return = true; + return $return; + } + + /** + * Deletes an whole attribute or a value or the whole entry + * + * The parameter can be one of the following: + * + * "attributename" - The attribute as a whole will be deleted + * array("attributename1", "attributename2) - All given attributes will be + * deleted + * array("attributename" => "value") - The value will be deleted + * array("attributename" => array("value1", "value2") - The given values + * will be deleted + * If $attr is null or omitted , then the whole Entry will be deleted! + * + * These changes are local to the entry and do + * not affect the entry on the server until {@link update()} is called. + * + * Please note that you must select the attribute (at $ldap->search() for example) + * to be able to delete values of it, Otherwise {@link update()} will silently fail + * and remove nothing. + * + * @param string|array $attr Attributes to delete (NULL or missing to delete whole entry) + * + * @access public + * @return true + */ + public function delete($attr = null) + { + if (is_null($attr)) { + $this->_delete = true; + return true; + } + if (is_string($attr)) { + $attr = array($attr); + } + // Make the assumption that attribute names cannot be numeric, + // therefore this has to be a simple list of attribute names to delete + if (is_numeric(key($attr))) { + foreach ($attr as $name) { + if (is_array($name)) { + // someone mixed modes (list mode but specific values given!) + $del_attr_name = array_search($name, $attr); + $this->delete(array($del_attr_name => $name)); + } else { + // mark for update() if this attr was not marked before + $name = $this->getAttrName($name); + if ($this->exists($name)) { + $this->_changes["delete"][$name] = null; + unset($this->_attributes[$name]); + } + } + } + } else { + // Here we have a hash with "attributename" => "value to delete" + foreach ($attr as $name => $values) { + if (is_int($name)) { + // someone mixed modes and gave us just an attribute name + $this->delete($values); + } else { + // mark for update() if this attr was not marked before; + // this time it must consider the selected values also + $name = $this->getAttrName($name); + if ($this->exists($name)) { + if (false == is_array($values)) { + $values = array($values); + } + // save values to be deleted + if (empty($this->_changes["delete"][$name])) { + $this->_changes["delete"][$name] = array(); + } + $this->_changes["delete"][$name] = + array_unique(array_merge($this->_changes["delete"][$name], $values)); + foreach ($values as $value) { + // find the key for the value that should be deleted + $key = array_search($value, $this->_attributes[$name]); + if (false !== $key) { + // delete the value + unset($this->_attributes[$name][$key]); + } + } + } + } + } + } + $return = true; + return $return; + } + + /** + * Replaces attributes or its values + * + * The parameter has to an array of the following form: + * array("attributename" => "single value", + * "attribute2name" => array("value1", "value2"), + * "deleteme1" => null, + * "deleteme2" => "") + * If the attribute does not yet exist it will be added instead (see also $force). + * If the attribue value is null, the attribute will de deleted. + * + * These changes are local to the entry and do + * not affect the entry on the server until {@link update()} is called. + * + * In some cases you are not allowed to read the attributes value (for + * example the ActiveDirectory attribute unicodePwd) but are allowed to + * replace the value. In this case replace() would assume that the attribute + * is not in the directory yet and tries to add it which will result in an + * LDAP_TYPE_OR_VALUE_EXISTS error. + * To force replace mode instead of add, you can set $force to true. + * + * @param array $attr Attributes to replace + * @param bool $force Force replacing mode in case we can't read the attr value but are allowed to replace it + * + * @access public + * @return true|Net_LDAP2_Error + */ + public function replace($attr = array(), $force = false) + { + if (false == is_array($attr)) { + return PEAR::raiseError("Parameter must be an array"); + } + foreach ($attr as $k => $v) { + $k = $this->getAttrName($k); + if (false == is_array($v)) { + // delete attributes with empty values; treat ints as string + if (is_int($v)) { + $v = "$v"; + } + if ($v == null) { + $this->delete($k); + continue; + } else { + $v = array($v); + } + } + // existing attributes will get replaced + if ($this->exists($k) || $force) { + $this->_changes["replace"][$k] = $v; + $this->_attributes[$k] = $v; + } else { + // new ones just get added + $this->add(array($k => $v)); + } + } + $return = true; + return $return; + } + + /** + * Update the entry on the directory server + * + * This will evaluate all changes made so far and send them + * to the directory server. + * Please note, that if you make changes to objectclasses wich + * have mandatory attributes set, update() will currently fail. + * Remove the entry from the server and readd it as new in such cases. + * This also will deal with problems with setting structural object classes. + * + * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance + * + * @access public + * @return true|Net_LDAP2_Error + * @todo Entry rename with a DN containing special characters needs testing! + */ + public function update($ldap = null) + { + if ($ldap) { + $msg = $this->setLDAP($ldap); + if (Net_LDAP2::isError($msg)) { + return PEAR::raiseError('You passed an invalid $ldap variable to update()'); + } + } + + // ensure we have a valid LDAP object + $ldap =& $this->getLDAP(); + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("The entries LDAP object is not valid"); + } + + // Get and check link + $link = $ldap->getLink(); + if (!is_resource($link)) { + return PEAR::raiseError("Could not update entry: internal LDAP link is invalid"); + } + + /* + * Delete the entry + */ + if (true === $this->_delete) { + return $ldap->delete($this); + } + + /* + * New entry + */ + if (true === $this->_new) { + $msg = $ldap->add($this); + if (Net_LDAP2::isError($msg)) { + return $msg; + } + $this->_new = false; + $this->_changes['add'] = array(); + $this->_changes['delete'] = array(); + $this->_changes['replace'] = array(); + $this->_original = $this->_attributes; + + $return = true; + return $return; + } + + /* + * Rename/move entry + */ + if (false == is_null($this->_newdn)) { + if ($ldap->getLDAPVersion() !== 3) { + return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3"); + } + // make dn relative to parent (needed for ldap rename) + $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false)); + if (Net_LDAP2::isError($parent)) { + return $parent; + } + $child = array_shift($parent); + // maybe the dn consist of a multivalued RDN, we must build the dn in this case + // because the $child-RDN is an array! + if (is_array($child)) { + $child = Net_LDAP2_Util::canonical_dn($child); + } + $parent = Net_LDAP2_Util::canonical_dn($parent); + + // rename/move + if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) { + return PEAR::raiseError("Entry not renamed: " . + @ldap_error($link), @ldap_errno($link)); + } + // reflect changes to local copy + $this->_dn = $this->_newdn; + $this->_newdn = null; + } + + /* + * Carry out modifications to the entry + */ + // ADD + foreach ($this->_changes["add"] as $attr => $value) { + // if attribute exists, add new values + if ($this->exists($attr)) { + if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) { + return PEAR::raiseError("Could not add new values to attribute $attr: " . + @ldap_error($link), @ldap_errno($link)); + } + } else { + // new attribute + if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { + return PEAR::raiseError("Could not add new attribute $attr: " . + @ldap_error($link), @ldap_errno($link)); + } + } + // all went well here, I guess + unset($this->_changes["add"][$attr]); + } + + // DELETE + foreach ($this->_changes["delete"] as $attr => $value) { + // In LDAPv3 you need to specify the old values for deleting + if (is_null($value) && $ldap->getLDAPVersion() === 3) { + $value = $this->_original[$attr]; + } + if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) { + return PEAR::raiseError("Could not delete attribute $attr: " . + @ldap_error($link), @ldap_errno($link)); + } + unset($this->_changes["delete"][$attr]); + } + + // REPLACE + foreach ($this->_changes["replace"] as $attr => $value) { + if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { + return PEAR::raiseError("Could not replace attribute $attr values: " . + @ldap_error($link), @ldap_errno($link)); + } + unset($this->_changes["replace"][$attr]); + } + + // all went well, so _original (server) becomes _attributes (local copy) + $this->_original = $this->_attributes; + + $return = true; + return $return; + } + + /** + * Returns the right attribute name + * + * @param string $attr Name of attribute + * + * @access protected + * @return string The right name of the attribute + */ + protected function getAttrName($attr) + { + $name = strtolower($attr); + if (array_key_exists($name, $this->_map)) { + $attr = $this->_map[$name]; + } + return $attr; + } + + /** + * Returns a reference to the LDAP-Object of this entry + * + * @access public + * @return Net_LDAP2|Net_LDAP2_Error Reference to the Net_LDAP2 Object (the connection) or Net_LDAP2_Error + */ + public function &getLDAP() + { + if (!$this->_ldap instanceof Net_LDAP2) { + $err = new PEAR_Error('LDAP is not a valid Net_LDAP2 object'); + return $err; + } else { + return $this->_ldap; + } + } + + /** + * Sets a reference to the LDAP-Object of this entry + * + * After setting a Net_LDAP2 object, calling update() will use that object for + * updating directory contents. Use this to dynamicly switch directorys. + * + * @param Net_LDAP2 &$ldap Net_LDAP2 object that this entry should be connected to + * + * @access public + * @return true|Net_LDAP2_Error + */ + public function setLDAP(&$ldap) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("LDAP is not a valid Net_LDAP2 object"); + } else { + $this->_ldap =& $ldap; + return true; + } + } + + /** + * Marks the entry as new/existing. + * + * If an Entry is marked as new, it will be added to the directory + * when calling {@link update()}. + * If the entry is marked as old ($mark = false), then the entry is + * assumed to be present in the directory server wich results in + * modification when calling {@link update()}. + * + * @param boolean $mark Value to set, defaults to "true" + * + * @return void + */ + public function markAsNew($mark = true) + { + $this->_new = ($mark)? true : false; + } + + /** + * Applies a regular expression onto a single- or multivalued attribute (like preg_match()) + * + * This method behaves like PHPs preg_match() but with some exceptions. + * If you want to retrieve match information, then you MUST pass the + * $matches parameter via reference! otherwise you will get no matches. + * Since it is possible to have multi valued attributes the $matches + * array will have a additionally numerical dimension (one for each value): + * + * $matches = array( + * 0 => array (usual preg_match() returnarray), + * 1 => array (usual preg_match() returnarray) + * ) + * + * Please note, that $matches will be initialized to an empty array inside. + * + * Usage example: + * + * $result = $entry->preg_match('/089(\d+)/', 'telephoneNumber', &$matches); + * if ( $result === true ){ + * echo "First match: ".$matches[0][1]; // Match of value 1, content of first bracket + * } else { + * if ( Net_LDAP2::isError($result) ) { + * echo "Error: ".$result->getMessage(); + * } else { + * echo "No match found."; + * } + * } + * + * + * Please note that it is important to test for an Net_LDAP2_Error, because objects are + * evaluating to true by default, thus if an error occured, and you only check using "==" then + * you get misleading results. Use the "identical" (===) operator to test for matches to + * avoid this as shown above. + * + * @param string $regex The regular expression + * @param string $attr_name The attribute to search in + * @param array $matches (optional, PASS BY REFERENCE!) Array to store matches in + * + * @return boolean|Net_LDAP2_Error TRUE, if we had a match in one of the values, otherwise false. Net_LDAP2_Error in case something went wrong + */ + public function pregMatch($regex, $attr_name, $matches = array()) + { + $matches = array(); + + // fetch attribute values + $attr = $this->getValue($attr_name, 'all'); + if (Net_LDAP2::isError($attr)) { + return $attr; + } else { + unset($attr['count']); + } + + // perform preg_match() on all values + $match = false; + foreach ($attr as $thisvalue) { + $matches_int = array(); + if (preg_match($regex, $thisvalue, $matches_int)) { + $match = true; + array_push($matches, $matches_int); // store matches in reference + } + } + return $match; + } + + /** + * Alias of {@link pregMatch()} for compatibility to Net_LDAP 1 + * + * @see pregMatch() + * @return boolean|Net_LDAP2_Error + */ + public function preg_match() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'pregMatch' ), $args); + } + + /** + * Tells if the entry is consiedered as new (not present in the server) + * + * Please note, that this doesn't tell you if the entry is present on the server. + * Use {@link Net_LDAP2::dnExists()} to see if an entry is already there. + * + * @return boolean + */ + public function isNew() + { + return $this->_new; + } + + + /** + * Is this entry going to be deleted once update() is called? + * + * @return boolean + */ + public function willBeDeleted() + { + return $this->_delete; + } + + /** + * Is this entry going to be moved once update() is called? + * + * @return boolean + */ + public function willBeMoved() + { + return ($this->dn() !== $this->currentDN()); + } + + /** + * Returns always the original DN + * + * If an entry will be moved but {@link update()} was not called, + * {@link dn()} will return the new DN. This method however, returns + * always the current active DN. + * + * @return string + */ + public function currentDN() + { + return $this->_dn; + } + + /** + * Returns the attribute changes to be carried out once update() is called + * + * @return array + */ + public function getChanges() + { + return $this->_changes; + } +} +?> diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Filter.php b/plugins/LdapCommon/extlib/Net/LDAP2/Filter.php new file mode 100644 index 000000000..0723edab2 --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/Filter.php @@ -0,0 +1,514 @@ + +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: Filter.php 289978 2009-10-27 09:56:41Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; +require_once 'Util.php'; + +/** +* Object representation of a part of a LDAP filter. +* +* This Class is not completely compatible to the PERL interface! +* +* The purpose of this class is, that users can easily build LDAP filters +* without having to worry about right escaping etc. +* A Filter is built using several independent filter objects +* which are combined afterwards. This object works in two +* modes, depending how the object is created. +* If the object is created using the {@link create()} method, then this is a leaf-object. +* If the object is created using the {@link combine()} method, then this is a container object. +* +* LDAP filters are defined in RFC-2254 and can be found under +* {@link http://www.ietf.org/rfc/rfc2254.txt} +* +* Here a quick copy&paste example: +* +* $filter0 = Net_LDAP2_Filter::create('stars', 'equals', '***'); +* $filter_not0 = Net_LDAP2_Filter::combine('not', $filter0); +* +* $filter1 = Net_LDAP2_Filter::create('gn', 'begins', 'bar'); +* $filter2 = Net_LDAP2_Filter::create('gn', 'ends', 'baz'); +* $filter_comp = Net_LDAP2_Filter::combine('or',array($filter_not0, $filter1, $filter2)); +* +* echo $filter_comp->asString(); +* // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz)) +* // The stars in $filter0 are treaten as real stars unless you disable escaping. +* +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP2/ +*/ +class Net_LDAP2_Filter extends PEAR +{ + /** + * Storage for combination of filters + * + * This variable holds a array of filter objects + * that should be combined by this filter object. + * + * @access protected + * @var array + */ + protected $_subfilters = array(); + + /** + * Match of this filter + * + * If this is a leaf filter, then a matching rule is stored, + * if it is a container, then it is a logical operator + * + * @access protected + * @var string + */ + protected $_match; + + /** + * Single filter + * + * If we operate in leaf filter mode, + * then the constructing method stores + * the filter representation here + * + * @acces private + * @var string + */ + protected $_filter; + + /** + * Create a new Net_LDAP2_Filter object and parse $filter. + * + * This is for PERL Net::LDAP interface. + * Construction of Net_LDAP2_Filter objects should happen through either + * {@link create()} or {@link combine()} which give you more control. + * However, you may use the perl iterface if you already have generated filters. + * + * @param string $filter LDAP filter string + * + * @see parse() + */ + public function __construct($filter = false) + { + // The optional parameter must remain here, because otherwise create() crashes + if (false !== $filter) { + $filter_o = self::parse($filter); + if (PEAR::isError($filter_o)) { + $this->_filter = $filter_o; // assign error, so asString() can report it + } else { + $this->_filter = $filter_o->asString(); + } + } + } + + /** + * Constructor of a new part of a LDAP filter. + * + * The following matching rules exists: + * - equals: One of the attributes values is exactly $value + * Please note that case sensitiviness is depends on the + * attributes syntax configured in the server. + * - begins: One of the attributes values must begin with $value + * - ends: One of the attributes values must end with $value + * - contains: One of the attributes values must contain $value + * - present | any: The attribute can contain any value but must be existent + * - greater: The attributes value is greater than $value + * - less: The attributes value is less than $value + * - greaterOrEqual: The attributes value is greater or equal than $value + * - lessOrEqual: The attributes value is less or equal than $value + * - approx: One of the attributes values is similar to $value + * + * If $escape is set to true (default) then $value will be escaped + * properly. If it is set to false then $value will be treaten as raw filter value string. + * You should escape yourself using {@link Net_LDAP2_Util::escape_filter_value()}! + * + * Examples: + * + * // This will find entries that contain an attribute "sn" that ends with "foobar": + * $filter = new Net_LDAP2_Filter('sn', 'ends', 'foobar'); + * + * // This will find entries that contain an attribute "sn" that has any value set: + * $filter = new Net_LDAP2_Filter('sn', 'any'); + * + * + * @param string $attr_name Name of the attribute the filter should apply to + * @param string $match Matching rule (equals, begins, ends, contains, greater, less, greaterOrEqual, lessOrEqual, approx, any) + * @param string $value (optional) if given, then this is used as a filter + * @param boolean $escape Should $value be escaped? (default: yes, see {@link Net_LDAP2_Util::escape_filter_value()} for detailed information) + * + * @return Net_LDAP2_Filter|Net_LDAP2_Error + */ + public static function &create($attr_name, $match, $value = '', $escape = true) + { + $leaf_filter = new Net_LDAP2_Filter(); + if ($escape) { + $array = Net_LDAP2_Util::escape_filter_value(array($value)); + $value = $array[0]; + } + switch (strtolower($match)) { + case 'equals': + $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')'; + break; + case 'begins': + $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)'; + break; + case 'ends': + $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')'; + break; + case 'contains': + $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)'; + break; + case 'greater': + $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')'; + break; + case 'less': + $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')'; + break; + case 'greaterorequal': + case '>=': + $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')'; + break; + case 'lessorequal': + case '<=': + $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')'; + break; + case 'approx': + case '~=': + $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')'; + break; + case 'any': + case 'present': // alias that may improve user code readability + $leaf_filter->_filter = '(' . $attr_name . '=*)'; + break; + default: + return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!'); + } + return $leaf_filter; + } + + /** + * Combine two or more filter objects using a logical operator + * + * This static method combines two or more filter objects and returns one single + * filter object that contains all the others. + * Call this method statically: $filter = Net_LDAP2_Filter('or', array($filter1, $filter2)) + * If the array contains filter strings instead of filter objects, we will try to parse them. + * + * @param string $log_op The locicall operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!" + * @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects + * + * @return Net_LDAP2_Filter|Net_LDAP2_Error + * @static + */ + public static function &combine($log_op, $filters) + { + if (PEAR::isError($filters)) { + return $filters; + } + + // substitude named operators to logical operators + if ($log_op == 'and') $log_op = '&'; + if ($log_op == 'or') $log_op = '|'; + if ($log_op == 'not') $log_op = '!'; + + // tests for sane operation + if ($log_op == '!') { + // Not-combination, here we only accept one filter object or filter string + if ($filters instanceof Net_LDAP2_Filter) { + $filters = array($filters); // force array + } elseif (is_string($filters)) { + $filter_o = self::parse($filters); + if (PEAR::isError($filter_o)) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: '.$filter_o->getMessage()); + return $err; + } else { + $filters = array($filter_o); + } + } elseif (is_array($filters)) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!'); + return $err; + } else { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!'); + return $err; + } + } elseif ($log_op == '&' || $log_op == '|') { + if (!is_array($filters) || count($filters) < 2) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: parameter $filters is not an array or contains less than two Net_LDAP2_Filter objects!'); + return $err; + } + } else { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: logical operator is not known!'); + return $err; + } + + $combined_filter = new Net_LDAP2_Filter(); + foreach ($filters as $key => $testfilter) { // check for errors + if (PEAR::isError($testfilter)) { + return $testfilter; + } elseif (is_string($testfilter)) { + // string found, try to parse into an filter object + $filter_o = self::parse($testfilter); + if (PEAR::isError($filter_o)) { + return $filter_o; + } else { + $filters[$key] = $filter_o; + } + } elseif (!$testfilter instanceof Net_LDAP2_Filter) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: invalid object passed in array $filters!'); + return $err; + } + } + + $combined_filter->_subfilters = $filters; + $combined_filter->_match = $log_op; + return $combined_filter; + } + + /** + * Parse FILTER into a Net_LDAP2_Filter object + * + * This parses an filter string into Net_LDAP2_Filter objects. + * + * @param string $FILTER The filter string + * + * @access static + * @return Net_LDAP2_Filter|Net_LDAP2_Error + * @todo Leaf-mode: Do we need to escape at all? what about *-chars?check for the need of encoding values, tackle problems (see code comments) + */ + public static function parse($FILTER) + { + if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) { + if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) { + // Subfilter processing: pass subfilters to parse() and combine + // the objects using the logical operator detected + // we have now something like "&(...)(...)(...)" but at least one part ("!(...)"). + // Each subfilter could be an arbitary complex subfilter. + + // extract logical operator and filter arguments + $log_op = substr($matches[1], 0, 1); + $remaining_component = substr($matches[1], 1); + + // split $remaining_component into individual subfilters + // we cannot use split() for this, because we do not know the + // complexiness of the subfilter. Thus, we look trough the filter + // string and just recognize ending filters at the first level. + // We record the index number of the char and use that information + // later to split the string. + $sub_index_pos = array(); + $prev_char = ''; // previous character looked at + $level = 0; // denotes the current bracket level we are, + // >1 is too deep, 1 is ok, 0 is outside any + // subcomponent + for ($curpos = 0; $curpos < strlen($remaining_component); $curpos++) { + $cur_char = substr($remaining_component, $curpos, 1); + + // rise/lower bracket level + if ($cur_char == '(' && $prev_char != '\\') { + $level++; + } elseif ($cur_char == ')' && $prev_char != '\\') { + $level--; + } + + if ($cur_char == '(' && $prev_char == ')' && $level == 1) { + array_push($sub_index_pos, $curpos); // mark the position for splitting + } + $prev_char = $cur_char; + } + + // now perform the splits. To get also the last part, we + // need to add the "END" index to the split array + array_push($sub_index_pos, strlen($remaining_component)); + $subfilters = array(); + $oldpos = 0; + foreach ($sub_index_pos as $s_pos) { + $str_part = substr($remaining_component, $oldpos, $s_pos - $oldpos); + array_push($subfilters, $str_part); + $oldpos = $s_pos; + } + + // some error checking... + if (count($subfilters) == 1) { + // only one subfilter found + } elseif (count($subfilters) > 1) { + // several subfilters found + if ($log_op == "!") { + return PEAR::raiseError("Filter parsing error: invalid filter syntax - NOT operator detected but several arguments given!"); + } + } else { + // this should not happen unless the user specified a wrong filter + return PEAR::raiseError("Filter parsing error: invalid filter syntax - got operator '$log_op' but no argument!"); + } + + // Now parse the subfilters into objects and combine them using the operator + $subfilters_o = array(); + foreach ($subfilters as $s_s) { + $o = self::parse($s_s); + if (PEAR::isError($o)) { + return $o; + } else { + array_push($subfilters_o, self::parse($s_s)); + } + } + + $filter_o = self::combine($log_op, $subfilters_o); + return $filter_o; + + } else { + // This is one leaf filter component, do some syntax checks, then escape and build filter_o + // $matches[1] should be now something like "foo=bar" + + // detect multiple leaf components + // [TODO] Maybe this will make problems with filters containing brackets inside the value + if (stristr($matches[1], ')(')) { + return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!"); + } else { + $filter_parts = preg_split('/(?|<|>=|<=)/', $matches[1], 2, PREG_SPLIT_DELIM_CAPTURE); + if (count($filter_parts) != 3) { + return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used"); + } else { + $filter_o = new Net_LDAP2_Filter(); + // [TODO]: Do we need to escape at all? what about *-chars user provide and that should remain special? + // I think, those prevent escaping! We need to check against PERL Net::LDAP! + // $value_arr = Net_LDAP2_Util::escape_filter_value(array($filter_parts[2])); + // $value = $value_arr[0]; + $value = $filter_parts[2]; + $filter_o->_filter = '('.$filter_parts[0].$filter_parts[1].$value.')'; + return $filter_o; + } + } + } + } else { + // ERROR: Filter components must be enclosed in round brackets + return PEAR::raiseError("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets"); + } + } + + /** + * Get the string representation of this filter + * + * This method runs through all filter objects and creates + * the string representation of the filter. If this + * filter object is a leaf filter, then it will return + * the string representation of this filter. + * + * @return string|Net_LDAP2_Error + */ + public function asString() + { + if ($this->isLeaf()) { + $return = $this->_filter; + } else { + $return = ''; + foreach ($this->_subfilters as $filter) { + $return = $return.$filter->asString(); + } + $return = '(' . $this->_match . $return . ')'; + } + return $return; + } + + /** + * Alias for perl interface as_string() + * + * @see asString() + * @return string|Net_LDAP2_Error + */ + public function as_string() + { + return $this->asString(); + } + + /** + * Print the text representation of the filter to FH, or the currently selected output handle if FH is not given + * + * This method is only for compatibility to the perl interface. + * However, the original method was called "print" but due to PHP language restrictions, + * we can't have a print() method. + * + * @param resource $FH (optional) A filehandle resource + * + * @return true|Net_LDAP2_Error + */ + public function printMe($FH = false) + { + if (!is_resource($FH)) { + if (PEAR::isError($FH)) { + return $FH; + } + $filter_str = $this->asString(); + if (PEAR::isError($filter_str)) { + return $filter_str; + } else { + print($filter_str); + } + } else { + $filter_str = $this->asString(); + if (PEAR::isError($filter_str)) { + return $filter_str; + } else { + $res = @fwrite($FH, $this->asString()); + if ($res == false) { + return PEAR::raiseError("Unable to write filter string to filehandle \$FH!"); + } + } + } + return true; + } + + /** + * This can be used to escape a string to provide a valid LDAP-Filter. + * + * LDAP will only recognise certain characters as the + * character istself if they are properly escaped. This is + * what this method does. + * The method can be called statically, so you can use it outside + * for your own purposes (eg for escaping only parts of strings) + * + * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}. + * For upward compatibiliy reasons you are strongly encouraged to use the escape + * methods provided by the Net_LDAP2_Util class. + * + * @param string $value Any string who should be escaped + * + * @static + * @return string The string $string, but escaped + * @deprecated Do not use this method anymore, instead use Net_LDAP2_Util::escape_filter_value() directly + */ + public static function escape($value) + { + $return = Net_LDAP2_Util::escape_filter_value(array($value)); + return $return[0]; + } + + /** + * Is this a container or a leaf filter object? + * + * @access protected + * @return boolean + */ + protected function isLeaf() + { + if (count($this->_subfilters) > 0) { + return false; // Container! + } else { + return true; // Leaf! + } + } +} +?> diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php b/plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php new file mode 100644 index 000000000..34f3e75dd --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php @@ -0,0 +1,922 @@ + +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: LDIF.php 286718 2009-08-03 07:30:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; +require_once 'Net/LDAP2.php'; +require_once 'Net/LDAP2/Entry.php'; +require_once 'Net/LDAP2/Util.php'; + +/** +* LDIF capabilitys for Net_LDAP2, closely taken from PERLs Net::LDAP +* +* It provides a means to convert between Net_LDAP2_Entry objects and LDAP entries +* represented in LDIF format files. Reading and writing are supported and may +* manipulate single entries or lists of entries. +* +* Usage example: +* +* // Read and parse an ldif-file into Net_LDAP2_Entry objects +* // and print out the DNs. Store the entries for later use. +* require 'Net/LDAP2/LDIF.php'; +* $options = array( +* 'onerror' => 'die' +* ); +* $entries = array(); +* $ldif = new Net_LDAP2_LDIF('test.ldif', 'r', $options); +* do { +* $entry = $ldif->read_entry(); +* $dn = $entry->dn(); +* echo " done building entry: $dn\n"; +* array_push($entries, $entry); +* } while (!$ldif->eof()); +* $ldif->done(); +* +* +* // write those entries to another file +* $ldif = new Net_LDAP2_LDIF('test.out.ldif', 'w', $options); +* $ldif->write_entry($entries); +* $ldif->done(); +* +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +* @see http://www.ietf.org/rfc/rfc2849.txt +* @todo Error handling should be PEARified +* @todo LDAPv3 controls are not implemented yet +*/ +class Net_LDAP2_LDIF extends PEAR +{ + /** + * Options + * + * @access protected + * @var array + */ + protected $_options = array('encode' => 'base64', + 'onerror' => null, + 'change' => 0, + 'lowercase' => 0, + 'sort' => 0, + 'version' => null, + 'wrap' => 78, + 'raw' => '' + ); + + /** + * Errorcache + * + * @access protected + * @var array + */ + protected $_error = array('error' => null, + 'line' => 0 + ); + + /** + * Filehandle for read/write + * + * @access protected + * @var array + */ + protected $_FH = null; + + /** + * Says, if we opened the filehandle ourselves + * + * @access protected + * @var array + */ + protected $_FH_opened = false; + + /** + * Linecounter for input file handle + * + * @access protected + * @var array + */ + protected $_input_line = 0; + + /** + * counter for processed entries + * + * @access protected + * @var int + */ + protected $_entrynum = 0; + + /** + * Mode we are working in + * + * Either 'r', 'a' or 'w' + * + * @access protected + * @var string + */ + protected $_mode = false; + + /** + * Tells, if the LDIF version string was already written + * + * @access protected + * @var boolean + */ + protected $_version_written = false; + + /** + * Cache for lines that have build the current entry + * + * @access protected + * @var boolean + */ + protected $_lines_cur = array(); + + /** + * Cache for lines that will build the next entry + * + * @access protected + * @var boolean + */ + protected $_lines_next = array(); + + /** + * Open LDIF file for reading or for writing + * + * new (FILE): + * Open the file read-only. FILE may be the name of a file + * or an already open filehandle. + * If the file doesn't exist, it will be created if in write mode. + * + * new (FILE, MODE, OPTIONS): + * Open the file with the given MODE (see PHPs fopen()), eg "w" or "a". + * FILE may be the name of a file or an already open filehandle. + * PERLs Net_LDAP2 "FILE|" mode does not work curently. + * + * OPTIONS is an associative array and may contain: + * encode => 'none' | 'canonical' | 'base64' + * Some DN values in LDIF cannot be written verbatim and have to be encoded in some way: + * 'none' No encoding. + * 'canonical' See "canonical_dn()" in Net::LDAP::Util. + * 'base64' Use base64. (default, this differs from the Perl interface. + * The perl default is "none"!) + * + * onerror => 'die' | 'warn' | NULL + * Specify what happens when an error is detected. + * 'die' Net_LDAP2_LDIF will croak with an appropriate message. + * 'warn' Net_LDAP2_LDIF will warn (echo) with an appropriate message. + * NULL Net_LDAP2_LDIF will not warn (default), use error(). + * + * change => 1 + * Write entry changes to the LDIF file instead of the entries itself. I.e. write LDAP + * operations acting on the entries to the file instead of the entries contents. + * This writes the changes usually carried out by an update() to the LDIF file. + * + * lowercase => 1 + * Convert attribute names to lowercase when writing. + * + * sort => 1 + * Sort attribute names when writing entries according to the rule: + * objectclass first then all other attributes alphabetically sorted by attribute name + * + * version => '1' + * Set the LDIF version to write to the resulting LDIF file. + * According to RFC 2849 currently the only legal value for this option is 1. + * When this option is set Net_LDAP2_LDIF tries to adhere more strictly to + * the LDIF specification in RFC2489 in a few places. + * The default is NULL meaning no version information is written to the LDIF file. + * + * wrap => 78 + * Number of columns where output line wrapping shall occur. + * Default is 78. Setting it to 40 or lower inhibits wrapping. + * + * raw => REGEX + * Use REGEX to denote the names of attributes that are to be + * considered binary in search results if writing entries. + * Example: raw => "/(?i:^jpegPhoto|;binary)/i" + * + * @param string|ressource $file Filename or filehandle + * @param string $mode Mode to open filename + * @param array $options Options like described above + */ + public function __construct($file, $mode = 'r', $options = array()) + { + $this->PEAR('Net_LDAP2_Error'); // default error class + + // First, parse options + // todo: maybe implement further checks on possible values + foreach ($options as $option => $value) { + if (!array_key_exists($option, $this->_options)) { + $this->dropError('Net_LDAP2_LDIF error: option '.$option.' not known!'); + return; + } else { + $this->_options[$option] = strtolower($value); + } + } + + // setup LDIF class + $this->version($this->_options['version']); + + // setup file mode + if (!preg_match('/^[rwa]\+?$/', $mode)) { + $this->dropError('Net_LDAP2_LDIF error: file mode '.$mode.' not supported!'); + } else { + $this->_mode = $mode; + + // setup filehandle + if (is_resource($file)) { + // TODO: checks on mode possible? + $this->_FH =& $file; + } else { + $imode = substr($this->_mode, 0, 1); + if ($imode == 'r') { + if (!file_exists($file)) { + $this->dropError('Unable to open '.$file.' for read: file not found'); + $this->_mode = false; + } + if (!is_readable($file)) { + $this->dropError('Unable to open '.$file.' for read: permission denied'); + $this->_mode = false; + } + } + + if (($imode == 'w' || $imode == 'a')) { + if (file_exists($file)) { + if (!is_writable($file)) { + $this->dropError('Unable to open '.$file.' for write: permission denied'); + $this->_mode = false; + } + } else { + if (!@touch($file)) { + $this->dropError('Unable to create '.$file.' for write: permission denied'); + $this->_mode = false; + } + } + } + + if ($this->_mode) { + $this->_FH = @fopen($file, $this->_mode); + if (false === $this->_FH) { + // Fallback; should never be reached if tests above are good enough! + $this->dropError('Net_LDAP2_LDIF error: Could not open file '.$file); + } else { + $this->_FH_opened = true; + } + } + } + } + } + + /** + * Read one entry from the file and return it as a Net::LDAP::Entry object. + * + * @return Net_LDAP2_Entry + */ + public function read_entry() + { + // read fresh lines, set them as current lines and create the entry + $attrs = $this->next_lines(true); + if (count($attrs) > 0) { + $this->_lines_cur = $attrs; + } + return $this->current_entry(); + } + + /** + * Returns true when the end of the file is reached. + * + * @return boolean + */ + public function eof() + { + return feof($this->_FH); + } + + /** + * Write the entry or entries to the LDIF file. + * + * If you want to build an LDIF file containing several entries AND + * you want to call write_entry() several times, you must open the filehandle + * in append mode ("a"), otherwise you will always get the last entry only. + * + * @param Net_LDAP2_Entry|array $entries Entry or array of entries + * + * @return void + * @todo implement operations on whole entries (adding a whole entry) + */ + public function write_entry($entries) + { + if (!is_array($entries)) { + $entries = array($entries); + } + + foreach ($entries as $entry) { + $this->_entrynum++; + if (!$entry instanceof Net_LDAP2_Entry) { + $this->dropError('Net_LDAP2_LDIF error: entry '.$this->_entrynum.' is not an Net_LDAP2_Entry object'); + } else { + if ($this->_options['change']) { + // LDIF change mode + // fetch change information from entry + $entry_attrs_changes = $entry->getChanges(); + $num_of_changes = count($entry_attrs_changes['add']) + + count($entry_attrs_changes['replace']) + + count($entry_attrs_changes['delete']); + + $is_changed = ($num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved()); + + // write version if not done yet + // also write DN of entry + if ($is_changed) { + if (!$this->_version_written) { + $this->write_version(); + } + $this->writeDN($entry->currentDN()); + } + + // process changes + // TODO: consider DN add! + if ($entry->willBeDeleted()) { + $this->writeLine("changetype: delete".PHP_EOL); + } elseif ($entry->willBeMoved()) { + $this->writeLine("changetype: modrdn".PHP_EOL); + $olddn = Net_LDAP2_Util::ldap_explode_dn($entry->currentDN(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs + $oldrdn = array_shift($olddn); + $oldparent = implode(',', $olddn); + $newdn = Net_LDAP2_Util::ldap_explode_dn($entry->dn(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs + $rdn = array_shift($newdn); + $parent = implode(',', $newdn); + $this->writeLine("newrdn: ".$rdn.PHP_EOL); + $this->writeLine("deleteoldrdn: 1".PHP_EOL); + if ($parent !== $oldparent) { + $this->writeLine("newsuperior: ".$parent.PHP_EOL); + } + // TODO: What if the entry has attribute changes as well? + // I think we should check for that and make a dummy + // entry with the changes that is written to the LDIF file + } elseif ($num_of_changes > 0) { + // write attribute change data + $this->writeLine("changetype: modify".PHP_EOL); + foreach ($entry_attrs_changes as $changetype => $entry_attrs) { + foreach ($entry_attrs as $attr_name => $attr_values) { + $this->writeLine("$changetype: $attr_name".PHP_EOL); + if ($attr_values !== null) $this->writeAttribute($attr_name, $attr_values, $changetype); + $this->writeLine("-".PHP_EOL); + } + } + } + + // finish this entrys data if we had changes + if ($is_changed) { + $this->finishEntry(); + } + } else { + // LDIF-content mode + // fetch attributes for further processing + $entry_attrs = $entry->getValues(); + + // sort and put objectclass-attrs to first position + if ($this->_options['sort']) { + ksort($entry_attrs); + if (array_key_exists('objectclass', $entry_attrs)) { + $oc = $entry_attrs['objectclass']; + unset($entry_attrs['objectclass']); + $entry_attrs = array_merge(array('objectclass' => $oc), $entry_attrs); + } + } + + // write data + if (!$this->_version_written) { + $this->write_version(); + } + $this->writeDN($entry->dn()); + foreach ($entry_attrs as $attr_name => $attr_values) { + $this->writeAttribute($attr_name, $attr_values); + } + $this->finishEntry(); + } + } + } + } + + /** + * Write version to LDIF + * + * If the object's version is defined, this method allows to explicitely write the version before an entry is written. + * If not called explicitely, it gets called automatically when writing the first entry. + * + * @return void + */ + public function write_version() + { + $this->_version_written = true; + if (!is_null($this->version())) { + return $this->writeLine('version: '.$this->version().PHP_EOL, 'Net_LDAP2_LDIF error: unable to write version'); + } + } + + /** + * Get or set LDIF version + * + * If called without arguments it returns the version of the LDIF file or NULL if no version has been set. + * If called with an argument it sets the LDIF version to VERSION. + * According to RFC 2849 currently the only legal value for VERSION is 1. + * + * @param int $version (optional) LDIF version to set + * + * @return int + */ + public function version($version = null) + { + if ($version !== null) { + if ($version != 1) { + $this->dropError('Net_LDAP2_LDIF error: illegal LDIF version set'); + } else { + $this->_options['version'] = $version; + } + } + return $this->_options['version']; + } + + /** + * Returns the file handle the Net_LDAP2_LDIF object reads from or writes to. + * + * You can, for example, use this to fetch the content of the LDIF file yourself + * + * @return null|resource + */ + public function &handle() + { + if (!is_resource($this->_FH)) { + $this->dropError('Net_LDAP2_LDIF error: invalid file resource'); + $null = null; + return $null; + } else { + return $this->_FH; + } + } + + /** + * Clean up + * + * This method signals that the LDIF object is no longer needed. + * You can use this to free up some memory and close the file handle. + * The file handle is only closed, if it was opened from Net_LDAP2_LDIF. + * + * @return void + */ + public function done() + { + // close FH if we opened it + if ($this->_FH_opened) { + fclose($this->handle()); + } + + // free variables + foreach (get_object_vars($this) as $name => $value) { + unset($this->$name); + } + } + + /** + * Returns last error message if error was found. + * + * Example: + * + * $ldif->someAction(); + * if ($ldif->error()) { + * echo "Error: ".$ldif->error()." at input line: ".$ldif->error_lines(); + * } + * + * + * @param boolean $as_string If set to true, only the message is returned + * + * @return false|Net_LDAP2_Error + */ + public function error($as_string = false) + { + if (Net_LDAP2::isError($this->_error['error'])) { + return ($as_string)? $this->_error['error']->getMessage() : $this->_error['error']; + } else { + return false; + } + } + + /** + * Returns lines that resulted in error. + * + * Perl returns an array of faulty lines in list context, + * but we always just return an int because of PHPs language. + * + * @return int + */ + public function error_lines() + { + return $this->_error['line']; + } + + /** + * Returns the current Net::LDAP::Entry object. + * + * @return Net_LDAP2_Entry|false + */ + public function current_entry() + { + return $this->parseLines($this->current_lines()); + } + + /** + * Parse LDIF lines of one entry into an Net_LDAP2_Entry object + * + * @param array $lines LDIF lines for one entry + * + * @return Net_LDAP2_Entry|false Net_LDAP2_Entry object for those lines + * @todo what about file inclusions and urls? "jpegphoto:< file:///usr/local/directory/photos/fiona.jpg" + */ + public function parseLines($lines) + { + // parse lines into an array of attributes and build the entry + $attributes = array(); + $dn = false; + foreach ($lines as $line) { + if (preg_match('/^(\w+)(:|::|:<)\s(.+)$/', $line, $matches)) { + $attr =& $matches[1]; + $delim =& $matches[2]; + $data =& $matches[3]; + + if ($delim == ':') { + // normal data + $attributes[$attr][] = $data; + } elseif ($delim == '::') { + // base64 data + $attributes[$attr][] = base64_decode($data); + } elseif ($delim == ':<') { + // file inclusion + // TODO: Is this the job of the LDAP-client or the server? + $this->dropError('File inclusions are currently not supported'); + //$attributes[$attr][] = ...; + } else { + // since the pattern above, the delimeter cannot be something else. + $this->dropError('Net_LDAP2_LDIF parsing error: invalid syntax at parsing entry line: '.$line); + continue; + } + + if (strtolower($attr) == 'dn') { + // DN line detected + $dn = $attributes[$attr][0]; // save possibly decoded DN + unset($attributes[$attr]); // remove wrongly added "dn: " attribute + } + } else { + // line not in "attr: value" format -> ignore + // maybe we should rise an error here, but this should be covered by + // next_lines() already. A problem arises, if users try to feed data of + // several entries to this method - the resulting entry will + // get wrong attributes. However, this is already mentioned in the + // methods documentation above. + } + } + + if (false === $dn) { + $this->dropError('Net_LDAP2_LDIF parsing error: unable to detect DN for entry'); + return false; + } else { + $newentry = Net_LDAP2_Entry::createFresh($dn, $attributes); + return $newentry; + } + } + + /** + * Returns the lines that generated the current Net::LDAP::Entry object. + * + * Note that this returns an empty array if no lines have been read so far. + * + * @return array Array of lines + */ + public function current_lines() + { + return $this->_lines_cur; + } + + /** + * Returns the lines that will generate the next Net::LDAP::Entry object. + * + * If you set $force to TRUE then you can iterate over the lines that build + * up entries manually. Otherwise, iterating is done using {@link read_entry()}. + * Force will move the file pointer forward, thus returning the next entries lines. + * + * Wrapped lines will be unwrapped. Comments are stripped. + * + * @param boolean $force Set this to true if you want to iterate over the lines manually + * + * @return array + */ + public function next_lines($force = false) + { + // if we already have those lines, just return them, otherwise read + if (count($this->_lines_next) == 0 || $force) { + $this->_lines_next = array(); // empty in case something was left (if used $force) + $entry_done = false; + $fh = &$this->handle(); + $commentmode = false; // if we are in an comment, for wrapping purposes + $datalines_read = 0; // how many lines with data we have read + + while (!$entry_done && !$this->eof()) { + $this->_input_line++; + // Read line. Remove line endings, we want only data; + // this is okay since ending spaces should be encoded + $data = rtrim(fgets($fh)); + if ($data === false) { + // error only, if EOF not reached after fgets() call + if (!$this->eof()) { + $this->dropError('Net_LDAP2_LDIF error: error reading from file at input line '.$this->_input_line, $this->_input_line); + } + break; + } else { + if (count($this->_lines_next) > 0 && preg_match('/^$/', $data)) { + // Entry is finished if we have an empty line after we had data + $entry_done = true; + + // Look ahead if the next EOF is nearby. Comments and empty + // lines at the file end may cause problems otherwise + $current_pos = ftell($fh); + $data = fgets($fh); + while (!feof($fh)) { + if (preg_match('/^\s*$/', $data) || preg_match('/^#/', $data)) { + // only empty lines or comments, continue to seek + // TODO: Known bug: Wrappings for comments are okay but are treaten as + // error, since we do not honor comment mode here. + // This should be a very theoretically case, however + // i am willing to fix this if really necessary. + $this->_input_line++; + $current_pos = ftell($fh); + $data = fgets($fh); + } else { + // Data found if non emtpy line and not a comment!! + // Rewind to position prior last read and stop lookahead + fseek($fh, $current_pos); + break; + } + } + // now we have either the file pointer at the beginning of + // a new data position or at the end of file causing feof() to return true + + } else { + // build lines + if (preg_match('/^version:\s(.+)$/', $data, $match)) { + // version statement, set version + $this->version($match[1]); + } elseif (preg_match('/^\w+::?\s.+$/', $data)) { + // normal attribute: add line + $commentmode = false; + $this->_lines_next[] = trim($data); + $datalines_read++; + } elseif (preg_match('/^\s(.+)$/', $data, $matches)) { + // wrapped data: unwrap if not in comment mode + if (!$commentmode) { + if ($datalines_read == 0) { + // first line of entry: wrapped data is illegal + $this->dropError('Net_LDAP2_LDIF error: illegal wrapping at input line '.$this->_input_line, $this->_input_line); + } else { + $last = array_pop($this->_lines_next); + $last = $last.trim($matches[1]); + $this->_lines_next[] = $last; + $datalines_read++; + } + } + } elseif (preg_match('/^#/', $data)) { + // LDIF comments + $commentmode = true; + } elseif (preg_match('/^\s*$/', $data)) { + // empty line but we had no data for this + // entry, so just ignore this line + $commentmode = false; + } else { + $this->dropError('Net_LDAP2_LDIF error: invalid syntax at input line '.$this->_input_line, $this->_input_line); + continue; + } + + } + } + } + } + return $this->_lines_next; + } + + /** + * Convert an attribute and value to LDIF string representation + * + * It honors correct encoding of values according to RFC 2849. + * Line wrapping will occur at the configured maximum but only if + * the value is greater than 40 chars. + * + * @param string $attr_name Name of the attribute + * @param string $attr_value Value of the attribute + * + * @access protected + * @return string LDIF string for that attribute and value + */ + protected function convertAttribute($attr_name, $attr_value) + { + // Handle empty attribute or process + if (strlen($attr_value) == 0) { + $attr_value = " "; + } else { + $base64 = false; + // ASCII-chars that are NOT safe for the + // start and for being inside the value. + // These are the int values of those chars. + $unsafe_init = array(0, 10, 13, 32, 58, 60); + $unsafe = array(0, 10, 13); + + // Test for illegal init char + $init_ord = ord(substr($attr_value, 0, 1)); + if ($init_ord > 127 || in_array($init_ord, $unsafe_init)) { + $base64 = true; + } + + // Test for illegal content char + for ($i = 0; $i < strlen($attr_value); $i++) { + $char_ord = ord(substr($attr_value, $i, 1)); + if ($char_ord > 127 || in_array($char_ord, $unsafe)) { + $base64 = true; + } + } + + // Test for ending space + if (substr($attr_value, -1) == ' ') { + $base64 = true; + } + + // If converting is needed, do it + // Either we have some special chars or a matching "raw" regex + if ($base64 || ($this->_options['raw'] && preg_match($this->_options['raw'], $attr_name))) { + $attr_name .= ':'; + $attr_value = base64_encode($attr_value); + } + + // Lowercase attr names if requested + if ($this->_options['lowercase']) $attr_name = strtolower($attr_name); + + // Handle line wrapping + if ($this->_options['wrap'] > 40 && strlen($attr_value) > $this->_options['wrap']) { + $attr_value = wordwrap($attr_value, $this->_options['wrap'], PHP_EOL." ", true); + } + } + + return $attr_name.': '.$attr_value; + } + + /** + * Convert an entries DN to LDIF string representation + * + * It honors correct encoding of values according to RFC 2849. + * + * @param string $dn UTF8-Encoded DN + * + * @access protected + * @return string LDIF string for that DN + * @todo I am not sure, if the UTF8 stuff is correctly handled right now + */ + protected function convertDN($dn) + { + $base64 = false; + // ASCII-chars that are NOT safe for the + // start and for being inside the dn. + // These are the int values of those chars. + $unsafe_init = array(0, 10, 13, 32, 58, 60); + $unsafe = array(0, 10, 13); + + // Test for illegal init char + $init_ord = ord(substr($dn, 0, 1)); + if ($init_ord >= 127 || in_array($init_ord, $unsafe_init)) { + $base64 = true; + } + + // Test for illegal content char + for ($i = 0; $i < strlen($dn); $i++) { + $char = substr($dn, $i, 1); + if (ord($char) >= 127 || in_array($init_ord, $unsafe)) { + $base64 = true; + } + } + + // Test for ending space + if (substr($dn, -1) == ' ') { + $base64 = true; + } + + // if converting is needed, do it + return ($base64)? 'dn:: '.base64_encode($dn) : 'dn: '.$dn; + } + + /** + * Writes an attribute to the filehandle + * + * @param string $attr_name Name of the attribute + * @param string|array $attr_values Single attribute value or array with attribute values + * + * @access protected + * @return void + */ + protected function writeAttribute($attr_name, $attr_values) + { + // write out attribute content + if (!is_array($attr_values)) { + $attr_values = array($attr_values); + } + foreach ($attr_values as $attr_val) { + $line = $this->convertAttribute($attr_name, $attr_val).PHP_EOL; + $this->writeLine($line, 'Net_LDAP2_LDIF error: unable to write attribute '.$attr_name.' of entry '.$this->_entrynum); + } + } + + /** + * Writes a DN to the filehandle + * + * @param string $dn DN to write + * + * @access protected + * @return void + */ + protected function writeDN($dn) + { + // prepare DN + if ($this->_options['encode'] == 'base64') { + $dn = $this->convertDN($dn).PHP_EOL; + } elseif ($this->_options['encode'] == 'canonical') { + $dn = Net_LDAP2_Util::canonical_dn($dn, array('casefold' => 'none')).PHP_EOL; + } else { + $dn = $dn.PHP_EOL; + } + $this->writeLine($dn, 'Net_LDAP2_LDIF error: unable to write DN of entry '.$this->_entrynum); + } + + /** + * Finishes an LDIF entry + * + * @access protected + * @return void + */ + protected function finishEntry() + { + $this->writeLine(PHP_EOL, 'Net_LDAP2_LDIF error: unable to close entry '.$this->_entrynum); + } + + /** + * Just write an arbitary line to the filehandle + * + * @param string $line Content to write + * @param string $error If error occurs, drop this message + * + * @access protected + * @return true|false + */ + protected function writeLine($line, $error = 'Net_LDAP2_LDIF error: unable to write to filehandle') + { + if (is_resource($this->handle()) && fwrite($this->handle(), $line, strlen($line)) === false) { + $this->dropError($error); + return false; + } else { + return true; + } + } + + /** + * Optionally raises an error and pushes the error on the error cache + * + * @param string $msg Errortext + * @param int $line Line in the LDIF that caused the error + * + * @access protected + * @return void + */ + protected function dropError($msg, $line = null) + { + $this->_error['error'] = new Net_LDAP2_Error($msg); + if ($line !== null) $this->_error['line'] = $line; + + if ($this->_options['onerror'] == 'die') { + die($msg.PHP_EOL); + } elseif ($this->_options['onerror'] == 'warn') { + echo $msg.PHP_EOL; + } + } +} +?> diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php b/plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php new file mode 100644 index 000000000..8dc81fd4f --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php @@ -0,0 +1,240 @@ + +* @copyright 2009 Jan Wagner +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: RootDSE.php 286718 2009-08-03 07:30:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Getting the rootDSE entry of a LDAP server +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_RootDSE extends PEAR +{ + /** + * @access protected + * @var object Net_LDAP2_Entry + **/ + protected $_entry; + + /** + * Class constructor + * + * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry object of the RootDSE + */ + protected function __construct(&$entry) + { + $this->_entry = $entry; + } + + /** + * Fetches a RootDSE object from an LDAP connection + * + * @param Net_LDAP2 $ldap Directory from which the RootDSE should be fetched + * @param array $attrs Array of attributes to search for + * + * @access static + * @return Net_LDAP2_RootDSE|Net_LDAP2_Error + */ + public static function fetch($ldap, $attrs = null) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!"); + } + + if (is_array($attrs) && count($attrs) > 0 ) { + $attributes = $attrs; + } else { + $attributes = array('vendorName', + 'vendorVersion', + 'namingContexts', + 'altServer', + 'supportedExtension', + 'supportedControl', + 'supportedSASLMechanisms', + 'supportedLDAPVersion', + 'subschemaSubentry' ); + } + $result = $ldap->search('', '(objectClass=*)', array('attributes' => $attributes, 'scope' => 'base')); + if (self::isError($result)) { + return $result; + } + $entry = $result->shiftEntry(); + if (false === $entry) { + return PEAR::raiseError('Could not fetch RootDSE entry'); + } + $ret = new Net_LDAP2_RootDSE($entry); + return $ret; + } + + /** + * Gets the requested attribute value + * + * Same usuage as {@link Net_LDAP2_Entry::getValue()} + * + * @param string $attr Attribute name + * @param array $options Array of options + * + * @access public + * @return mixed Net_LDAP2_Error object or attribute values + * @see Net_LDAP2_Entry::get_value() + */ + public function getValue($attr = '', $options = '') + { + return $this->_entry->get_value($attr, $options); + } + + /** + * Alias function of getValue() for perl-ldap interface + * + * @see getValue() + * @return mixed + */ + public function get_value() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'getValue' ), $args); + } + + /** + * Determines if the extension is supported + * + * @param array $oids Array of oids to check + * + * @access public + * @return boolean + */ + public function supportedExtension($oids) + { + return $this->checkAttr($oids, 'supportedExtension'); + } + + /** + * Alias function of supportedExtension() for perl-ldap interface + * + * @see supportedExtension() + * @return boolean + */ + public function supported_extension() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'supportedExtension'), $args); + } + + /** + * Determines if the version is supported + * + * @param array $versions Versions to check + * + * @access public + * @return boolean + */ + public function supportedVersion($versions) + { + return $this->checkAttr($versions, 'supportedLDAPVersion'); + } + + /** + * Alias function of supportedVersion() for perl-ldap interface + * + * @see supportedVersion() + * @return boolean + */ + public function supported_version() + { + $args = func_get_args(); + return call_user_func_array(array(&$this, 'supportedVersion'), $args); + } + + /** + * Determines if the control is supported + * + * @param array $oids Control oids to check + * + * @access public + * @return boolean + */ + public function supportedControl($oids) + { + return $this->checkAttr($oids, 'supportedControl'); + } + + /** + * Alias function of supportedControl() for perl-ldap interface + * + * @see supportedControl() + * @return boolean + */ + public function supported_control() + { + $args = func_get_args(); + return call_user_func_array(array(&$this, 'supportedControl' ), $args); + } + + /** + * Determines if the sasl mechanism is supported + * + * @param array $mechlist SASL mechanisms to check + * + * @access public + * @return boolean + */ + public function supportedSASLMechanism($mechlist) + { + return $this->checkAttr($mechlist, 'supportedSASLMechanisms'); + } + + /** + * Alias function of supportedSASLMechanism() for perl-ldap interface + * + * @see supportedSASLMechanism() + * @return boolean + */ + public function supported_sasl_mechanism() + { + $args = func_get_args(); + return call_user_func_array(array(&$this, 'supportedSASLMechanism'), $args); + } + + /** + * Checks for existance of value in attribute + * + * @param array $values values to check + * @param string $attr attribute name + * + * @access protected + * @return boolean + */ + protected function checkAttr($values, $attr) + { + if (!is_array($values)) $values = array($values); + + foreach ($values as $value) { + if (!@in_array($value, $this->get_value($attr, 'all'))) { + return false; + } + } + return true; + } +} + +?> diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Schema.php b/plugins/LdapCommon/extlib/Net/LDAP2/Schema.php new file mode 100644 index 000000000..b590eabc5 --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/Schema.php @@ -0,0 +1,516 @@ + +* @author Benedikt Hallinger +* @copyright 2009 Jan Wagner, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: Schema.php 286718 2009-08-03 07:30:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +* @todo see the comment at the end of the file +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Syntax definitions +* +* Please don't forget to add binary attributes to isBinary() below +* to support proper value fetching from Net_LDAP2_Entry +*/ +define('NET_LDAP2_SYNTAX_BOOLEAN', '1.3.6.1.4.1.1466.115.121.1.7'); +define('NET_LDAP2_SYNTAX_DIRECTORY_STRING', '1.3.6.1.4.1.1466.115.121.1.15'); +define('NET_LDAP2_SYNTAX_DISTINGUISHED_NAME', '1.3.6.1.4.1.1466.115.121.1.12'); +define('NET_LDAP2_SYNTAX_INTEGER', '1.3.6.1.4.1.1466.115.121.1.27'); +define('NET_LDAP2_SYNTAX_JPEG', '1.3.6.1.4.1.1466.115.121.1.28'); +define('NET_LDAP2_SYNTAX_NUMERIC_STRING', '1.3.6.1.4.1.1466.115.121.1.36'); +define('NET_LDAP2_SYNTAX_OID', '1.3.6.1.4.1.1466.115.121.1.38'); +define('NET_LDAP2_SYNTAX_OCTET_STRING', '1.3.6.1.4.1.1466.115.121.1.40'); + +/** +* Load an LDAP Schema and provide information +* +* This class takes a Subschema entry, parses this information +* and makes it available in an array. Most of the code has been +* inspired by perl-ldap( http://perl-ldap.sourceforge.net). +* You will find portions of their implementation in here. +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner +* @author Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Schema extends PEAR +{ + /** + * Map of entry types to ldap attributes of subschema entry + * + * @access public + * @var array + */ + public $types = array( + 'attribute' => 'attributeTypes', + 'ditcontentrule' => 'dITContentRules', + 'ditstructurerule' => 'dITStructureRules', + 'matchingrule' => 'matchingRules', + 'matchingruleuse' => 'matchingRuleUse', + 'nameform' => 'nameForms', + 'objectclass' => 'objectClasses', + 'syntax' => 'ldapSyntaxes' + ); + + /** + * Array of entries belonging to this type + * + * @access protected + * @var array + */ + protected $_attributeTypes = array(); + protected $_matchingRules = array(); + protected $_matchingRuleUse = array(); + protected $_ldapSyntaxes = array(); + protected $_objectClasses = array(); + protected $_dITContentRules = array(); + protected $_dITStructureRules = array(); + protected $_nameForms = array(); + + + /** + * hash of all fetched oids + * + * @access protected + * @var array + */ + protected $_oids = array(); + + /** + * Tells if the schema is initialized + * + * @access protected + * @var boolean + * @see parse(), get() + */ + protected $_initialized = false; + + + /** + * Constructor of the class + * + * @access protected + */ + protected function __construct() + { + $this->PEAR('Net_LDAP2_Error'); // default error class + } + + /** + * Fetch the Schema from an LDAP connection + * + * @param Net_LDAP2 $ldap LDAP connection + * @param string $dn (optional) Subschema entry dn + * + * @access public + * @return Net_LDAP2_Schema|NET_LDAP2_Error + */ + public function fetch($ldap, $dn = null) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!"); + } + + $schema_o = new Net_LDAP2_Schema(); + + if (is_null($dn)) { + // get the subschema entry via root dse + $dse = $ldap->rootDSE(array('subschemaSubentry')); + if (false == Net_LDAP2::isError($dse)) { + $base = $dse->getValue('subschemaSubentry', 'single'); + if (!Net_LDAP2::isError($base)) { + $dn = $base; + } + } + } + + // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that incorrectly + // call this entry subSchemaSubentry instead of subschemaSubentry. + // Note the correct case/spelling as per RFC 2251. + if (is_null($dn)) { + // get the subschema entry via root dse + $dse = $ldap->rootDSE(array('subSchemaSubentry')); + if (false == Net_LDAP2::isError($dse)) { + $base = $dse->getValue('subSchemaSubentry', 'single'); + if (!Net_LDAP2::isError($base)) { + $dn = $base; + } + } + } + + // Final fallback case where there is no subschemaSubentry attribute + // in the root DSE (this is a bug for an LDAP v3 server so report this + // to your LDAP vendor if you get this far). + if (is_null($dn)) { + $dn = 'cn=Subschema'; + } + + // fetch the subschema entry + $result = $ldap->search($dn, '(objectClass=*)', + array('attributes' => array_values($schema_o->types), + 'scope' => 'base')); + if (Net_LDAP2::isError($result)) { + return $result; + } + + $entry = $result->shiftEntry(); + if (!$entry instanceof Net_LDAP2_Entry) { + return PEAR::raiseError('Could not fetch Subschema entry'); + } + + $schema_o->parse($entry); + return $schema_o; + } + + /** + * Return a hash of entries for the given type + * + * Returns a hash of entry for th givene type. Types may be: + * objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules, + * matchingruleuses, nameforms, syntaxes + * + * @param string $type Type to fetch + * + * @access public + * @return array|Net_LDAP2_Error Array or Net_LDAP2_Error + */ + public function &getAll($type) + { + $map = array('objectclasses' => &$this->_objectClasses, + 'attributes' => &$this->_attributeTypes, + 'ditcontentrules' => &$this->_dITContentRules, + 'ditstructurerules' => &$this->_dITStructureRules, + 'matchingrules' => &$this->_matchingRules, + 'matchingruleuses' => &$this->_matchingRuleUse, + 'nameforms' => &$this->_nameForms, + 'syntaxes' => &$this->_ldapSyntaxes ); + + $key = strtolower($type); + $ret = ((key_exists($key, $map)) ? $map[$key] : PEAR::raiseError("Unknown type $type")); + return $ret; + } + + /** + * Return a specific entry + * + * @param string $type Type of name + * @param string $name Name or OID to fetch + * + * @access public + * @return mixed Entry or Net_LDAP2_Error + */ + public function &get($type, $name) + { + if ($this->_initialized) { + $type = strtolower($type); + if (false == key_exists($type, $this->types)) { + return PEAR::raiseError("No such type $type"); + } + + $name = strtolower($name); + $type_var = &$this->{'_' . $this->types[$type]}; + + if (key_exists($name, $type_var)) { + return $type_var[$name]; + } elseif (key_exists($name, $this->_oids) && $this->_oids[$name]['type'] == $type) { + return $this->_oids[$name]; + } else { + return PEAR::raiseError("Could not find $type $name"); + } + } else { + $return = null; + return $return; + } + } + + + /** + * Fetches attributes that MAY be present in the given objectclass + * + * @param string $oc Name or OID of objectclass + * + * @access public + * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error + */ + public function may($oc) + { + return $this->_getAttr($oc, 'may'); + } + + /** + * Fetches attributes that MUST be present in the given objectclass + * + * @param string $oc Name or OID of objectclass + * + * @access public + * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error + */ + public function must($oc) + { + return $this->_getAttr($oc, 'must'); + } + + /** + * Fetches the given attribute from the given objectclass + * + * @param string $oc Name or OID of objectclass + * @param string $attr Name of attribute to fetch + * + * @access protected + * @return array|Net_LDAP2_Error The attribute or Net_LDAP2_Error + */ + protected function _getAttr($oc, $attr) + { + $oc = strtolower($oc); + if (key_exists($oc, $this->_objectClasses) && key_exists($attr, $this->_objectClasses[$oc])) { + return $this->_objectClasses[$oc][$attr]; + } elseif (key_exists($oc, $this->_oids) && + $this->_oids[$oc]['type'] == 'objectclass' && + key_exists($attr, $this->_oids[$oc])) { + return $this->_oids[$oc][$attr]; + } else { + return PEAR::raiseError("Could not find $attr attributes for $oc "); + } + } + + /** + * Returns the name(s) of the immediate superclass(es) + * + * @param string $oc Name or OID of objectclass + * + * @access public + * @return array|Net_LDAP2_Error Array of names or Net_LDAP2_Error + */ + public function superclass($oc) + { + $o = $this->get('objectclass', $oc); + if (Net_LDAP2::isError($o)) { + return $o; + } + return (key_exists('sup', $o) ? $o['sup'] : array()); + } + + /** + * Parses the schema of the given Subschema entry + * + * @param Net_LDAP2_Entry &$entry Subschema entry + * + * @access public + * @return void + */ + public function parse(&$entry) + { + foreach ($this->types as $type => $attr) { + // initialize map type to entry + $type_var = '_' . $attr; + $this->{$type_var} = array(); + + // get values for this type + if ($entry->exists($attr)) { + $values = $entry->getValue($attr); + if (is_array($values)) { + foreach ($values as $value) { + + unset($schema_entry); // this was a real mess without it + + // get the schema entry + $schema_entry = $this->_parse_entry($value); + + // set the type + $schema_entry['type'] = $type; + + // save a ref in $_oids + $this->_oids[$schema_entry['oid']] = &$schema_entry; + + // save refs for all names in type map + $names = $schema_entry['aliases']; + array_push($names, $schema_entry['name']); + foreach ($names as $name) { + $this->{$type_var}[strtolower($name)] = &$schema_entry; + } + } + } + } + } + $this->_initialized = true; + } + + /** + * Parses an attribute value into a schema entry + * + * @param string $value Attribute value + * + * @access protected + * @return array|false Schema entry array or false + */ + protected function &_parse_entry($value) + { + // tokens that have no value associated + $noValue = array('single-value', + 'obsolete', + 'collective', + 'no-user-modification', + 'abstract', + 'structural', + 'auxiliary'); + + // tokens that can have multiple values + $multiValue = array('must', 'may', 'sup'); + + $schema_entry = array('aliases' => array()); // initilization + + $tokens = $this->_tokenize($value); // get an array of tokens + + // remove surrounding brackets + if ($tokens[0] == '(') array_shift($tokens); + if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); // -1 doesnt work on arrays :-( + + $schema_entry['oid'] = array_shift($tokens); // first token is the oid + + // cycle over the tokens until none are left + while (count($tokens) > 0) { + $token = strtolower(array_shift($tokens)); + if (in_array($token, $noValue)) { + $schema_entry[$token] = 1; // single value token + } else { + // this one follows a string or a list if it is multivalued + if (($schema_entry[$token] = array_shift($tokens)) == '(') { + // this creates the list of values and cycles through the tokens + // until the end of the list is reached ')' + $schema_entry[$token] = array(); + while ($tmp = array_shift($tokens)) { + if ($tmp == ')') break; + if ($tmp != '$') array_push($schema_entry[$token], $tmp); + } + } + // create a array if the value should be multivalued but was not + if (in_array($token, $multiValue) && !is_array($schema_entry[$token])) { + $schema_entry[$token] = array($schema_entry[$token]); + } + } + } + // get max length from syntax + if (key_exists('syntax', $schema_entry)) { + if (preg_match('/{(\d+)}/', $schema_entry['syntax'], $matches)) { + $schema_entry['max_length'] = $matches[1]; + } + } + // force a name + if (empty($schema_entry['name'])) { + $schema_entry['name'] = $schema_entry['oid']; + } + // make one name the default and put the other ones into aliases + if (is_array($schema_entry['name'])) { + $aliases = $schema_entry['name']; + $schema_entry['name'] = array_shift($aliases); + $schema_entry['aliases'] = $aliases; + } + return $schema_entry; + } + + /** + * Tokenizes the given value into an array of tokens + * + * @param string $value String to parse + * + * @access protected + * @return array Array of tokens + */ + protected function _tokenize($value) + { + $tokens = array(); // array of tokens + $matches = array(); // matches[0] full pattern match, [1,2,3] subpatterns + + // this one is taken from perl-ldap, modified for php + $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x"; + + /** + * This one matches one big pattern wherin only one of the three subpatterns matched + * We are interested in the subpatterns that matched. If it matched its value will be + * non-empty and so it is a token. Tokens may be round brackets, a string, or a string + * enclosed by ' + */ + preg_match_all($pattern, $value, $matches); + + for ($i = 0; $i < count($matches[0]); $i++) { // number of tokens (full pattern match) + for ($j = 1; $j < 4; $j++) { // each subpattern + if (null != trim($matches[$j][$i])) { // pattern match in this subpattern + $tokens[$i] = trim($matches[$j][$i]); // this is the token + } + } + } + return $tokens; + } + + /** + * Returns wether a attribute syntax is binary or not + * + * This method gets used by Net_LDAP2_Entry to decide which + * PHP function needs to be used to fetch the value in the + * proper format (e.g. binary or string) + * + * @param string $attribute The name of the attribute (eg.: 'sn') + * + * @access public + * @return boolean + */ + public function isBinary($attribute) + { + $return = false; // default to false + + // This list contains all syntax that should be treaten as + // containing binary values + // The Syntax Definitons go into constants at the top of this page + $syntax_binary = array( + NET_LDAP2_SYNTAX_OCTET_STRING, + NET_LDAP2_SYNTAX_JPEG + ); + + // Check Syntax + $attr_s = $this->get('attribute', $attribute); + if (Net_LDAP2::isError($attr_s)) { + // Attribute not found in schema + $return = false; // consider attr not binary + } elseif (isset($attr_s['syntax']) && in_array($attr_s['syntax'], $syntax_binary)) { + // Syntax is defined as binary in schema + $return = true; + } else { + // Syntax not defined as binary, or not found + // if attribute is a subtype, check superior attribute syntaxes + if (isset($attr_s['sup'])) { + foreach ($attr_s['sup'] as $superattr) { + $return = $this->isBinary($superattr); + if ($return) { + break; // stop checking parents since we are binary + } + } + } + } + + return $return; + } + + // [TODO] add method that allows us to see to which objectclasses a certain attribute belongs to + // it should return the result structured, e.g. sorted in "may" and "must". Optionally it should + // be able to return it just "flat", e.g. array_merge()d. + // We could use get_all() to achieve this easily, i think +} +?> diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/SchemaCache.interface.php b/plugins/LdapCommon/extlib/Net/LDAP2/SchemaCache.interface.php new file mode 100644 index 000000000..e0c3094c4 --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/SchemaCache.interface.php @@ -0,0 +1,59 @@ + +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: SchemaCache.interface.php 286718 2009-08-03 07:30:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Interface describing a custom schema cache object +* +* To implement a custom schema cache, one must implement this interface and +* pass the instanciated object to Net_LDAP2s registerSchemaCache() method. +*/ +interface Net_LDAP2_SchemaCache +{ + /** + * Return the schema object from the cache + * + * Net_LDAP2 will consider anything returned invalid, except + * a valid Net_LDAP2_Schema object. + * In case you return a Net_LDAP2_Error, this error will be routed + * to the return of the $ldap->schema() call. + * If you return something else, Net_LDAP2 will + * fetch a fresh Schema object from the LDAP server. + * + * You may want to implement a cache aging mechanism here too. + * + * @return Net_LDAP2_Schema|Net_LDAP2_Error|false + */ + public function loadSchema(); + + /** + * Store a schema object in the cache + * + * This method will be called, if Net_LDAP2 has fetched a fresh + * schema object from LDAP and wants to init or refresh the cache. + * + * In case of errors you may return a Net_LDAP2_Error which will + * be routet to the client. + * Note that doing this prevents, that the schema object fetched from LDAP + * will be given back to the client, so only return errors if storing + * of the cache is something crucial (e.g. for doing something else with it). + * Normaly you dont want to give back errors in which case Net_LDAP2 needs to + * fetch the schema once per script run and instead use the error + * returned from loadSchema(). + * + * @return true|Net_LDAP2_Error + */ + public function storeSchema($schema); +} diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Search.php b/plugins/LdapCommon/extlib/Net/LDAP2/Search.php new file mode 100644 index 000000000..de4fde122 --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/Search.php @@ -0,0 +1,614 @@ + +* @author Benedikt Hallinger +* @copyright 2009 Tarjej Huse, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: Search.php 286718 2009-08-03 07:30:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Result set of an LDAP search +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse +* @author Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Search extends PEAR implements Iterator +{ + /** + * Search result identifier + * + * @access protected + * @var resource + */ + protected $_search; + + /** + * LDAP resource link + * + * @access protected + * @var resource + */ + protected $_link; + + /** + * Net_LDAP2 object + * + * A reference of the Net_LDAP2 object for passing to Net_LDAP2_Entry + * + * @access protected + * @var object Net_LDAP2 + */ + protected $_ldap; + + /** + * Result entry identifier + * + * @access protected + * @var resource + */ + protected $_entry = null; + + /** + * The errorcode the search got + * + * Some errorcodes might be of interest, but might not be best handled as errors. + * examples: 4 - LDAP_SIZELIMIT_EXCEEDED - indicates a huge search. + * Incomplete results are returned. If you just want to check if there's anything in the search. + * than this is a point to handle. + * 32 - no such object - search here returns a count of 0. + * + * @access protected + * @var int + */ + protected $_errorCode = 0; // if not set - sucess! + + /** + * Cache for all entries already fetched from iterator interface + * + * @access protected + * @var array + */ + protected $_iteratorCache = array(); + + /** + * What attributes we searched for + * + * The $attributes array contains the names of the searched attributes and gets + * passed from $Net_LDAP2->search() so the Net_LDAP2_Search object can tell + * what attributes was searched for ({@link searchedAttrs()) + * + * This variable gets set from the constructor and returned + * from {@link searchedAttrs()} + * + * @access protected + * @var array + */ + protected $_searchedAttrs = array(); + + /** + * Cache variable for storing entries fetched internally + * + * This currently is only used by {@link pop_entry()} + * + * @access protected + * @var array + */ + protected $_entry_cache = false; + + /** + * Constructor + * + * @param resource &$search Search result identifier + * @param Net_LDAP2|resource &$ldap Net_LDAP2 object or just a LDAP-Link resource + * @param array $attributes (optional) Array with searched attribute names. (see {@link $_searchedAttrs}) + * + * @access public + */ + public function __construct(&$search, &$ldap, $attributes = array()) + { + $this->PEAR('Net_LDAP2_Error'); + + $this->setSearch($search); + + if ($ldap instanceof Net_LDAP2) { + $this->_ldap =& $ldap; + $this->setLink($this->_ldap->getLink()); + } else { + $this->setLink($ldap); + } + + $this->_errorCode = @ldap_errno($this->_link); + + if (is_array($attributes) && !empty($attributes)) { + $this->_searchedAttrs = $attributes; + } + } + + /** + * Returns an array of entry objects + * + * @return array Array of entry objects. + */ + public function entries() + { + $entries = array(); + + while ($entry = $this->shiftEntry()) { + $entries[] = $entry; + } + + return $entries; + } + + /** + * Get the next entry in the searchresult. + * + * This will return a valid Net_LDAP2_Entry object or false, so + * you can use this method to easily iterate over the entries inside + * a while loop. + * + * @return Net_LDAP2_Entry|false Reference to Net_LDAP2_Entry object or false + */ + public function &shiftEntry() + { + if ($this->count() == 0 ) { + $false = false; + return $false; + } + + if (is_null($this->_entry)) { + $this->_entry = @ldap_first_entry($this->_link, $this->_search); + $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry); + if ($entry instanceof Net_LDAP2_Error) $entry = false; + } else { + if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) { + $false = false; + return $false; + } + $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry); + if ($entry instanceof Net_LDAP2_Error) $entry = false; + } + return $entry; + } + + /** + * Alias function of shiftEntry() for perl-ldap interface + * + * @see shiftEntry() + * @return Net_LDAP2_Entry|false + */ + public function shift_entry() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'shiftEntry' ), $args); + } + + /** + * Retrieve the next entry in the searchresult, but starting from last entry + * + * This is the opposite to {@link shiftEntry()} and is also very useful + * to be used inside a while loop. + * + * @return Net_LDAP2_Entry|false + */ + public function popEntry() + { + if (false === $this->_entry_cache) { + // fetch entries into cache if not done so far + $this->_entry_cache = $this->entries(); + } + + $return = array_pop($this->_entry_cache); + return (null === $return)? false : $return; + } + + /** + * Alias function of popEntry() for perl-ldap interface + * + * @see popEntry() + * @return Net_LDAP2_Entry|false + */ + public function pop_entry() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'popEntry' ), $args); + } + + /** + * Return entries sorted as array + * + * This returns a array with sorted entries and the values. + * Sorting is done with PHPs {@link array_multisort()}. + * This method relies on {@link as_struct()} to fetch the raw data of the entries. + * + * Please note that attribute names are case sensitive! + * + * Usage example: + * + * // to sort entries first by location, then by surename, but descending: + * $entries = $search->sorted_as_struct(array('locality','sn'), SORT_DESC); + * + * + * @param array $attrs Array of attribute names to sort; order from left to right. + * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC + * + * @return array|Net_LDAP2_Error Array with sorted entries or error + * @todo what about server side sorting as specified in http://www.ietf.org/rfc/rfc2891.txt? + */ + public function sorted_as_struct($attrs = array('cn'), $order = SORT_ASC) + { + /* + * Old Code, suitable and fast for single valued sorting + * This code should be used if we know that single valued sorting is desired, + * but we need some method to get that knowledge... + */ + /* + $attrs = array_reverse($attrs); + foreach ($attrs as $attribute) { + if (!ldap_sort($this->_link, $this->_search, $attribute)){ + $this->raiseError("Sorting failed for Attribute " . $attribute); + } + } + + $results = ldap_get_entries($this->_link, $this->_search); + + unset($results['count']); //for tidier output + if ($order) { + return array_reverse($results); + } else { + return $results; + }*/ + + /* + * New code: complete "client side" sorting + */ + // first some parameterchecks + if (!is_array($attrs)) { + return PEAR::raiseError("Sorting failed: Parameterlist must be an array!"); + } + if ($order != SORT_ASC && $order != SORT_DESC) { + return PEAR::raiseError("Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)"); + } + + // fetch the entries data + $entries = $this->as_struct(); + + // now sort each entries attribute values + // this is neccessary because later we can only sort by one value, + // so we need the highest or lowest attribute now, depending on the + // selected ordering for that specific attribute + foreach ($entries as $dn => $entry) { + foreach ($entry as $attr_name => $attr_values) { + sort($entries[$dn][$attr_name]); + if ($order == SORT_DESC) { + array_reverse($entries[$dn][$attr_name]); + } + } + } + + // reformat entrys array for later use with array_multisort() + $to_sort = array(); // <- will be a numeric array similar to ldap_get_entries + foreach ($entries as $dn => $entry_attr) { + $row = array(); + $row['dn'] = $dn; + foreach ($entry_attr as $attr_name => $attr_values) { + $row[$attr_name] = $attr_values; + } + $to_sort[] = $row; + } + + // Build columns for array_multisort() + // each requested attribute is one row + $columns = array(); + foreach ($attrs as $attr_name) { + foreach ($to_sort as $key => $row) { + $columns[$attr_name][$key] =& $to_sort[$key][$attr_name][0]; + } + } + + // sort the colums with array_multisort, if there is something + // to sort and if we have requested sort columns + if (!empty($to_sort) && !empty($columns)) { + $sort_params = ''; + foreach ($attrs as $attr_name) { + $sort_params .= '$columns[\''.$attr_name.'\'], '.$order.', '; + } + eval("array_multisort($sort_params \$to_sort);"); // perform sorting + } + + return $to_sort; + } + + /** + * Return entries sorted as objects + * + * This returns a array with sorted Net_LDAP2_Entry objects. + * The sorting is actually done with {@link sorted_as_struct()}. + * + * Please note that attribute names are case sensitive! + * Also note, that it is (depending on server capabilitys) possible to let + * the server sort your results. This happens through search controls + * and is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt} + * + * Usage example: + * + * // to sort entries first by location, then by surename, but descending: + * $entries = $search->sorted(array('locality','sn'), SORT_DESC); + * + * + * @param array $attrs Array of sort attributes to sort; order from left to right. + * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC + * + * @return array|Net_LDAP2_Error Array with sorted Net_LDAP2_Entries or error + * @todo Entry object construction could be faster. Maybe we could use one of the factorys instead of fetching the entry again + */ + public function sorted($attrs = array('cn'), $order = SORT_ASC) + { + $return = array(); + $sorted = $this->sorted_as_struct($attrs, $order); + if (PEAR::isError($sorted)) { + return $sorted; + } + foreach ($sorted as $key => $row) { + $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttrs()); + if (!PEAR::isError($entry)) { + array_push($return, $entry); + } else { + return $entry; + } + } + return $return; + } + + /** + * Return entries as array + * + * This method returns the entries and the selected attributes values as + * array. + * The first array level contains all found entries where the keys are the + * DNs of the entries. The second level arrays contian the entries attributes + * such that the keys is the lowercased name of the attribute and the values + * are stored in another indexed array. Note that the attribute values are stored + * in an array even if there is no or just one value. + * + * The array has the following structure: + * + * $return = array( + * 'cn=foo,dc=example,dc=com' => array( + * 'sn' => array('foo'), + * 'multival' => array('val1', 'val2', 'valN') + * ) + * 'cn=bar,dc=example,dc=com' => array( + * 'sn' => array('bar'), + * 'multival' => array('val1', 'valN') + * ) + * ) + * + * + * @return array associative result array as described above + */ + public function as_struct() + { + $return = array(); + $entries = $this->entries(); + foreach ($entries as $entry) { + $attrs = array(); + $entry_attributes = $entry->attributes(); + foreach ($entry_attributes as $attr_name) { + $attr_values = $entry->getValue($attr_name, 'all'); + if (!is_array($attr_values)) { + $attr_values = array($attr_values); + } + $attrs[$attr_name] = $attr_values; + } + $return[$entry->dn()] = $attrs; + } + return $return; + } + + /** + * Set the search objects resource link + * + * @param resource &$search Search result identifier + * + * @access public + * @return void + */ + public function setSearch(&$search) + { + $this->_search = $search; + } + + /** + * Set the ldap ressource link + * + * @param resource &$link Link identifier + * + * @access public + * @return void + */ + public function setLink(&$link) + { + $this->_link = $link; + } + + /** + * Returns the number of entries in the searchresult + * + * @return int Number of entries in search. + */ + public function count() + { + // this catches the situation where OL returned errno 32 = no such object! + if (!$this->_search) { + return 0; + } + return @ldap_count_entries($this->_link, $this->_search); + } + + /** + * Get the errorcode the object got in its search. + * + * @return int The ldap error number. + */ + public function getErrorCode() + { + return $this->_errorCode; + } + + /** + * Destructor + * + * @access protected + */ + public function _Net_LDAP2_Search() + { + @ldap_free_result($this->_search); + } + + /** + * Closes search result + * + * @return void + */ + public function done() + { + $this->_Net_LDAP2_Search(); + } + + /** + * Return the attribute names this search selected + * + * @return array + * @see $_searchedAttrs + * @access protected + */ + protected function searchedAttrs() + { + return $this->_searchedAttrs; + } + + /** + * Tells if this search exceeds a sizelimit + * + * @return boolean + */ + public function sizeLimitExceeded() + { + return ($this->getErrorCode() == 4); + } + + + /* + * SPL Iterator interface methods. + * This interface allows to use Net_LDAP2_Search + * objects directly inside a foreach loop! + */ + /** + * SPL Iterator interface: Return the current element. + * + * The SPL Iterator interface allows you to fetch entries inside + * a foreach() loop: foreach ($search as $dn => $entry) { ... + * + * Of course, you may call {@link current()}, {@link key()}, {@link next()}, + * {@link rewind()} and {@link valid()} yourself. + * + * If the search throwed an error, it returns false. + * False is also returned, if the end is reached + * In case no call to next() was made, we will issue one, + * thus returning the first entry. + * + * @return Net_LDAP2_Entry|false + */ + public function current() + { + if (count($this->_iteratorCache) == 0) { + $this->next(); + reset($this->_iteratorCache); + } + $entry = current($this->_iteratorCache); + return ($entry instanceof Net_LDAP2_Entry)? $entry : false; + } + + /** + * SPL Iterator interface: Return the identifying key (DN) of the current entry. + * + * @see current() + * @return string|false DN of the current entry; false in case no entry is returned by current() + */ + public function key() + { + $entry = $this->current(); + return ($entry instanceof Net_LDAP2_Entry)? $entry->dn() :false; + } + + /** + * SPL Iterator interface: Move forward to next entry. + * + * After a call to {@link next()}, {@link current()} will return + * the next entry in the result set. + * + * @see current() + * @return void + */ + public function next() + { + // fetch next entry. + // if we have no entrys anymore, we add false (which is + // returned by shiftEntry()) so current() will complain. + if (count($this->_iteratorCache) - 1 <= $this->count()) { + $this->_iteratorCache[] = $this->shiftEntry(); + } + + // move on array pointer to current element. + // even if we have added all entries, this will + // ensure proper operation in case we rewind() + next($this->_iteratorCache); + } + + /** + * SPL Iterator interface: Check if there is a current element after calls to {@link rewind()} or {@link next()}. + * + * Used to check if we've iterated to the end of the collection. + * + * @see current() + * @return boolean FALSE if there's nothing more to iterate over + */ + public function valid() + { + return ($this->current() instanceof Net_LDAP2_Entry); + } + + /** + * SPL Iterator interface: Rewind the Iterator to the first element. + * + * After rewinding, {@link current()} will return the first entry in the result set. + * + * @see current() + * @return void + */ + public function rewind() + { + reset($this->_iteratorCache); + } +} + +?> diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/SimpleFileSchemaCache.php b/plugins/LdapCommon/extlib/Net/LDAP2/SimpleFileSchemaCache.php new file mode 100644 index 000000000..8019654ac --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/SimpleFileSchemaCache.php @@ -0,0 +1,97 @@ + +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: SimpleFileSchemaCache.php 286718 2009-08-03 07:30:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* A simple file based schema cacher with cache aging. +* +* Once the cache is too old, the loadSchema() method will return false, so +* Net_LDAP2 will fetch a fresh object from the LDAP server that will +* overwrite the current (outdated) old cache. +*/ +class Net_LDAP2_SimpleFileSchemaCache implements Net_LDAP2_SchemaCache +{ + /** + * Internal config of this cache + * + * @see Net_LDAP2_SimpleFileSchemaCache() + * @var array + */ + protected $config = array( + 'path' => '/tmp/Net_LDAP_Schema.cache', + 'max_age' => 1200 + ); + + /** + * Initialize the simple cache + * + * Config is as following: + * path Complete path to the cache file. + * max_age Maximum age of cache in seconds, 0 means "endlessly". + * + * @param array $cfg Config array + */ + public function Net_LDAP2_SimpleFileSchemaCache($cfg) + { + foreach ($cfg as $key => $value) { + if (array_key_exists($key, $this->config)) { + if (gettype($this->config[$key]) != gettype($value)) { + $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key does not match type ".gettype($this->config[$key])."!"); + } + $this->config[$key] = $value; + } else { + $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key is not defined!"); + } + } + } + + /** + * Return the schema object from the cache + * + * If file is existent and cache has not expired yet, + * then the cache is deserialized and returned. + * + * @return Net_LDAP2_Schema|Net_LDAP2_Error|false + */ + public function loadSchema() + { + $return = false; // Net_LDAP2 will load schema from LDAP + if (file_exists($this->config['path'])) { + $cache_maxage = filemtime($this->config['path']) + $this->config['max_age']; + if (time() <= $cache_maxage || $this->config['max_age'] == 0) { + $return = unserialize(file_get_contents($this->config['path'])); + } + } + return $return; + } + + /** + * Store a schema object in the cache + * + * This method will be called, if Net_LDAP2 has fetched a fresh + * schema object from LDAP and wants to init or refresh the cache. + * + * To invalidate the cache and cause Net_LDAP2 to refresh the cache, + * you can call this method with null or false as value. + * The next call to $ldap->schema() will then refresh the caches object. + * + * @param mixed $schema The object that should be cached + * @return true|Net_LDAP2_Error|false + */ + public function storeSchema($schema) { + file_put_contents($this->config['path'], serialize($schema)); + return true; + } +} diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Util.php b/plugins/LdapCommon/extlib/Net/LDAP2/Util.php new file mode 100644 index 000000000..48b03f9f9 --- /dev/null +++ b/plugins/LdapCommon/extlib/Net/LDAP2/Util.php @@ -0,0 +1,572 @@ + +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id: Util.php 286718 2009-08-03 07:30:49Z beni $ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Utility Class for Net_LDAP2 +* +* This class servers some functionality to the other classes of Net_LDAP2 but most of +* the methods can be used separately as well. +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Util extends PEAR +{ + /** + * Constructor + * + * @access public + */ + public function __construct() + { + // We do nothing here, since all methods can be called statically. + // In Net_LDAP <= 0.7, we needed a instance of Util, because + // it was possible to do utf8 encoding and decoding, but this + // has been moved to the LDAP class. The constructor remains only + // here to document the downward compatibility of creating an instance. + } + + /** + * Explodes the given DN into its elements + * + * {@link http://www.ietf.org/rfc/rfc2253.txt RFC 2253} says, a Distinguished Name is a sequence + * of Relative Distinguished Names (RDNs), which themselves + * are sets of Attributes. For each RDN a array is constructed where the RDN part is stored. + * + * For example, the DN 'OU=Sales+CN=J. Smith,DC=example,DC=net' is exploded to: + * array( [0] => array([0] => 'OU=Sales', [1] => 'CN=J. Smith'), [2] => 'DC=example', [3] => 'DC=net' ) + * + * [NOT IMPLEMENTED] DNs might also contain values, which are the bytes of the BER encoding of + * the X.500 AttributeValue rather than some LDAP string syntax. These values are hex-encoded + * and prefixed with a #. To distinguish such BER values, ldap_explode_dn uses references to + * the actual values, e.g. '1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com' is exploded to: + * [ { '1.3.6.1.4.1.1466.0' => "\004\002Hi" }, { 'DC' => 'example' }, { 'DC' => 'com' } ]; + * See {@link http://www.vijaymukhi.com/vmis/berldap.htm} for more information on BER. + * + * It also performs the following operations on the given DN: + * - Unescape "\" followed by ",", "+", """, "\", "<", ">", ";", "#", "=", " ", or a hexpair + * and strings beginning with "#". + * - Removes the leading 'OID.' characters if the type is an OID instead of a name. + * - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order. + * + * OPTIONS is a list of name/value pairs, valid options are: + * casefold Controls case folding of attribute types names. + * Attribute values are not affected by this option. + * The default is to uppercase. Valid values are: + * lower Lowercase attribute types names. + * upper Uppercase attribute type names. This is the default. + * none Do not change attribute type names. + * reverse If TRUE, the RDN sequence is reversed. + * onlyvalues If TRUE, then only attributes values are returned ('foo' instead of 'cn=foo') + * + + * @param string $dn The DN that should be exploded + * @param array $options Options to use + * + * @static + * @return array Parts of the exploded DN + * @todo implement BER + */ + public static function ldap_explode_dn($dn, $options = array('casefold' => 'upper')) + { + if (!isset($options['onlyvalues'])) $options['onlyvalues'] = false; + if (!isset($options['reverse'])) $options['reverse'] = false; + if (!isset($options['casefold'])) $options['casefold'] = 'upper'; + + // Escaping of DN and stripping of "OID." + $dn = self::canonical_dn($dn, array('casefold' => $options['casefold'])); + + // splitting the DN + $dn_array = preg_split('/(?<=[^\\\\]),/', $dn); + + // clear wrong splitting (possibly we have split too much) + // /!\ Not clear, if this is neccessary here + //$dn_array = self::correct_dn_splitting($dn_array, ','); + + // construct subarrays for multivalued RDNs and unescape DN value + // also convert to output format and apply casefolding + foreach ($dn_array as $key => $value) { + $value_u = self::unescape_dn_value($value); + $rdns = self::split_rdn_multival($value_u[0]); + if (count($rdns) > 1) { + // MV RDN! + foreach ($rdns as $subrdn_k => $subrdn_v) { + // Casefolding + if ($options['casefold'] == 'upper') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $subrdn_v); + if ($options['casefold'] == 'lower') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $subrdn_v); + + if ($options['onlyvalues']) { + preg_match('/(.+?)(?", ";", "#", "=" with a special meaning in RFC 2252 + * are preceeded by ba backslash. Control characters with an ASCII code < 32 are represented as \hexpair. + * Finally all leading and trailing spaces are converted to sequences of \20. + * + * @param array $values An array containing the DN values that should be escaped + * + * @static + * @return array The array $values, but escaped + */ + public static function escape_dn_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $val) { + // Escaping of filter meta characters + $val = str_replace('\\', '\\\\', $val); + $val = str_replace(',', '\,', $val); + $val = str_replace('+', '\+', $val); + $val = str_replace('"', '\"', $val); + $val = str_replace('<', '\<', $val); + $val = str_replace('>', '\>', $val); + $val = str_replace(';', '\;', $val); + $val = str_replace('#', '\#', $val); + $val = str_replace('=', '\=', $val); + + // ASCII < 32 escaping + $val = self::asc2hex32($val); + + // Convert all leading and trailing spaces to sequences of \20. + if (preg_match('/^(\s*)(.+?)(\s*)$/', $val, $matches)) { + $val = $matches[2]; + for ($i = 0; $i < strlen($matches[1]); $i++) { + $val = '\20'.$val; + } + for ($i = 0; $i < strlen($matches[3]); $i++) { + $val = $val.'\20'; + } + } + + if (null === $val) $val = '\0'; // apply escaped "null" if string is empty + + $values[$key] = $val; + } + + return $values; + } + + /** + * Undoes the conversion done by escape_dn_value(). + * + * Any escape sequence starting with a baskslash - hexpair or special character - + * will be transformed back to the corresponding character. + * + * @param array $values Array of DN Values + * + * @return array Same as $values, but unescaped + * @static + */ + public static function unescape_dn_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $val) { + // strip slashes from special chars + $val = str_replace('\\\\', '\\', $val); + $val = str_replace('\,', ',', $val); + $val = str_replace('\+', '+', $val); + $val = str_replace('\"', '"', $val); + $val = str_replace('\<', '<', $val); + $val = str_replace('\>', '>', $val); + $val = str_replace('\;', ';', $val); + $val = str_replace('\#', '#', $val); + $val = str_replace('\=', '=', $val); + + // Translate hex code into ascii + $values[$key] = self::hex2asc($val); + } + + return $values; + } + + /** + * Returns the given DN in a canonical form + * + * Returns false if DN is not a valid Distinguished Name. + * DN can either be a string or an array + * as returned by ldap_explode_dn, which is useful when constructing a DN. + * The DN array may have be indexed (each array value is a OCL=VALUE pair) + * or associative (array key is OCL and value is VALUE). + * + * It performs the following operations on the given DN: + * - Removes the leading 'OID.' characters if the type is an OID instead of a name. + * - Escapes all RFC 2253 special characters (",", "+", """, "\", "<", ">", ";", "#", "="), slashes ("/"), and any other character where the ASCII code is < 32 as \hexpair. + * - Converts all leading and trailing spaces in values to be \20. + * - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order. + * + * OPTIONS is a list of name/value pairs, valid options are: + * casefold Controls case folding of attribute type names. + * Attribute values are not affected by this option. The default is to uppercase. + * Valid values are: + * lower Lowercase attribute type names. + * upper Uppercase attribute type names. This is the default. + * none Do not change attribute type names. + * [NOT IMPLEMENTED] mbcescape If TRUE, characters that are encoded as a multi-octet UTF-8 sequence will be escaped as \(hexpair){2,*}. + * reverse If TRUE, the RDN sequence is reversed. + * separator Separator to use between RDNs. Defaults to comma (','). + * + * Note: The empty string "" is a valid DN, so be sure not to do a "$can_dn == false" test, + * because an empty string evaluates to false. Use the "===" operator instead. + * + * @param array|string $dn The DN + * @param array $options Options to use + * + * @static + * @return false|string The canonical DN or FALSE + * @todo implement option mbcescape + */ + public static function canonical_dn($dn, $options = array('casefold' => 'upper', 'separator' => ',')) + { + if ($dn === '') return $dn; // empty DN is valid! + + // options check + if (!isset($options['reverse'])) { + $options['reverse'] = false; + } else { + $options['reverse'] = true; + } + if (!isset($options['casefold'])) $options['casefold'] = 'upper'; + if (!isset($options['separator'])) $options['separator'] = ','; + + + if (!is_array($dn)) { + // It is not clear to me if the perl implementation splits by the user defined + // separator or if it just uses this separator to construct the new DN + $dn = preg_split('/(?<=[^\\\\])'.$options['separator'].'/', $dn); + + // clear wrong splitting (possibly we have split too much) + $dn = self::correct_dn_splitting($dn, $options['separator']); + } else { + // Is array, check, if the array is indexed or associative + $assoc = false; + foreach ($dn as $dn_key => $dn_part) { + if (!is_int($dn_key)) { + $assoc = true; + } + } + // convert to indexed, if associative array detected + if ($assoc) { + $newdn = array(); + foreach ($dn as $dn_key => $dn_part) { + if (is_array($dn_part)) { + ksort($dn_part, SORT_STRING); // we assume here, that the rdn parts are also associative + $newdn[] = $dn_part; // copy array as-is, so we can resolve it later + } else { + $newdn[] = $dn_key.'='.$dn_part; + } + } + $dn =& $newdn; + } + } + + // Escaping and casefolding + foreach ($dn as $pos => $dnval) { + if (is_array($dnval)) { + // subarray detected, this means very surely, that we had + // a multivalued dn part, which must be resolved + $dnval_new = ''; + foreach ($dnval as $subkey => $subval) { + // build RDN part + if (!is_int($subkey)) { + $subval = $subkey.'='.$subval; + } + $subval_processed = self::canonical_dn($subval); + if (false === $subval_processed) return false; + $dnval_new .= $subval_processed.'+'; + } + $dn[$pos] = substr($dnval_new, 0, -1); // store RDN part, strip last plus + } else { + // try to split multivalued RDNS into array + $rdns = self::split_rdn_multival($dnval); + if (count($rdns) > 1) { + // Multivalued RDN was detected! + // The RDN value is expected to be correctly split by split_rdn_multival(). + // It's time to sort the RDN and build the DN! + $rdn_string = ''; + sort($rdns, SORT_STRING); // Sort RDN keys alphabetically + foreach ($rdns as $rdn) { + $subval_processed = self::canonical_dn($rdn); + if (false === $subval_processed) return false; + $rdn_string .= $subval_processed.'+'; + } + + $dn[$pos] = substr($rdn_string, 0, -1); // store RDN part, strip last plus + + } else { + // no multivalued RDN! + // split at first unescaped "=" + $dn_comp = preg_split('/(?<=[^\\\\])=/', $rdns[0], 2); + $ocl = ltrim($dn_comp[0]); // trim left whitespaces 'cause of "cn=foo, l=bar" syntax (whitespace after comma) + $val = $dn_comp[1]; + + // strip 'OID.', otherwise apply casefolding and escaping + if (substr(strtolower($ocl), 0, 4) == 'oid.') { + $ocl = substr($ocl, 4); + } else { + if ($options['casefold'] == 'upper') $ocl = strtoupper($ocl); + if ($options['casefold'] == 'lower') $ocl = strtolower($ocl); + $ocl = self::escape_dn_value(array($ocl)); + $ocl = $ocl[0]; + } + + // escaping of dn-value + $val = self::escape_dn_value(array($val)); + $val = str_replace('/', '\/', $val[0]); + + $dn[$pos] = $ocl.'='.$val; + } + } + } + + if ($options['reverse']) $dn = array_reverse($dn); + return implode($options['separator'], $dn); + } + + /** + * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters. + * + * Any control characters with an ACII code < 32 as well as the characters with special meaning in + * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a + * backslash followed by two hex digits representing the hexadecimal value of the character. + * + * @param array $values Array of values to escape + * + * @static + * @return array Array $values, but escaped + */ + public static function escape_filter_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $val) { + // Escaping of filter meta characters + $val = str_replace('\\', '\5c', $val); + $val = str_replace('*', '\2a', $val); + $val = str_replace('(', '\28', $val); + $val = str_replace(')', '\29', $val); + + // ASCII < 32 escaping + $val = self::asc2hex32($val); + + if (null === $val) $val = '\0'; // apply escaped "null" if string is empty + + $values[$key] = $val; + } + + return $values; + } + + /** + * Undoes the conversion done by {@link escape_filter_value()}. + * + * Converts any sequences of a backslash followed by two hex digits into the corresponding character. + * + * @param array $values Array of values to escape + * + * @static + * @return array Array $values, but unescaped + */ + public static function unescape_filter_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $value) { + // Translate hex code into ascii + $values[$key] = self::hex2asc($value); + } + + return $values; + } + + /** + * Converts all ASCII chars < 32 to "\HEX" + * + * @param string $string String to convert + * + * @static + * @return string + */ + public static function asc2hex32($string) + { + for ($i = 0; $i < strlen($string); $i++) { + $char = substr($string, $i, 1); + if (ord($char) < 32) { + $hex = dechex(ord($char)); + if (strlen($hex) == 1) $hex = '0'.$hex; + $string = str_replace($char, '\\'.$hex, $string); + } + } + return $string; + } + + /** + * Converts all Hex expressions ("\HEX") to their original ASCII characters + * + * @param string $string String to convert + * + * @static + * @author beni@php.net, heavily based on work from DavidSmith@byu.net + * @return string + */ + public static function hex2asc($string) + { + $string = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $string); + return $string; + } + + /** + * Split an multivalued RDN value into an Array + * + * A RDN can contain multiple values, spearated by a plus sign. + * This function returns each separate ocl=value pair of the RDN part. + * + * If no multivalued RDN is detected, an array containing only + * the original rdn part is returned. + * + * For example, the multivalued RDN 'OU=Sales+CN=J. Smith' is exploded to: + * array([0] => 'OU=Sales', [1] => 'CN=J. Smith') + * + * The method trys to be smart if it encounters unescaped "+" characters, but may fail, + * so ensure escaped "+"es in attr names and attr values. + * + * [BUG] If you have a multivalued RDN with unescaped plus characters + * and there is a unescaped plus sign at the end of an value followed by an + * attribute name containing an unescaped plus, then you will get wrong splitting: + * $rdn = 'OU=Sales+C+N=J. Smith'; + * returns: + * array('OU=Sales+C', 'N=J. Smith'); + * The "C+" is treaten as value of the first pair instead as attr name of the second pair. + * To prevent this, escape correctly. + * + * @param string $rdn Part of an (multivalued) escaped RDN (eg. ou=foo OR ou=foo+cn=bar) + * + * @static + * @return array Array with the components of the multivalued RDN or Error + */ + public static function split_rdn_multival($rdn) + { + $rdns = preg_split('/(? $dn_value) { + $dn_value = $dn[$key]; // refresh value (foreach caches!) + // if the dn_value is not in attr=value format, then we had an + // unescaped separator character inside the attr name or the value. + // We assume, that it was the attribute value. + // [TODO] To solve this, we might ask the schema. Keep in mind, that UTIL class + // must remain independent from the other classes or connections. + if (!preg_match('/.+(? -- cgit v1.2.3-54-g00ecf From abe4be5438180f5e4f7618f60112023e5ccd788e Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 23 Mar 2010 22:42:30 -0400 Subject: Use $param instead of hardcoded 'attach' name. --- lib/mediafile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mediafile.php b/lib/mediafile.php index 10d90d008..1c96c42d7 100644 --- a/lib/mediafile.php +++ b/lib/mediafile.php @@ -171,7 +171,7 @@ class MediaFile return; } - if (!MediaFile::respectsQuota($user, $_FILES['attach']['size'])) { + if (!MediaFile::respectsQuota($user, $_FILES[$param]['size'])) { // Should never actually get here -- cgit v1.2.3-54-g00ecf From a3da5b24c9fc602e147304333ac059d0aae13de7 Mon Sep 17 00:00:00 2001 From: Julien C Date: Sun, 7 Feb 2010 18:29:42 +0100 Subject: Misc small fixes, plus a new hook in tag.php --- EVENTS.txt | 2 +- actions/tag.php | 13 +++++++++---- plugins/RSSCloud/RSSCloudPlugin.php | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index 2da6f3da6..cf9c6123f 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -141,7 +141,7 @@ StartLogout: Before logging out EndLogout: After logging out - $action: the logout action -ArgsInitialized: After the argument array has been initialized +ArgsInitialize: After the argument array has been initialized - $args: associative array of arguments, can be modified StartAddressData: Allows the site owner to provide additional information about themselves for contact (e.g., tagline, email, location) diff --git a/actions/tag.php b/actions/tag.php index ee9617b66..72668a0c9 100644 --- a/actions/tag.php +++ b/actions/tag.php @@ -102,12 +102,17 @@ class TagAction extends Action function showContent() { - $nl = new NoticeList($this->notice, $this); + if(Event::handle('StartTagShowContent', array($this))) { + + $nl = new NoticeList($this->notice, $this); - $cnt = $nl->show(); + $cnt = $nl->show(); - $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, - $this->page, 'tag', array('tag' => $this->tag)); + $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, + $this->page, 'tag', array('tag' => $this->tag)); + + Event::handle('EndTagShowContent', array($this)) + } } function isReadOnly($args) diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 9f444c8bb..001106ace 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -105,7 +105,7 @@ class RSSCloudPlugin extends Plugin * @return boolean hook return */ - function onRouterInitialized(&$m) + function onRouterInitialized($m) { $m->connect('/main/rsscloud/request_notify', array('action' => 'RSSCloudRequestNotify')); -- cgit v1.2.3-54-g00ecf From 7b1b6045e61973b8835e7253d6b532a752535297 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 24 Mar 2010 00:00:55 -0700 Subject: Look for the first object in the Activity --- plugins/OStatus/actions/usersalmon.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index ecdcfa193..6c360c49f 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -92,7 +92,7 @@ class UsersalmonAction extends SalmonAction throw new ClientException("Not to anyone in reply to anything!"); } - $existing = Notice::staticGet('uri', $this->act->object->id); + $existing = Notice::staticGet('uri', $this->act->objects[0]->id); if (!empty($existing)) { common_log(LOG_ERR, "Not saving notice '{$existing->uri}'; already exists."); @@ -143,7 +143,7 @@ class UsersalmonAction extends SalmonAction function handleFavorite() { - $notice = $this->getNotice($this->act->object); + $notice = $this->getNotice($this->act->objects[0]); $profile = $this->ensureProfile()->localProfile(); $old = Fave::pkeyGet(array('user_id' => $profile->id, @@ -164,7 +164,7 @@ class UsersalmonAction extends SalmonAction */ function handleUnfavorite() { - $notice = $this->getNotice($this->act->object); + $notice = $this->getNotice($this->act->objects[0]); $profile = $this->ensureProfile()->localProfile(); $fave = Fave::pkeyGet(array('user_id' => $profile->id, -- cgit v1.2.3-54-g00ecf From 647b3a1f6bff2f0c8f02ea65939ebde088742b16 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Mar 2010 14:50:12 +0100 Subject: Moved print inside base stylesheet using media rules. One less HTTP GET. --- lib/action.php | 3 +-- theme/base/css/display.css | 32 ++++++++++++++++++++++++++++++++ theme/biz/css/base.css | 32 ++++++++++++++++++++++++++++++++ theme/biz/css/display.css | 3 ++- theme/cloudy/css/display.css | 30 ++++++++++++++++++++++++++++++ theme/default/css/display.css | 4 +++- theme/h4ck3r/css/base.css | 32 ++++++++++++++++++++++++++++++++ theme/h4ck3r/css/display.css | 5 ++++- theme/identica/css/display.css | 4 +++- theme/pigeonthoughts/css/base.css | 32 ++++++++++++++++++++++++++++++++ theme/pigeonthoughts/css/display.css | 4 +++- 11 files changed, 174 insertions(+), 7 deletions(-) diff --git a/lib/action.php b/lib/action.php index 491d7d481..09113a598 100644 --- a/lib/action.php +++ b/lib/action.php @@ -198,8 +198,7 @@ class Action extends HTMLOutputter // lawsuit if (Event::handle('StartShowStatusNetStyles', array($this)) && Event::handle('StartShowLaconicaStyles', array($this))) { - $this->cssLink('css/display.css',null,'screen, projection, tv'); - $this->cssLink('css/print.css','base','print'); + $this->cssLink('css/display.css',null, 'screen, projection, tv, print'); Event::handle('EndShowStatusNetStyles', array($this)); Event::handle('EndShowLaconicaStyles', array($this)); } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index d58684efb..36f0533b1 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -7,6 +7,7 @@ * @link http://status.net/ */ +@media screen, projection, tv { * { margin:0; padding:0; } img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } @@ -1688,3 +1689,34 @@ width:auto; #bookmarklet #wrap { min-width:0; } + +}/*end of @media screen, projection, tv*/ + + +@media print { +a:after { background-color:#FFFFFF; } +a:not([href^="#"]):after { content:" <"attr(href)"> "; } +img { border:none; } +p { orphans: 2; widows: 1; } + +#site_nav_global_primary, +#site_nav_local_views, +#form_notice, +.pagination, +#site_nav_global_secondary, +.entity_actions, +.notice-options, +#aside_primary, +.form_subscription_edit .submit { +display:none; +} +.timestamp dt, .timestamp dd, +.device dt, .device dd { +display:inline; +} +.profiles li, +.notices li { +margin-bottom:18px; +} + +}/*end of @media print*/ diff --git a/theme/biz/css/base.css b/theme/biz/css/base.css index 2c2ab33a0..43b8e4656 100644 --- a/theme/biz/css/base.css +++ b/theme/biz/css/base.css @@ -7,6 +7,7 @@ * @link http://status.net/ */ +@media screen, projection, tv { * { margin:0; padding:0; } img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } @@ -1358,3 +1359,34 @@ display:none; .guide { clear:both; } + +}/*end of @media screen, projection, tv*/ + + +@media print { +a:after { background-color:#FFFFFF; } +a:not([href^="#"]):after { content:" <"attr(href)"> "; } +img { border:none; } +p { orphans: 2; widows: 1; } + +#site_nav_global_primary, +#site_nav_local_views, +#form_notice, +.pagination, +#site_nav_global_secondary, +.entity_actions, +.notice-options, +#aside_primary, +.form_subscription_edit .submit { +display:none; +} +.timestamp dt, .timestamp dd, +.device dt, .device dd { +display:inline; +} +.profiles li, +.notices li { +margin-bottom:18px; +} + +}/*end of @media print*/ diff --git a/theme/biz/css/display.css b/theme/biz/css/display.css index 3e97444f1..cafb152dc 100644 --- a/theme/biz/css/display.css +++ b/theme/biz/css/display.css @@ -7,8 +7,9 @@ * @link http://status.net/ */ -@import url(base.css); +@import url(base.css) screen, projection, tv, print; +@media screen, projection, tv { html { background-color:#144A6E; } diff --git a/theme/cloudy/css/display.css b/theme/cloudy/css/display.css index 5bc32e6d9..d9e9f3ce2 100644 --- a/theme/cloudy/css/display.css +++ b/theme/cloudy/css/display.css @@ -7,6 +7,7 @@ * @link http://status.net/ */ +@media screen, projection, tv { * { margin:0; padding:0; } img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } @@ -2099,4 +2100,33 @@ border-left-color:#FFFFFF; #footer { background-color:#FFFFFF; } +}/*end of @media screen, projection, tv*/ + +@media print { +a:after { background-color:#FFFFFF; } +a:not([href^="#"]):after { content:" <"attr(href)"> "; } +img { border:none; } +p { orphans: 2; widows: 1; } + +#site_nav_global_primary, +#site_nav_local_views, +#form_notice, +.pagination, +#site_nav_global_secondary, +.entity_actions, +.notice-options, +#aside_primary, +.form_subscription_edit .submit { +display:none; +} +.timestamp dt, .timestamp dd, +.device dt, .device dd { +display:inline; +} +.profiles li, +.notices li { +margin-bottom:18px; +} + +}/*end of @media print*/ diff --git a/theme/default/css/display.css b/theme/default/css/display.css index d7f15cc46..7ccd234cd 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -7,8 +7,9 @@ * @link http://status.net/ */ -@import url(../../base/css/display.css); +@import url(../../base/css/display.css) screen, projection, tv, print; +@media screen, projection, tv { body, a:active { background-color:#CEE1E9; @@ -516,3 +517,4 @@ background-position:90% 47%; background-position:10% 47%; } +}/*end of @media screen, projection, tv*/ diff --git a/theme/h4ck3r/css/base.css b/theme/h4ck3r/css/base.css index 18ea742a5..0302653fd 100644 --- a/theme/h4ck3r/css/base.css +++ b/theme/h4ck3r/css/base.css @@ -7,6 +7,7 @@ * @link http://status.net/ */ +@media screen, projection, tv { * { margin:0; padding:0; } img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } @@ -1137,3 +1138,34 @@ display:none; .guide { clear:both; } + +}/*end of @media screen, projection, tv*/ + + +@media print { +a:after { background-color:#FFFFFF; } +a:not([href^="#"]):after { content:" <"attr(href)"> "; } +img { border:none; } +p { orphans: 2; widows: 1; } + +#site_nav_global_primary, +#site_nav_local_views, +#form_notice, +.pagination, +#site_nav_global_secondary, +.entity_actions, +.notice-options, +#aside_primary, +.form_subscription_edit .submit { +display:none; +} +.timestamp dt, .timestamp dd, +.device dt, .device dd { +display:inline; +} +.profiles li, +.notices li { +margin-bottom:18px; +} + +}/*end of @media print*/ diff --git a/theme/h4ck3r/css/display.css b/theme/h4ck3r/css/display.css index 58b3f242a..7112765ab 100644 --- a/theme/h4ck3r/css/display.css +++ b/theme/h4ck3r/css/display.css @@ -7,8 +7,9 @@ * @link http://status.net/ */ -@import url(base.css); +@import url(base.css) screen, projection, tv, print; +@media screen, projection, tv { html, body, a:active { @@ -234,3 +235,5 @@ background-position:10% 45%; background-image:url(../../base/images/icons/twotone/green/arrow-right.gif); background-position:90% 45%; } + +}/*end of @media screen, projection, tv*/ diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index d9f39e780..3972657a7 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -7,8 +7,9 @@ * @link http://status.net/ */ -@import url(../../base/css/display.css); +@import url(../../base/css/display.css) screen, projection, tv, print; +@media screen, projection, tv { body, a:active { background-color:#F0F2F5; @@ -515,3 +516,4 @@ background-position:90% 47%; background-position:10% 47%; } +}/*end of @media screen, projection, tv*/ diff --git a/theme/pigeonthoughts/css/base.css b/theme/pigeonthoughts/css/base.css index 2814260bd..bd12e6eaa 100644 --- a/theme/pigeonthoughts/css/base.css +++ b/theme/pigeonthoughts/css/base.css @@ -7,6 +7,7 @@ * @link http://status.net/ */ +@media screen, projection, tv { * { margin:0; padding:0; } img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } @@ -1383,3 +1384,34 @@ display:none; .guide { clear:both; } + +}/*end of @media screen, projection, tv*/ + + +@media print { +a:after { background-color:#FFFFFF; } +a:not([href^="#"]):after { content:" <"attr(href)"> "; } +img { border:none; } +p { orphans: 2; widows: 1; } + +#site_nav_global_primary, +#site_nav_local_views, +#form_notice, +.pagination, +#site_nav_global_secondary, +.entity_actions, +.notice-options, +#aside_primary, +.form_subscription_edit .submit { +display:none; +} +.timestamp dt, .timestamp dd, +.device dt, .device dd { +display:inline; +} +.profiles li, +.notices li { +margin-bottom:18px; +} + +}/*end of @media print*/ diff --git a/theme/pigeonthoughts/css/display.css b/theme/pigeonthoughts/css/display.css index dfeb01b48..de5164ea8 100644 --- a/theme/pigeonthoughts/css/display.css +++ b/theme/pigeonthoughts/css/display.css @@ -7,8 +7,9 @@ * @link http://status.net/ */ -@import url(base.css); +@import url(base.css) screen, projection, tv, print; +@media screen, projection, tv { html { background:url(../images/illustrations/illu_pigeons-01.png) no-repeat 0 100%; } @@ -496,3 +497,4 @@ background-position:90% 47%; background-position:10% 47%; } +}/*end of @media screen, projection, tv*/ -- cgit v1.2.3-54-g00ecf From 5808f86584a64d6dbd12e070b268f40c043917e4 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Mar 2010 15:13:38 +0100 Subject: Removed print stylesheet --- theme/base/css/print.css | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 theme/base/css/print.css diff --git a/theme/base/css/print.css b/theme/base/css/print.css deleted file mode 100644 index 094d07fed..000000000 --- a/theme/base/css/print.css +++ /dev/null @@ -1,36 +0,0 @@ -/** theme: base - * - * @package StatusNet - * @author Sarven Capadisli - * @copyright 2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -a:after { background-color:#fff; } -a:not([href^="#"]):after { content:" ( "attr(href)" ) "; } - -img { border:none; } -p { orphans: 2; widows: 1; } - -#site_nav_global_primary, -#site_nav_local_views, -#form_notice, -.pagination, -#site_nav_global_secondary, -.entity_actions, -.notice-options, -#aside_primary, -.form_subscription_edit .submit { -display:none; -} - -.timestamp dt, .timestamp dd, -.device dt, .device dd { -display:inline; -} - -.profiles li, -.notices li { -margin-bottom:18px; -} -- cgit v1.2.3-54-g00ecf From 10410907a0a6f1af9fb18cb3341db792baa49cf3 Mon Sep 17 00:00:00 2001 From: James Walker Date: Wed, 24 Mar 2010 14:27:35 -0400 Subject: A bit safer checking in the keypair parsing --- plugins/OStatus/lib/magicenvelope.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 9266cab5c..799b5e307 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -59,12 +59,21 @@ class MagicEnvelope } if ($xrd->links) { if ($link = Discovery::getService($xrd->links, Magicsig::PUBLICKEYREL)) { - list($type, $keypair) = explode(',', $link['href']); - if (empty($keypair)) { + $keypair = false; + $parts = explode(',', $link['href']); + if (count($parts) == 2) { + $keypair = $parts[1]; + } else { // Backwards compatibility check for separator bug in 0.9.0 - list($type, $keypair) = explode(';', $link['href']); + $parts = explode(';', $link['href']); + if (count($parts) == 2) { + $keypair = $parts[1]; + } + } + + if ($keypair) { + return $keypair; } - return $keypair; } } throw new Exception('Unable to locate signer public key'); -- cgit v1.2.3-54-g00ecf From c4273f0ef32f65267ddf43dc5dc6977659a0697e Mon Sep 17 00:00:00 2001 From: James Walker Date: Wed, 24 Mar 2010 15:15:20 -0400 Subject: Check for 0.9.0 bad keys from old Crypt_RSA library --- plugins/OStatus/classes/Magicsig.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 87c684c93..1a9541495 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -50,7 +50,15 @@ class Magicsig extends Memcached_DataObject { $obj = parent::staticGet(__CLASS__, $k, $v); if (!empty($obj)) { - return Magicsig::fromString($obj->keypair); + $obj = Magicsig::fromString($obj->keypair); + + // Double check keys: Crypt_RSA did not + // consistently generate good keypairs. + // We've also moved to 1024 bit keys. + if (strlen($obj->publicKey->modulus->toBits()) != 1024) { + $obj->delete(); + return false; + } } return $obj; -- cgit v1.2.3-54-g00ecf From cfca789b34eeac6c531c4c7aac622ed2e2510390 Mon Sep 17 00:00:00 2001 From: James Walker Date: Wed, 24 Mar 2010 15:18:41 -0400 Subject: Updated Math_Biginteger from upstream - removing safe* workarounds --- plugins/OStatus/classes/Magicsig.php | 8 ++++---- plugins/OStatus/extlib/Math/BigInteger.php | 8 ++++---- plugins/OStatus/lib/safecrypt_rsa.php | 18 ------------------ plugins/OStatus/lib/safemath_biginteger.php | 20 -------------------- 4 files changed, 8 insertions(+), 46 deletions(-) delete mode 100644 plugins/OStatus/lib/safecrypt_rsa.php delete mode 100644 plugins/OStatus/lib/safemath_biginteger.php diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 1a9541495..c7dd17c26 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -108,16 +108,16 @@ class Magicsig extends Memcached_DataObject public function generate($user_id) { - $rsa = new SafeCrypt_RSA(); + $rsa = new Crypt_RSA(); $keypair = $rsa->createKey(); $rsa->loadKey($keypair['privatekey']); - $this->privateKey = new SafeCrypt_RSA(); + $this->privateKey = new Crypt_RSA(); $this->privateKey->loadKey($keypair['privatekey']); - $this->publicKey = new SafeCrypt_RSA(); + $this->publicKey = new Crypt_RSA(); $this->publicKey->loadKey($keypair['publickey']); $this->user_id = $user_id; @@ -169,7 +169,7 @@ class Magicsig extends Memcached_DataObject { common_log(LOG_DEBUG, "Adding ".$type." key: (".$mod .', '. $exp .")"); - $rsa = new SafeCrypt_RSA(); + $rsa = new Crypt_RSA(); $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; $rsa->setHash('sha256'); $rsa->modulus = new Math_BigInteger(base64_url_decode($mod), 256); diff --git a/plugins/OStatus/extlib/Math/BigInteger.php b/plugins/OStatus/extlib/Math/BigInteger.php index 9733351d4..4373805f9 100644 --- a/plugins/OStatus/extlib/Math/BigInteger.php +++ b/plugins/OStatus/extlib/Math/BigInteger.php @@ -67,7 +67,7 @@ * @author Jim Wigginton * @copyright MMVI Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: BigInteger.php,v 1.31 2010/03/01 17:28:19 terrafrost Exp $ + * @version $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $ * @link http://pear.php.net/package/Math_BigInteger */ @@ -294,7 +294,7 @@ class Math_BigInteger { $this->value = array(); } - if ($x === 0) { + if (empty($x)) { return; } @@ -718,7 +718,7 @@ class Math_BigInteger { * * Will be called, automatically, when serialize() is called on a Math_BigInteger object. * - * @see __wakeup + * @see __wakeup() * @access public */ function __sleep() @@ -740,7 +740,7 @@ class Math_BigInteger { * * Will be called, automatically, when unserialize() is called on a Math_BigInteger object. * - * @see __sleep + * @see __sleep() * @access public */ function __wakeup() diff --git a/plugins/OStatus/lib/safecrypt_rsa.php b/plugins/OStatus/lib/safecrypt_rsa.php deleted file mode 100644 index f3aa2c928..000000000 --- a/plugins/OStatus/lib/safecrypt_rsa.php +++ /dev/null @@ -1,18 +0,0 @@ -zero = new SafeMath_BigInteger(); - } -} - diff --git a/plugins/OStatus/lib/safemath_biginteger.php b/plugins/OStatus/lib/safemath_biginteger.php deleted file mode 100644 index c05e24d1e..000000000 --- a/plugins/OStatus/lib/safemath_biginteger.php +++ /dev/null @@ -1,20 +0,0 @@ -hex == '') { - $this->hex = '0'; - } - parent::__wakeup(); - } -} - -- cgit v1.2.3-54-g00ecf From 9e0b9857f435bf45d353bc88eb2462d483bcc46b Mon Sep 17 00:00:00 2001 From: James Walker Date: Wed, 24 Mar 2010 15:26:03 -0400 Subject: Make sure we're requiring the library --- plugins/OStatus/classes/Magicsig.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index c7dd17c26..864fef628 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -27,6 +27,8 @@ * @link http://status.net/ */ +require_once 'Crypt/RSA.php'; + class Magicsig extends Memcached_DataObject { -- cgit v1.2.3-54-g00ecf From e7ae36b52a8192021f3a48f1a3929bbeee877ccd Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Mar 2010 20:50:07 +0100 Subject: Updated tag list output in subscriptions list. Matches userprofile. --- lib/subscriptionlist.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/subscriptionlist.php b/lib/subscriptionlist.php index e1207774f..fc8f33f2e 100644 --- a/lib/subscriptionlist.php +++ b/lib/subscriptionlist.php @@ -113,12 +113,13 @@ class SubscriptionListItem extends ProfileListItem $this->out->elementStart('ul', 'tags xoxo'); foreach ($tags as $tag) { $this->out->elementStart('li'); - $this->out->element('span', 'mark_hash', '#'); - $this->out->element('a', array('rel' => 'tag', - 'href' => common_local_url($this->action->trimmed('action'), - array('nickname' => $this->owner->nickname, - 'tag' => $tag))), - $tag); + // Avoid space by using raw output. + $pt = '#'; + $this->out->raw($pt); $this->out->elementEnd('li'); } $this->out->elementEnd('ul'); -- cgit v1.2.3-54-g00ecf From 09ff213d1c6b8dc42f28b9c637431bafa54146ec Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Mar 2010 20:58:13 +0100 Subject: Using hCard label instead of location. Matches userprofile. --- lib/profilelist.php | 2 +- theme/base/css/display.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/profilelist.php b/lib/profilelist.php index d970e605a..3e5513895 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -213,7 +213,7 @@ class ProfileListItem extends Widget { if (!empty($this->profile->location)) { $this->out->text(' '); - $this->out->elementStart('span', 'location'); + $this->out->elementStart('span', 'label'); $this->out->raw($this->highlight($this->profile->location)); $this->out->elementEnd('span'); } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 36f0533b1..b0ab02bce 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -926,7 +926,7 @@ display:inline; } .profile .entity_profile .fn, -.profile .entity_profile .location { +.profile .entity_profile .label { margin-left:11px; margin-bottom:4px; width:auto; -- cgit v1.2.3-54-g00ecf From 9fe12be41eec8132fcfa6da2dc5fad926a932286 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Mar 2010 21:34:53 +0100 Subject: Using unique @for, @id pair for jabber and sms options in subscriptions --- actions/subscriptions.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/actions/subscriptions.php b/actions/subscriptions.php index ba6171ef4..7b10b3425 100644 --- a/actions/subscriptions.php +++ b/actions/subscriptions.php @@ -196,12 +196,30 @@ class SubscriptionsListItem extends SubscriptionListItem $this->out->hidden('token', common_session_token()); $this->out->hidden('profile', $this->profile->id); if (common_config('xmpp', 'enabled')) { - $this->out->checkbox('jabber', _('Jabber'), $sub->jabber); + $attrs = array('name' => 'jabber', + 'type' => 'checkbox', + 'class' => 'checkbox', + 'id' => 'jabber-'.$this->profile->id); + if ($sub->jabber) { + $attrs['checked'] = 'checked'; + } + + $this->out->element('input', $attrs); + $this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _('Jabber')); } else { $this->out->hidden('jabber', $sub->jabber); } if (common_config('sms', 'enabled')) { - $this->out->checkbox('sms', _('SMS'), $sub->sms); + $attrs = array('name' => 'sms', + 'type' => 'checkbox', + 'class' => 'checkbox', + 'id' => 'sms-'.$this->profile->id); + if ($sub->sms) { + $attrs['checked'] = 'checked'; + } + + $this->out->element('input', $attrs); + $this->out->element('label', array('for' => 'sms-'.$this->profile->id), _('SMS')); } else { $this->out->hidden('sms', $sub->sms); } -- cgit v1.2.3-54-g00ecf From a954fd65ba00328cd1a76e620113d2f639340aaf Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Mar 2010 13:36:57 -0700 Subject: Fix for API group methods, caused failure or output corruption when pulling up local groups by name in api/statusnet/groups/is_member.json/xml --- lib/apiaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/apiaction.php b/lib/apiaction.php index e6aaf9316..9fc1a0779 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -1273,7 +1273,7 @@ class ApiAction extends Action if (empty($local)) { return null; } else { - return User_group::staticGet('id', $local->id); + return User_group::staticGet('id', $local->group_id); } } -- cgit v1.2.3-54-g00ecf