From 71ecd689019a8086570c677af47ead4e02227fb3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 16 Feb 2010 12:45:00 -0500 Subject: [PATCH 001/190] add a FIXME to Profile --- classes/Profile.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/classes/Profile.php b/classes/Profile.php index ab05bb8546..c79b1d893a 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -807,6 +807,8 @@ class Profile extends Memcached_DataObject null, 'http://activitystrea.ms/schema/1.0/person' ); + // FIXME: this presupposes a local user -- not necessarily the case + // instead use User::uri or Remote_profile::uri or Ostatus_profile::homeuri $xs->element( 'id', null, From 201110ffaa8ae0ce4e74fe46a7a730203be681cd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 16 Feb 2010 12:49:54 -0500 Subject: [PATCH 002/190] restructure Activity classes to push more DOM stuff to ActivityUtils --- plugins/OStatus/lib/activity.php | 123 +++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 40 deletions(-) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 048efda2c9..3d02e35848 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -63,22 +63,78 @@ class ActivityUtils * @return string related link, if any */ - static function getLink($element) + static function getPermalink($element) + { + return self::getLink($element, 'alternate', 'text/html'); + } + + /** + * Get the permalink for an Activity object + * + * @param DOMElement $element A DOM element + * + * @return string related link, if any + */ + + static function getLink($element, $rel, $type=null) { $links = $element->getElementsByTagnameNS(self::ATOM, self::LINK); foreach ($links as $link) { - $rel = $link->getAttribute(self::REL); - $type = $link->getAttribute(self::TYPE); + $linkRel = $link->getAttribute(self::REL); + $linkType = $link->getAttribute(self::TYPE); - if ($rel == 'alternate' && $type == 'text/html') { + if ($linkRel == $rel && + (is_null($type) || $linkType == $type)) { return $link->getAttribute(self::HREF); } } return null; } + + /** + * Gets the first child element with the given tag + * + * @param DOMElement $element element to pick at + * @param string $tag tag to look for + * @param string $namespace Namespace to look under + * + * @return DOMElement found element or null + */ + + static function child($element, $tag, $namespace=self::ATOM) + { + $els = $element->getElementsByTagnameNS($namespace, $tag); + + if (empty($els) || $els->length == 0) { + return null; + } else { + return $els->item(0); + } + } + + /** + * Grab the text content of a DOM element child of the current element + * + * @param DOMElement $element Element whose children we examine + * @param string $tag Tag to look up + * @param string $namespace Namespace to use, defaults to Atom + * + * @return string content of the child + */ + + static function childContent($element, $tag, $namespace=self::ATOM) + { + $el = self::child($element, $tag, $namespace); + + if (empty($el)) { + return null; + } else { + return $el->textContent; + } + } } /** @@ -130,6 +186,7 @@ class ActivityObject const URI = 'uri'; const EMAIL = 'email'; + public $element; public $type; public $id; public $title; @@ -150,7 +207,7 @@ class ActivityObject function __construct($element) { - $this->source = $element; + $this->element = $element; if ($element->tagName == 'author') { @@ -179,33 +236,35 @@ class ActivityObject $this->title = $this->_childContent($element, self::TITLE); $this->summary = $this->_childContent($element, self::SUMMARY); $this->content = $this->_childContent($element, self::CONTENT); - $this->source = $this->_childContent($element, self::SOURCE); - $this->link = ActivityUtils::getLink($element); + $this->source = $this->_getSource($element); + + $this->link = ActivityUtils::getPermalink($element); // XXX: grab PoCo stuff } } - /** - * Grab the text content of a DOM element child of the current element - * - * @param DOMElement $element Element whose children we examine - * @param string $tag Tag to look up - * @param string $namespace Namespace to use, defaults to Atom - * - * @return string content of the child - */ - - private function _childContent($element, $tag, $namespace=Activity::ATOM) + private function _childContent($element, $tag, $namespace=ActivityUtils::ATOM) { - $els = $element->getElementsByTagnameNS($namespace, $tag); + return ActivityUtils::childContent($element, $tag, $namespace); + } - if (empty($els) || $els->length == 0) { + // Try to get a unique id for the source feed + + private function _getSource($element) + { + $sourceEl = ActivityUtils::child($element, 'source'); + + if (empty($sourceEl)) { return null; } else { - $el = $els->item(0); - return $el->textContent; + $href = ActivityUtils::getLink($sourceEl, 'self'); + if (!empty($href)) { + return $href; + } else { + return ActivityUtils::childContent($sourceEl, 'id'); + } } } } @@ -306,7 +365,7 @@ class Activity } } - $this->link = ActivityUtils::getLink($entry); + $this->link = ActivityUtils::getPermalink($entry); $verbEl = $this->_child($entry, self::VERB); @@ -370,24 +429,8 @@ class Activity return null; } - /** - * Gets the first child element with the given tag - * - * @param DOMElement $element element to pick at - * @param string $tag tag to look for - * @param string $namespace Namespace to look under - * - * @return DOMElement found element or null - */ - private function _child($element, $tag, $namespace=self::SPEC) { - $els = $element->getElementsByTagnameNS($namespace, $tag); - - if (empty($els) || $els->length == 0) { - return null; - } else { - return $els->item(0); - } + return ActivityUtils::child($element, $tag, $namespace); } } \ No newline at end of file From eea52c708b4688c9b39f24d3931edc9da2cf1b07 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Feb 2010 11:32:10 -0800 Subject: [PATCH 003/190] Add rel="avatar" to img links in stanzas --- classes/Profile.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/classes/Profile.php b/classes/Profile.php index c79b1d893a..8f578c95a3 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -807,8 +807,6 @@ class Profile extends Memcached_DataObject null, 'http://activitystrea.ms/schema/1.0/person' ); - // FIXME: this presupposes a local user -- not necessarily the case - // instead use User::uri or Remote_profile::uri or Ostatus_profile::homeuri $xs->element( 'id', null, @@ -824,6 +822,7 @@ class Profile extends Memcached_DataObject $xs->element( 'link', array( 'type' => empty($avatar) ? 'image/png' : $avatar->mediatype, + 'rel' => 'avatar', 'href' => empty($avatar) ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) : $avatar->displayUrl() From a116cde1a401b1959515b8e6b512c41603387031 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 16 Feb 2010 20:11:48 +0000 Subject: [PATCH 004/190] OStatus: fix for low-level remote subscribe --- plugins/OStatus/classes/Ostatus_profile.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index b750e18839..9b6ef2f163 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -225,7 +225,7 @@ class Ostatus_profile extends Memcached_DataObject try { $local = $munger->profile(); - if ($entity->isGroup()) { + if ($profile->isGroup()) { $group = new User_group(); $group->nickname = $local->nickname . '@remote'; // @fixme $group->fullname = $local->fullname; @@ -245,17 +245,17 @@ class Ostatus_profile extends Memcached_DataObject $profile->profile_id = $local->id; } - $profile->created = sql_common_date(); - $profile->lastupdate = sql_common_date(); + $profile->created = common_sql_now(); + $profile->lastupdate = common_sql_now(); $result = $profile->insert(); if (empty($result)) { throw new FeedDBException($profile); } - $entity->query('COMMIT'); + $profile->query('COMMIT'); } catch (FeedDBException $e) { common_log_db_error($e->obj, 'INSERT', __FILE__); - $entity->query('ROLLBACK'); + $profile->query('ROLLBACK'); return false; } @@ -269,7 +269,7 @@ class Ostatus_profile extends Memcached_DataObject } } - return $entity; + return $profile; } /** From 440ab9039178bfc58c55316eb9ba2e19551bd12b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 16 Feb 2010 22:03:24 +0000 Subject: [PATCH 005/190] OStatus: fix up some recent regressions in subscription setup; fix state checks and verification token, and avatar save on setup. Needs updates for new atom code next... --- plugins/OStatus/actions/pushhub.php | 6 +- plugins/OStatus/classes/Ostatus_profile.php | 83 ++++++++++++++++----- plugins/OStatus/lib/feedmunger.php | 9 ++- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/plugins/OStatus/actions/pushhub.php b/plugins/OStatus/actions/pushhub.php index 901c18f702..13ec09d528 100644 --- a/plugins/OStatus/actions/pushhub.php +++ b/plugins/OStatus/actions/pushhub.php @@ -44,7 +44,7 @@ class PushHubAction extends Action // PHP converts '.'s in incoming var names to '_'s. // It also merges multiple values, which'll break hub.verify and hub.topic for publishing // @fixme handle multiple args - $arg = str_replace('.', '_', $arg); + $arg = str_replace('hub.', 'hub_', $arg); return parent::arg($arg, $def); } @@ -96,7 +96,11 @@ class PushHubAction extends Action $sub = new HubSub(); $sub->topic = $feed; $sub->callback = $callback; + $sub->verify_token = $this->arg('hub.verify_token', null); $sub->secret = $this->arg('hub.secret', null); + if (strlen($sub->secret) > 200) { + throw new ClientException("hub.secret must be no longer than 200 chars", 400); + } $sub->setLease(intval($this->arg('hub.lease_seconds'))); // @fixme check for feeds we don't manage diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 9b6ef2f163..243211c31f 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -262,7 +262,7 @@ class Ostatus_profile extends Memcached_DataObject $avatar = $munger->getAvatar(); if ($avatar) { try { - $this->updateAvatar($avatar); + $profile->updateAvatar($avatar); } catch (Exception $e) { common_log(LOG_ERR, "Exception setting OStatus avatar: " . $e->getMessage()); @@ -283,8 +283,10 @@ class Ostatus_profile extends Memcached_DataObject // ripped from oauthstore.php (for old OMB client) $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); copy($url, $temp_filename); - $imagefile = new ImageFile($profile->id, $temp_filename); - $filename = Avatar::filename($profile->id, + + // @fixme should we be using different ids? + $imagefile = new ImageFile($this->id, $temp_filename); + $filename = Avatar::filename($this->id, image_type_to_extension($imagefile->type), null, common_timestamp()); @@ -376,17 +378,56 @@ class Ostatus_profile extends Memcached_DataObject * The hub will later send us a confirmation POST to /main/push/callback. * * @return bool true on success, false on failure + * @throws ServerException if feed state is not valid */ public function subscribe($mode='subscribe') { - if (common_config('feedsub', 'nohub')) { - // Fake it! We're just testing remote feeds w/o hubs. - return true; + if ($this->sub_state != '') { + throw new ServerException("Attempting to start PuSH subscription to feed in state $this->sub_state"); } - // @fixme use the verification token - #$token = md5(mt_rand() . ':' . $this->feeduri); - #$this->verify_token = $token; - #$this->update(); // @fixme + if (empty($this->huburi)) { + if (common_config('feedsub', 'nohub')) { + // Fake it! We're just testing remote feeds w/o hubs. + return true; + } else { + throw new ServerException("Attempting to start PuSH subscription for feed with no hub"); + } + } + + return $this->doSubscribe('subscribe'); + } + + /** + * Send a PuSH unsubscription request to the hub for this feed. + * The hub will later send us a confirmation POST to /main/push/callback. + * + * @return bool true on success, false on failure + * @throws ServerException if feed state is not valid + */ + public function unsubscribe() { + if ($this->sub_state != 'active') { + throw new ServerException("Attempting to end PuSH subscription to feed in state $this->sub_state"); + } + if (empty($this->huburi)) { + if (common_config('feedsub', 'nohub')) { + // Fake it! We're just testing remote feeds w/o hubs. + return true; + } else { + throw new ServerException("Attempting to end PuSH subscription for feed with no hub"); + } + } + + return $this->doSubscribe('unsubscribe'); + } + + protected function doSubscribe($mode) + { + $orig = clone($this); + $this->verify_token = md5(mt_rand() . ':' . $this->feeduri); + $this->sub_state = $mode; + $this->update($orig); + unset($orig); + try { $callback = common_local_url('pushcallback', array('feed' => $this->id)); $headers = array('Content-Type: application/x-www-form-urlencoded'); @@ -416,6 +457,13 @@ class Ostatus_profile extends Memcached_DataObject } catch (Exception $e) { // wtf! common_log(LOG_ERR, __METHOD__ . ": error \"{$e->getMessage()}\" hitting hub $this->huburi subscribing to $this->feeduri"); + + $orig = clone($this); + $this->verify_token = null; + $this->sub_state = null; + $this->update($orig); + unset($orig); + return false; } } @@ -460,16 +508,6 @@ class Ostatus_profile extends Memcached_DataObject return $this->update($original); } - /** - * Send a PuSH unsubscription request to the hub for this feed. - * The hub will later send us a confirmation POST to /main/push/callback. - * - * @return bool true on success, false on failure - */ - public function unsubscribe() { - return $this->subscribe('unsubscribe'); - } - /** * Send an Activity Streams notification to the remote Salmon endpoint, * if so configured. @@ -568,6 +606,11 @@ class Ostatus_profile extends Memcached_DataObject { common_log(LOG_INFO, __METHOD__ . ": packet for \"$this->feeduri\"! $hmac $xml"); + if ($this->sub_state != 'active') { + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH for inactive feed $this->feeduri (in state '$this->sub_state')"); + return; + } + if ($this->secret) { if (preg_match('/^sha1=([0-9a-fA-F]{40})$/', $hmac, $matches)) { $their_hmac = strtolower($matches[1]); diff --git a/plugins/OStatus/lib/feedmunger.php b/plugins/OStatus/lib/feedmunger.php index c895b6ce24..e8c46de90e 100644 --- a/plugins/OStatus/lib/feedmunger.php +++ b/plugins/OStatus/lib/feedmunger.php @@ -258,11 +258,12 @@ class FeedMunger { // hack hack hack // should get profile for this entry's author... - $remote = Ostatus_profile::staticGet('feeduri', $this->getSelfLink()); - if ($feed) { - return $feed->profile_id; + $feeduri = $this->getSelfLink(); + $remote = Ostatus_profile::staticGet('feeduri', $feeduri); + if ($remote) { + return $remote->profile_id; } else { - throw new Exception("Can't find feed profile"); + throw new Exception("Can't find feed profile for $feeduri"); } } From 880acb05b0f51f873e72a7b4d322cefafe7e850c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 16 Feb 2010 22:04:57 +0000 Subject: [PATCH 006/190] OStatus: temporary output mode hack for apitimelineuser until PuSH feed generation is updated to use the shared code instead of output buffering --- actions/apitimelineuser.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index 24752e45fd..9f7ec4c236 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -196,7 +196,8 @@ class ApiTimelineUserAction extends ApiBareAuthAction $atom->addEntryFromNotices($this->notices); - $this->raw($atom->getString()); + #$this->raw($atom->getString()); + print $atom->getString(); // temporary for output buffering break; case 'json': From 014a32e6b873291bcd289a1ed25759a7a29221d7 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 16 Feb 2010 23:04:39 +0000 Subject: [PATCH 007/190] OStatus: check only direct children in ActivityUtil::child; fixes pulling actor's info when we wanted post info --- plugins/OStatus/lib/activity.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 3d02e35848..5b1c4fa8fa 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -106,12 +106,16 @@ class ActivityUtils static function child($element, $tag, $namespace=self::ATOM) { - $els = $element->getElementsByTagnameNS($namespace, $tag); - + $els = $element->childNodes; if (empty($els) || $els->length == 0) { return null; } else { - return $els->item(0); + for ($i = 0; $i < $els->length; $i++) { + $el = $els->item($i); + if ($el->localName == $tag && $el->namespaceURI == $namespace) { + return $el; + } + } } } From 4a139d1cc861272b45812969878fa62f81ed9cfe Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 16 Feb 2010 23:31:11 +0000 Subject: [PATCH 008/190] OStatus: migrated notice parsing to use Activity helper classes; on the way to killing FeedMunger --- plugins/OStatus/actions/pushcallback.php | 3 + plugins/OStatus/classes/Ostatus_profile.php | 240 ++++++++++++++------ 2 files changed, 173 insertions(+), 70 deletions(-) diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index 2601a377a0..388c8f9c3d 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -59,6 +59,9 @@ class PushCallbackAction extends Action } $post = file_get_contents('php://input'); + + // @fixme Queue this to a background process; we should return + // as quickly as possible from a distribution POST. $profile->postUpdates($post, $hmac); } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 243211c31f..4376d64c66 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -599,89 +599,189 @@ class Ostatus_profile extends Memcached_DataObject * Currently assumes that all items in the feed are new, * coming from a PuSH hub. * - * @param string $xml source of Atom or RSS feed + * @param string $post source of Atom or RSS feed * @param string $hmac X-Hub-Signature header, if present */ - public function postUpdates($xml, $hmac) + public function postUpdates($post, $hmac) { - common_log(LOG_INFO, __METHOD__ . ": packet for \"$this->feeduri\"! $hmac $xml"); + common_log(LOG_INFO, __METHOD__ . ": packet for \"$this->feeduri\"! $hmac $post"); if ($this->sub_state != 'active') { common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH for inactive feed $this->feeduri (in state '$this->sub_state')"); return; } - if ($this->secret) { - if (preg_match('/^sha1=([0-9a-fA-F]{40})$/', $hmac, $matches)) { - $their_hmac = strtolower($matches[1]); - $our_hmac = hash_hmac('sha1', $xml, $this->secret); - if ($their_hmac !== $our_hmac) { - common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bad SHA-1 HMAC: got $their_hmac, expected $our_hmac"); - return; - } - } else { - common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bogus HMAC '$hmac'"); - return; - } - } else if ($hmac) { - common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with unexpected HMAC '$hmac'"); + if ($post === '') { + common_log(LOG_ERR, __METHOD__ . ": ignoring empty post"); return; } - require_once "XML/Feed/Parser.php"; - $feed = new XML_Feed_Parser($xml, false, false, true); - $munger = new FeedMunger($feed); - - $hits = 0; - foreach ($feed as $index => $entry) { - // @fixme this might sort in wrong order if we get multiple updates - - $notice = $munger->notice($index); - - // Double-check for oldies - // @fixme this could explode horribly for multiple feeds on a blog. sigh - - $dupe = Notice::staticGet('uri', $notice->uri); - - if (!empty($dupe)) { - common_log(LOG_WARNING, __METHOD__ . ": tried to save dupe notice for entry {$notice->uri} of feed {$this->feeduri}"); - continue; - } - - // @fixme need to ensure that groups get handled correctly - $saved = Notice::saveNew($notice->profile_id, - $notice->content, - 'ostatus', - array('is_local' => Notice::REMOTE_OMB, - 'uri' => $notice->uri, - 'lat' => $notice->lat, - 'lon' => $notice->lon, - 'location_ns' => $notice->location_ns, - 'location_id' => $notice->location_id)); - - /* - common_log(LOG_DEBUG, "going to check group delivery..."); - if ($this->group_id) { - $group = User_group::staticGet($this->group_id); - if ($group) { - common_log(LOG_INFO, __METHOD__ . ": saving to local shadow group $group->id $group->nickname"); - $groups = array($group); - } else { - common_log(LOG_INFO, __METHOD__ . ": lost the local shadow group?"); - } - } else { - common_log(LOG_INFO, __METHOD__ . ": no local shadow groups"); - $groups = array(); - } - common_log(LOG_DEBUG, "going to add to inboxes..."); - $notice->addToInboxes($groups, array()); - common_log(LOG_DEBUG, "added to inboxes."); - */ - - $hits++; + if (!$this->validatePushSig($post, $hmac)) { + // Per spec we silently drop input with a bad sig, + // while reporting receipt to the server. + return; } - if ($hits == 0) { - common_log(LOG_INFO, __METHOD__ . ": no updates in packet for \"$this->feeduri\"! $xml"); + + $feed = new DOMDocument(); + if (!$feed->loadXML($post)) { + // @fixme might help to include the err message + common_log(LOG_ERR, __METHOD__ . ": ignoring invalid XML"); + return; + } + + $entries = $feed->getElementsByTagNameNS(Activity::ATOM, 'entry'); + if ($entries->length == 0) { + common_log(LOG_ERR, __METHOD__ . ": no entries in feed update, ignoring"); + return; + } + + for ($i = 0; $i < $entries->length; $i++) { + $entry = $entries->item($i); + $this->processEntry($entry, $feed); } } + + /** + * Validate the given Atom chunk and HMAC signature against our + * shared secret that was set up at subscription time. + * + * If we don't have a shared secret, there should be no signature. + * If we we do, our the calculated HMAC should match theirs. + * + * @param string $post raw XML source as POSTed to us + * @param string $hmac X-Hub-Signature HTTP header value, or empty + * @return boolean true for a match + */ + protected function validatePushSig($post, $hmac) + { + if ($this->secret) { + if (preg_match('/^sha1=([0-9a-fA-F]{40})$/', $hmac, $matches)) { + $their_hmac = strtolower($matches[1]); + $our_hmac = hash_hmac('sha1', $post, $this->secret); + if ($their_hmac === $our_hmac) { + return true; + } + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bad SHA-1 HMAC: got $their_hmac, expected $our_hmac"); + } else { + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bogus HMAC '$hmac'"); + } + } else { + if (empty($hmac)) { + return true; + } else { + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with unexpected HMAC '$hmac'"); + } + } + return false; + } + + /** + * Process a posted entry from this feed source. + * + * @param DOMElement $entry + * @param DOMElement $feed for context + */ + protected function processEntry($entry, $feed) + { + $activity = new Activity($entry, $feed); + + $debug = var_export($activity, true); + common_log(LOG_DEBUG, $debug); + + if ($activity->verb == ActivityVerb::POST) { + $this->processPost($activity); + } else { + common_log(LOG_INFO, "Ignoring activity with unrecognized verb $activity->verb"); + } + } + + /** + * Process an incoming post activity from this remote feed. + * @param Activity $activity + */ + protected function processPost($activity) + { + // @fixme pull profile reference from actor for group feeds + $actor = $this; + $localProfile = $actor->localProfile(); + if (empty($localProfile)) { + common_log(LOG_INFO, "OStatus: ignoring post with invalid author"); + return; + } + + if (empty($activity->object)) { + // This shouldn't happen! + common_log(LOG_INFO, "OStatus: ignoring post with missing post object."); + return; + } + + if ($activity->object->link) { + $sourceUri = $activity->object->link; + } else if (preg_match('!^https?://!', $activity->object->id)) { + $sourceUri = $activity->object->id; + } else { + common_log(LOG_INFO, "OStatus: ignoring post with no source link: id $activity->object->id"); + return; + } + + $dupe = Notice::staticGet('uri', $sourceUri); + if ($dupe) { + common_log(LOG_INFO, "OStatus: ignoring duplicate post: $noticeLink"); + return; + } + + // @fixme sanitize and save HTML content if available + $content = $activity->object->title; + + $params = array('is_local' => Notice::REMOTE_OMB, + 'uri' => $sourceUri); + + $location = $this->getEntryLocation($activity->entry); + if ($location) { + $params['lat'] = $location->lat; + $params['lon'] = $location->lon; + if ($location->location_id) { + $params['location_ns'] = $location->location_ns; + $params['location_id'] = $location->location_id; + } + } + + // @fixme save detailed ostatus source info + // @fixme ensure that groups get handled correctly + + $saved = Notice::saveNew($localProfile->id, + $content, + 'ostatus', + $params); + } + + /** + * Parse location given as a GeoRSS-simple point, if provided. + * http://www.georss.org/simple + * + * @param feed item $entry + * @return mixed Location or false + */ + function getLocation($dom) + { + $points = $dom->getElementsByTagNameNS('http://www.georss.org/georss', 'point'); + + for ($i = 0; $i < $points->length; $i++) { + $point = $points->item(0)->textContent; + $point = str_replace(',', ' ', $point); // per spec "treat commas as whitespace" + $point = preg_replace('/\s+/', ' ', $point); + $point = trim($point); + $coords = explode(' ', $point); + if (count($coords) == 2) { + list($lat, $lon) = $coords; + if (is_numeric($lat) && is_numeric($lon)) { + common_log(LOG_INFO, "Looking up location for $lat $lon from georss"); + return Location::fromLatLon($lat, $lon); + } + } + common_log(LOG_ERR, "Ignoring bogus georss:point value $point"); + } + + return false; + } } From c892726c80b4e466b2bbad0f7b396cf0c7a137d9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Feb 2010 16:22:58 -0800 Subject: [PATCH 009/190] Take remote profiles into account when looking up canonical profile URIs --- EVENTS.txt | 5 ++++- classes/Notice.php | 2 +- classes/Profile.php | 21 +++++++++++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index 69fe2ddccb..f333c5442f 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -1,4 +1,4 @@ -\InitializePlugin: a chance to initialize a plugin in a complete environment +InitializePlugin: a chance to initialize a plugin in a complete environment CleanupPlugin: a chance to cleanup a plugin at the end of a program @@ -722,3 +722,6 @@ StartRobotsTxt: Before outputting the robots.txt page EndRobotsTxt: After the default robots.txt page (good place for customization) - &$action: RobotstxtAction being shown +GetProfileUri: When determining the canonical URI for a given profile +- &$profile: the current profile + diff --git a/classes/Notice.php b/classes/Notice.php index 73b22d58a0..f184b9c52c 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1036,7 +1036,7 @@ class Notice extends Memcached_DataObject $xs->element( 'link', array( 'rel' => 'ostatus:attention', - 'href' => $profile->getAcctUri() + 'href' => $profile->getUri() ) ); } diff --git a/classes/Profile.php b/classes/Profile.php index 8f578c95a3..5a86619fd2 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -810,10 +810,7 @@ class Profile extends Memcached_DataObject $xs->element( 'id', null, - common_local_url( - 'userbyid', - array('id' => $this->id) - ) + $this->getUri() ); $xs->element('title', null, $this->getBestName()); @@ -835,9 +832,21 @@ class Profile extends Memcached_DataObject return $xs->getString(); } - function getAcctUri() + function getUri() { - return $this->nickname . '@' . common_config('site', 'server'); + if (Event::handle('GetProfileUri', array($this))) { + + $remote = Remote_profile::staticGet('id', $this->id); + + if (!empty($remote)) { + return $remote->uri; + } else { + return common_local_url( + 'userbyid', + array('id' => $this->id) + ); + } + } } } From 454d0b5738a1b79510b998b6da6d0df129a182ab Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 17 Feb 2010 01:49:49 +0000 Subject: [PATCH 010/190] OStatus: moving parts of profile processing to Activity from feedmunger. Pausing before refactoring DB schema a bit to clean up feed vs person vs group info --- plugins/OStatus/classes/Ostatus_profile.php | 185 ++++++++++++++++++-- plugins/OStatus/lib/activity.php | 8 + 2 files changed, 175 insertions(+), 18 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 4376d64c66..be01cdfe19 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -218,10 +218,6 @@ class Ostatus_profile extends Memcached_DataObject $profile->query('BEGIN'); - // Awful hack! Awful hack! - $profile->verify = common_good_rand(16); - $profile->secret = common_good_rand(32); - try { $local = $munger->profile(); @@ -423,7 +419,10 @@ class Ostatus_profile extends Memcached_DataObject protected function doSubscribe($mode) { $orig = clone($this); - $this->verify_token = md5(mt_rand() . ':' . $this->feeduri); + $this->verify_token = common_good_rand(16); + if ($mode == 'subscribe') { + $this->secret = common_good_rand(32); + } $this->sub_state = $mode; $this->update($orig); unset($orig); @@ -701,18 +700,19 @@ class Ostatus_profile extends Memcached_DataObject */ protected function processPost($activity) { - // @fixme pull profile reference from actor for group feeds - $actor = $this; - $localProfile = $actor->localProfile(); - if (empty($localProfile)) { - common_log(LOG_INFO, "OStatus: ignoring post with invalid author"); - return; - } - - if (empty($activity->object)) { - // This shouldn't happen! - common_log(LOG_INFO, "OStatus: ignoring post with missing post object."); - return; + if ($this->isGroup()) { + // @fixme validate these profiles in some way! + $oprofile = $this->ensureActorProfile($activity); + } else { + $actorUri = $this->getActorProfileURI($activity); + if ($actorUri == $this->homeuri) { + // @fixme check if profile info has changed and update it + } else { + // @fixme drop or reject the messages once we've got the canonical profile URI recorded sanely + common_log(LOG_INFO, "OStatus: Warning: non-group post with unexpected author: $actorUri expected $this->homeuri"); + //return; + } + $oprofile = $this; } if ($activity->object->link) { @@ -749,7 +749,7 @@ class Ostatus_profile extends Memcached_DataObject // @fixme save detailed ostatus source info // @fixme ensure that groups get handled correctly - $saved = Notice::saveNew($localProfile->id, + $saved = Notice::saveNew($oprofile->localProfile()->id, $content, 'ostatus', $params); @@ -784,4 +784,153 @@ class Ostatus_profile extends Memcached_DataObject return false; } + + /** + * Get an appropriate avatar image source URL, if available. + * + * @param ActivityObject $actor + * @param DOMElement $feed + * @return string + */ + function getAvatar($actor, $feed) + { + $url = ''; + $icon = ''; + if ($actor->avatar) { + $url = trim($actor->avatar); + } + if (!$url) { + // Check and on the feed + $els = $feed->childNodes(); + if ($els && $els->length) { + for ($i = 0; $i < $els->length; $i++) { + $el = $els->item($i); + if ($el->namespaceURI == Activity::ATOM) { + if (empty($url) && $el->localName == 'logo') { + $url = trim($el->textContent); + break; + } + if (empty($icon) && $el->localName == 'icon') { + // Use as a fallback + $icon = trim($el->textContent); + } + } + } + } + if ($icon && !$url) { + $url = $icon; + } + } + if ($url) { + $opts = array('allowed_schemes' => array('http', 'https')); + if (Validate::uri($url, $opts)) { + return $url; + } + } + return common_path('plugins/OStatus/images/96px-Feed-icon.svg.png'); + } + + /** + * @fixme move off of ostatus_profile or static? + */ + function ensureActorProfile($activity) + { + $profile = $this->getActorProfile($activity); + if (!$profile) { + $profile = $this->createActorProfile($activity); + } + return $profile; + } + + /** + * @param Activity $activity + * @return mixed matching Ostatus_profile or false if none known + */ + function getActorProfile($activity) + { + $homeuri = $this->getActorProfileURI($activity); + return Ostatus_profile::staticGet('homeuri', $homeuri); + } + + /** + * @param Activity $activity + * @return string + * @throws ServerException + */ + function getActorProfileURI($activity) + { + $opts = array('allowed_schemes' => array('http', 'https')); + $actor = $activity->actor; + if ($actor->id && Validate::uri($actor->id, $opts)) { + return $actor->id; + } + if ($actor->link && Validate::uri($actor->link, $opts)) { + return $actor->link; + } + throw new ServerException("No author ID URI found"); + } + + /** + * + */ + function createActorProfile($activity) + { + $actor = $activity->actor(); + $homeuri = $this->getActivityProfileURI($activity); + $nickname = $this->getAuthorNick($activity); + $avatar = $this->getAvatar($actor, $feed); + + $profile = new Profile(); + $profile->nickname = $nickname; + $profile->fullname = $actor->displayName; + $profile->homepage = $actor->link; // @fixme + $profile->profileurl = $homeuri; + // @fixme bio + // @fixme tags/categories + // @fixme location? + // @todo tags from categories + // @todo lat/lon/location? + + $ok = $profile->insert(); + if ($ok) { + $this->updateAvatar($profile, $avatar); + } else { + throw new ServerException("Can't save local profile"); + } + + // @fixme either need to do feed discovery here + // or need to split out some of the feed stuff + // so we can leave it empty until later. + $oprofile = new Ostatus_profile(); + $oprofile->homeuri = $homeuri; + $oprofile->profile_id = $profile->id; + + $ok = $oprofile->insert(); + if ($ok) { + return $oprofile; + } else { + throw new ServerException("Can't save OStatus profile"); + } + } + + /** + * @fixme move this into Activity? + * @param Activity $activity + * @return string + */ + function getAuthorNick($activity) + { + // @fixme not technically part of the actor? + foreach (array($activity->entry, $activity->feed) as $source) { + $author = ActivityUtil::child($source, 'author', Activity::ATOM); + if ($author) { + $name = ActivityUtil::child($author, 'name', Activity::ATOM); + if ($name) { + return trim($name->textContent); + } + } + } + return false; + } + } diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 5b1c4fa8fa..f137946ab4 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -247,6 +247,14 @@ class ActivityObject // XXX: grab PoCo stuff } + + // Some per-type attributes... + if ($this->type == self::PERSON || $this->type == self::GROUP) { + $this->displayName = $this->title; + + // @fixme we may have multiple avatars with different resolutions specified + $this->avatar = ActivityUtils::getLink($element, 'avatar'); + } } private function _childContent($element, $tag, $namespace=ActivityUtils::ATOM) From e51e96d7248b281e7d0e59f5a9bdcd4e7e651e82 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 17 Feb 2010 02:16:03 +0000 Subject: [PATCH 011/190] OStatus: override source link with the source domain and link to original message --- lib/noticelist.php | 28 ++++++++++++++++------------ plugins/OStatus/OStatusPlugin.php | 13 +++++++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/lib/noticelist.php b/lib/noticelist.php index c05b990245..837cb90faa 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -492,30 +492,34 @@ class NoticeListItem extends Widget break; default: - $name = null; + $name = $source_name; $url = null; - $ns = Notice_source::staticGet($this->notice->source); + if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) { + $ns = Notice_source::staticGet($this->notice->source); - if ($ns) { - $name = $ns->name; - $url = $ns->url; - } else { - $app = Oauth_application::staticGet('name', $this->notice->source); - if ($app) { - $name = $app->name; - $url = $app->source_url; + if ($ns) { + $name = $ns->name; + $url = $ns->url; + } else { + $app = Oauth_application::staticGet('name', $this->notice->source); + if ($app) { + $name = $app->name; + $url = $app->source_url; + } } } + Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title)); if (!empty($name) && !empty($url)) { $this->out->elementStart('span', 'device'); $this->out->element('a', array('href' => $url, - 'rel' => 'external'), + 'rel' => 'external', + 'title' => $title), $name); $this->out->elementEnd('span'); } else { - $this->out->element('span', 'device', $source_name); + $this->out->element('span', 'device', $name); } break; } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 3b1329d6c5..b6c9fa1d4c 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -289,4 +289,17 @@ class OStatusPlugin extends Plugin $action->script(common_path('plugins/OStatus/js/ostatus.js')); return true; } + + function onStartNoticeSourceLink($notice, &$name, &$url, &$title) + { + if ($notice->source == 'ostatus') { + $bits = parse_url($notice->uri); + $domain = $bits['host']; + + $name = $domain; + $url = $notice->uri; + $title = sprintf(_m("Sent from %s via OStatus"), $domain); + return false; + } + } } From 2cb243808c2c1540f2690bff5a2d9932fa428923 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Feb 2010 20:13:39 -0800 Subject: [PATCH 012/190] More sensical profile::getUri() --- EVENTS.txt | 8 ++++++-- classes/Profile.php | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index f333c5442f..90242fa133 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -722,6 +722,10 @@ StartRobotsTxt: Before outputting the robots.txt page EndRobotsTxt: After the default robots.txt page (good place for customization) - &$action: RobotstxtAction being shown -GetProfileUri: When determining the canonical URI for a given profile -- &$profile: the current profile +StartGetProfileUri: When determining the canonical URI for a given profile +- $profile: the current profile +- &$uri: the URI +EndGetProfileUri: After determining the canonical URI for a given profile +- $profile: the current profile +- &$uri: the URI diff --git a/classes/Profile.php b/classes/Profile.php index 5a86619fd2..494c697e42 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -769,7 +769,7 @@ class Profile extends Memcached_DataObject $xs->elementStart('author'); $xs->element('name', null, $this->nickname); - $xs->element('uri', null, $this->profileurl); + $xs->element('uri', null, $this->getUri()); $xs->elementEnd('author'); return $xs->getString(); @@ -832,21 +832,40 @@ class Profile extends Memcached_DataObject return $xs->getString(); } + /** + * Returns the best URI for a profile. Plugins may override. + * + * @return string $uri + */ function getUri() { - if (Event::handle('GetProfileUri', array($this))) { + $uri = null; - $remote = Remote_profile::staticGet('id', $this->id); + // check for a local user first + $user = User::staticGet('id', $this->id); - if (!empty($remote)) { - return $remote->uri; - } else { - return common_local_url( - 'userbyid', - array('id' => $this->id) - ); + if (!empty($user)) { + $uri = common_local_url( + 'userbyid', + array('id' => $user->id) + ); + } else { + + // give plugins a chance to set the URI + if (Event::handle('StartGetProfileUri', array($this, &$uri))) { + + // return OMB profile if any + $remote = Remote_profile::staticGet('id', $this->id); + + if (!empty($remote)) { + $uri = $remote->uri; + } + + Event::handle('EndGetProfileUri', array($this, &$uri)); } } + + return $uri; } } From a2f8c5da171d23790811677affd7ca5301a995a5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Feb 2010 23:30:08 -0800 Subject: [PATCH 013/190] New Conversation DO to handle remote notices as conversation roots --- classes/Conversation.php | 49 ++++++++++++++++++++++++++++++++++++++++ classes/statusnet.ini | 9 ++++++++ db/statusnet.sql | 8 +++++++ 3 files changed, 66 insertions(+) create mode 100755 classes/Conversation.php diff --git a/classes/Conversation.php b/classes/Conversation.php new file mode 100755 index 0000000000..929b06c149 --- /dev/null +++ b/classes/Conversation.php @@ -0,0 +1,49 @@ +. + * + * @category Data + * @package StatusNet + * @author Zach Copley + * @copyright 2010 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/ + */ + +require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; + +class Conversation extends Memcached_DataObject +{ + ###START_AUTOCODE + /* the code below is auto generated do not remove the above tag */ + + public $__table = 'conversation'; // table name + public $id; // int(4) primary_key not_null + public $uri; // varchar(225) unique_key not_null + public $created; // datetime not_null + public $modified; // timestamp not_null default_CURRENT_TIMESTAMP + + /* Static get */ + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Session',$k,$v); } + + /* the code above is auto generated do not remove the tag below */ + ###END_AUTOCODE +} + diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 5f8da7cf51..7a9ae07e70 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -47,6 +47,15 @@ modified = 384 [consumer__keys] consumer_key = K +[conversation] +id = 129 +uri = 130 +created = 142 +modified = 384 + +[conversation__keys] +id = N + [deleted_notice] id = 129 profile_id = 129 diff --git a/db/statusnet.sql b/db/statusnet.sql index 3434648016..74e5b69547 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -633,3 +633,11 @@ create table inbox ( constraint primary key (user_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table conversation ( + id integer auto_increment primary key comment 'unique identifier', + uri varchar(225) not null unique comment 'URI of the conversation', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified' +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + From ed46a38ecfea0a87e01aacfcde181087d5e0f19f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 01:11:14 -0800 Subject: [PATCH 014/190] - conversation.uri needs to be nullable - factory method for creating new local conversations --- classes/Conversation.php | 33 +++++++++++++++++++++++++++++++-- classes/statusnet.ini | 3 ++- db/statusnet.sql | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/classes/Conversation.php b/classes/Conversation.php index 929b06c149..ea8bd87b56 100755 --- a/classes/Conversation.php +++ b/classes/Conversation.php @@ -36,14 +36,43 @@ class Conversation extends Memcached_DataObject public $__table = 'conversation'; // table name public $id; // int(4) primary_key not_null - public $uri; // varchar(225) unique_key not_null + public $uri; // varchar(225) unique_key public $created; // datetime not_null public $modified; // timestamp not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Session',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('conversation',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + /** + * Factory method for creating a new conversation + * + * @return Conversation the new conversation DO + */ + static function create() + { + $conv = new Conversation(); + $conv->created = common_sql_now(); + $id = $conv->insert(); + + if (empty($id)) { + common_log_db_error($conv, 'INSERT', __FILE__); + return null; + } + + $orig = clone($conv); + $orig->uri = common_local_url('conversation', array('id' => $id)); + $result = $orig->update($conv); + + if (empty($result)) { + common_log_db_error($conv, 'UPDATE', __FILE__); + return null; + } + + return $conv; + } + } diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 7a9ae07e70..81c1b68b23 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -49,12 +49,13 @@ consumer_key = K [conversation] id = 129 -uri = 130 +uri = 2 created = 142 modified = 384 [conversation__keys] id = N +uri = U [deleted_notice] id = 129 diff --git a/db/statusnet.sql b/db/statusnet.sql index 74e5b69547..97117c80aa 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -636,7 +636,7 @@ create table inbox ( create table conversation ( id integer auto_increment primary key comment 'unique identifier', - uri varchar(225) not null unique comment 'URI of the conversation', + uri varchar(225) unique comment 'URI of the conversation', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified' ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; From 198c046c896c2a1c4dc9037fa538c14179e827ce Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 01:12:13 -0800 Subject: [PATCH 015/190] - Set the root of a new local conversation to a new conversation.id - Output conversation URIs from conversation.uri --- classes/Notice.php | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index f184b9c52c..b0edb6de60 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -309,7 +309,8 @@ class Notice extends Memcached_DataObject // the beginning of a new conversation. if (empty($notice->conversation)) { - $notice->conversation = $notice->id; + $conv = Conversation::create(); + $notice->conversation = $conv->id; $changed = true; } @@ -331,14 +332,15 @@ class Notice extends Memcached_DataObject return $notice; } - function blowOnInsert() + function blowOnInsert($conversation = false) { self::blow('profile:notice_ids:%d', $this->profile_id); self::blow('public'); - if ($this->conversation != $this->id) { - self::blow('notice:conversation_ids:%d', $this->conversation); - } + // XXX: Before we were blowing the casche only if the notice id + // was not the root of the conversation. What to do now? + + self::blow('notice:conversation_ids:%d', $this->conversation); if (!empty($this->repeat_of)) { self::blow('notice:repeats:%d', $this->repeat_of); @@ -1015,24 +1017,25 @@ class Notice extends Memcached_DataObject } } - if (!empty($this->conversation) - && $this->conversation != $this->id) { - $xs->element( - 'link', array( - 'rel' => 'ostatus:conversation', - 'href' => common_local_url( - 'conversation', - array('id' => $this->conversation) - ) + if (!empty($this->conversation)) { + + $conv = Conversation::staticGet('id', $this->conversation); + + if (!empty($conv)) { + $xs->element( + 'link', array( + 'rel' => 'ostatus:conversation', + 'href' => $conv->uri ) ); + } } $reply_ids = $this->getReplies(); foreach ($reply_ids as $id) { $profile = Profile::staticGet('id', $id); - if (!empty($profile)) { + if (!empty($profile)) { $xs->element( 'link', array( 'rel' => 'ostatus:attention', From 389e6d54bfcabd0eb2f6849c914684808aefa53c Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 17 Feb 2010 10:29:08 -0500 Subject: [PATCH 016/190] Fix script references in infinite scroll plugin and autocomplete plugin Add indicator.gif used by autocomplete plugin --- plugins/Autocomplete/AutocompletePlugin.php | 4 ++-- .../jquery-autocomplete/indicator.gif | Bin 0 -> 673 bytes plugins/InfiniteScroll/InfiniteScrollPlugin.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 plugins/Autocomplete/jquery-autocomplete/indicator.gif diff --git a/plugins/Autocomplete/AutocompletePlugin.php b/plugins/Autocomplete/AutocompletePlugin.php index d586631a4a..a28c65a294 100644 --- a/plugins/Autocomplete/AutocompletePlugin.php +++ b/plugins/Autocomplete/AutocompletePlugin.php @@ -42,8 +42,8 @@ class AutocompletePlugin extends Plugin function onEndShowScripts($action){ if (common_logged_in()) { - $action->script('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js'); - $action->script('plugins/Autocomplete/Autocomplete.js'); + $action->script(common_path('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js')); + $action->script(common_path('plugins/Autocomplete/Autocomplete.js')); } } diff --git a/plugins/Autocomplete/jquery-autocomplete/indicator.gif b/plugins/Autocomplete/jquery-autocomplete/indicator.gif new file mode 100644 index 0000000000000000000000000000000000000000..d0bce1542342e912da81a2c260562df172f30d73 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nnmm28Kh24mmkF0U1e2Nli^nlO|14{Lk&@8WQa67~pE8 zXTZz|lvDgC+Z`3#dv5h=E26FfcG1 zbL_hF&)}42ws10s6^G;;cE1^EoUR)U5A70}d2pLv!jVIT7j&Z~EblI3x0K*v_sV|m z0kj3v921Z^em#l`(k(o@H$3ZdDRc@9NidXDNbqrumReCGv$gd8+e8WW28HVqkJ_9i zH>s*<31KtHjANIPvi2#*6BEu%3Dak5O_t&NBI)H?V$TxT}#l{vOTn5naXTfF^&~Hhq+NX@#Ccc>y7T?;vjI&jdhsDsPJyAw*m0Qz>i}K7# zL9w50Ng{fT}A5JUe8lRK1h7_Y2;BWJDd=c6f&i?Wv5(5q?6|P zQw{>maxZP<537OA37Uk}7@%_$4o$EWe_Zl>&#id|lE-BpDC#+Fn|msJ%_2h{Hg1vP z#N8WAzfWasG}yq|xqE)DrWaOofX=z|?*pgc%{ig5vl!pqDlC|q&~Z0$&Rvsft&VO- z4MZj+%-+Vx%W}v;V76hyp=;+R;x+~t^Q%*xuFTQAF2})fSfTHDAs>sO!OBw`)&)o$ c0!CNZt))x~rAZP^^P&YOFfdqy5)K#u0POD40{{R3 literal 0 HcmV?d00001 diff --git a/plugins/InfiniteScroll/InfiniteScrollPlugin.php b/plugins/InfiniteScroll/InfiniteScrollPlugin.php index a4d1a5d05c..77ad83a51b 100644 --- a/plugins/InfiniteScroll/InfiniteScrollPlugin.php +++ b/plugins/InfiniteScroll/InfiniteScrollPlugin.php @@ -40,8 +40,8 @@ class InfiniteScrollPlugin extends Plugin function onEndShowScripts($action) { - $action->script('plugins/InfiniteScroll/jquery.infinitescroll.js'); - $action->script('plugins/InfiniteScroll/infinitescroll.js'); + $action->script(common_path('plugins/InfiniteScroll/jquery.infinitescroll.js')); + $action->script(common_path('plugins/InfiniteScroll/infinitescroll.js')); } function onPluginVersion(&$versions) From c19300272f0074359b2713c35d2fb46bbd1b42ec Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 17 Feb 2010 12:02:59 -0500 Subject: [PATCH 017/190] parse_url returns an associative array - not an object --- lib/htmloutputter.php | 2 +- plugins/Minify/MinifyPlugin.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 47e56fc8f8..7315fe2ad4 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -439,7 +439,7 @@ class HTMLOutputter extends XMLOutputter { if(Event::handle('StartCssLinkElement', array($this,&$src,&$theme,&$media))) { $url = parse_url($src); - if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment)) + if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) { if(file_exists(Theme::file($src,$theme))){ $src = Theme::path($src, $theme); diff --git a/plugins/Minify/MinifyPlugin.php b/plugins/Minify/MinifyPlugin.php index b49b6a4bad..fe1883ded4 100644 --- a/plugins/Minify/MinifyPlugin.php +++ b/plugins/Minify/MinifyPlugin.php @@ -96,7 +96,7 @@ class MinifyPlugin extends Plugin && is_null(common_config('theme', 'path')) && is_null(common_config('theme', 'server')); $url = parse_url($src); - if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment)) + if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) { if(!isset($theme)) { $theme = common_config('site', 'theme'); From 46e9aa13aa87955b441bc63b7cf2f58622b131b0 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 17 Feb 2010 12:03:14 -0500 Subject: [PATCH 018/190] htmloutputter->script() special cases src's that begin with plugin/ or local/ so that plugins don't need to include common_path() in every call to $action->script() Adjust plugins to not call common_path() when it's not necessary Fix minify plugin --- lib/htmloutputter.php | 63 ++++++++++--------- plugins/Autocomplete/AutocompletePlugin.php | 4 +- plugins/Comet/CometPlugin.php | 2 +- plugins/Facebook/FacebookPlugin.php | 2 +- plugins/Facebook/facebookaction.php | 2 +- .../InfiniteScroll/InfiniteScrollPlugin.php | 4 +- plugins/Minify/MinifyPlugin.php | 6 +- plugins/OStatus/OStatusPlugin.php | 4 +- plugins/Orbited/OrbitedPlugin.php | 4 +- plugins/Realtime/RealtimePlugin.php | 4 +- 10 files changed, 53 insertions(+), 42 deletions(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 7315fe2ad4..7786b5941e 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -356,40 +356,47 @@ class HTMLOutputter extends XMLOutputter if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) { - $path = common_config('javascript', 'path'); + if (strpos($src, 'plugins/') === 0 || strpos($src, 'local/') === 0) { - if (empty($path)) { - $path = common_config('site', 'path') . '/js/'; - } + $src = common_path($src) . '?version=' . STATUSNET_VERSION; - if ($path[strlen($path)-1] != '/') { - $path .= '/'; - } + }else{ - if ($path[0] != '/') { - $path = '/'.$path; - } + $path = common_config('javascript', 'path'); - $server = common_config('javascript', 'server'); - - if (empty($server)) { - $server = common_config('site', 'server'); - } - - $ssl = common_config('javascript', 'ssl'); - - if (is_null($ssl)) { // null -> guess - if (common_config('site', 'ssl') == 'always' && - !common_config('javascript', 'server')) { - $ssl = true; - } else { - $ssl = false; + if (empty($path)) { + $path = common_config('site', 'path') . '/js/'; } + + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } + + if ($path[0] != '/') { + $path = '/'.$path; + } + + $server = common_config('javascript', 'server'); + + if (empty($server)) { + $server = common_config('site', 'server'); + } + + $ssl = common_config('javascript', 'ssl'); + + if (is_null($ssl)) { // null -> guess + if (common_config('site', 'ssl') == 'always' && + !common_config('javascript', 'server')) { + $ssl = true; + } else { + $ssl = false; + } + } + + $protocol = ($ssl) ? 'https' : 'http'; + + $src = $protocol.'://'.$server.$path.$src . '?version=' . STATUSNET_VERSION; } - - $protocol = ($ssl) ? 'https' : 'http'; - - $src = $protocol.'://'.$server.$path.$src . '?version=' . STATUSNET_VERSION; } $this->element('script', array('type' => $type, diff --git a/plugins/Autocomplete/AutocompletePlugin.php b/plugins/Autocomplete/AutocompletePlugin.php index a28c65a294..d586631a4a 100644 --- a/plugins/Autocomplete/AutocompletePlugin.php +++ b/plugins/Autocomplete/AutocompletePlugin.php @@ -42,8 +42,8 @@ class AutocompletePlugin extends Plugin function onEndShowScripts($action){ if (common_logged_in()) { - $action->script(common_path('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js')); - $action->script(common_path('plugins/Autocomplete/Autocomplete.js')); + $action->script('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js'); + $action->script('plugins/Autocomplete/Autocomplete.js'); } } diff --git a/plugins/Comet/CometPlugin.php b/plugins/Comet/CometPlugin.php index 300d1e9a24..29cb3004bf 100644 --- a/plugins/Comet/CometPlugin.php +++ b/plugins/Comet/CometPlugin.php @@ -68,7 +68,7 @@ class CometPlugin extends RealtimePlugin $ours = array('jquery.comet.js', 'cometupdate.js'); foreach ($ours as $script) { - $scripts[] = common_path('plugins/Comet/'.$script); + $scripts[] = 'plugins/Comet/'.$script; } return $scripts; diff --git a/plugins/Facebook/FacebookPlugin.php b/plugins/Facebook/FacebookPlugin.php index 4266b886d9..78c9054e14 100644 --- a/plugins/Facebook/FacebookPlugin.php +++ b/plugins/Facebook/FacebookPlugin.php @@ -181,7 +181,7 @@ class FacebookPlugin extends Plugin if ($this->reqFbScripts($action)) { $apikey = common_config('facebook', 'apikey'); - $plugin_path = common_path('plugins/Facebook'); + $plugin_path = 'plugins/Facebook'; $login_url = common_local_url('FBConnectAuth'); $logout_url = common_local_url('logout'); diff --git a/plugins/Facebook/facebookaction.php b/plugins/Facebook/facebookaction.php index 8437a705a7..f65b97c865 100644 --- a/plugins/Facebook/facebookaction.php +++ b/plugins/Facebook/facebookaction.php @@ -89,7 +89,7 @@ class FacebookAction extends Action function showScripts() { - $this->script(common_path('plugins/Facebook/facebookapp.js')); + $this->script('plugins/Facebook/facebookapp.js'); } /** diff --git a/plugins/InfiniteScroll/InfiniteScrollPlugin.php b/plugins/InfiniteScroll/InfiniteScrollPlugin.php index 77ad83a51b..a4d1a5d05c 100644 --- a/plugins/InfiniteScroll/InfiniteScrollPlugin.php +++ b/plugins/InfiniteScroll/InfiniteScrollPlugin.php @@ -40,8 +40,8 @@ class InfiniteScrollPlugin extends Plugin function onEndShowScripts($action) { - $action->script(common_path('plugins/InfiniteScroll/jquery.infinitescroll.js')); - $action->script(common_path('plugins/InfiniteScroll/infinitescroll.js')); + $action->script('plugins/InfiniteScroll/jquery.infinitescroll.js'); + $action->script('plugins/InfiniteScroll/infinitescroll.js'); } function onPluginVersion(&$versions) diff --git a/plugins/Minify/MinifyPlugin.php b/plugins/Minify/MinifyPlugin.php index fe1883ded4..69def60641 100644 --- a/plugins/Minify/MinifyPlugin.php +++ b/plugins/Minify/MinifyPlugin.php @@ -86,7 +86,11 @@ class MinifyPlugin extends Plugin $url = parse_url($src); if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) { - $src = $this->minifyUrl($src); + if (strpos($src, 'plugins/') === 0 || strpos($src, 'local/') === 0) { + $src = $this->minifyUrl($src); + } else { + $src = $this->minifyUrl('js/'.$src); + } } } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 3b1329d6c5..a30f68cb36 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -281,12 +281,12 @@ class OStatusPlugin extends Plugin } function onEndShowStatusNetStyles($action) { - $action->cssLink(common_path('plugins/OStatus/theme/base/css/ostatus.css')); + $action->cssLink('plugins/OStatus/theme/base/css/ostatus.css'); return true; } function onEndShowStatusNetScripts($action) { - $action->script(common_path('plugins/OStatus/js/ostatus.js')); + $action->script('plugins/OStatus/js/ostatus.js'); return true; } } diff --git a/plugins/Orbited/OrbitedPlugin.php b/plugins/Orbited/OrbitedPlugin.php index ba87b266a0..8af71af747 100644 --- a/plugins/Orbited/OrbitedPlugin.php +++ b/plugins/Orbited/OrbitedPlugin.php @@ -77,9 +77,9 @@ class OrbitedPlugin extends RealtimePlugin $root = 'http://'.$server.(($port == 80) ? '':':'.$port); $scripts[] = $root.'/static/Orbited.js'; - $scripts[] = common_path('plugins/Orbited/orbitedextra.js'); + $scripts[] = 'plugins/Orbited/orbitedextra.js'; $scripts[] = $root.'/static/protocols/stomp/stomp.js'; - $scripts[] = common_path('plugins/Orbited/orbitedupdater.js'); + $scripts[] = 'plugins/Orbited/orbitedupdater.js'; return $scripts; } diff --git a/plugins/Realtime/RealtimePlugin.php b/plugins/Realtime/RealtimePlugin.php index 6c212453e4..e8c44a743a 100644 --- a/plugins/Realtime/RealtimePlugin.php +++ b/plugins/Realtime/RealtimePlugin.php @@ -117,7 +117,7 @@ class RealtimePlugin extends Plugin function onEndShowStatusNetStyles($action) { - $action->cssLink(common_path('plugins/Realtime/realtimeupdate.css'), + $action->cssLink('plugins/Realtime/realtimeupdate.css', null, 'screen, projection, tv'); return true; } @@ -307,7 +307,7 @@ class RealtimePlugin extends Plugin function _getScripts() { - return array(common_path('plugins/Realtime/realtimeupdate.js')); + return array('plugins/Realtime/realtimeupdate.js'); } function _updateInitialize($timeline, $user_id) From 9f3246124dc9702ff3a7e422df4adff687e62f9c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 17 Feb 2010 09:58:34 -0800 Subject: [PATCH 019/190] PostDebug plugin - saves POST data to debug log or directory to help debug form submission and server-to-server communications. Some sensitive items are sanitized but not all - don't just shove out the log results publicly! --- plugins/PostDebug/PostDebugPlugin.php | 150 ++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 plugins/PostDebug/PostDebugPlugin.php diff --git a/plugins/PostDebug/PostDebugPlugin.php b/plugins/PostDebug/PostDebugPlugin.php new file mode 100644 index 0000000000..48fe28eabd --- /dev/null +++ b/plugins/PostDebug/PostDebugPlugin.php @@ -0,0 +1,150 @@ +. + * + * @category Sample + * @package StatusNet + * @author Brion Vibber + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class PostDebugPlugin extends Plugin +{ + /** + * Set to a directory to dump individual items instead of + * sending to the debug log + */ + public $dir=false; + + public function onArgsInitialize(&$args) + { + if (isset($_SERVER['REQUEST_METHOD']) && + $_SERVER['REQUEST_METHOD'] == 'POST') { + $this->doDebug(); + } + } + + public function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'PostDebug', + 'version' => STATUSNET_VERSION, + 'author' => 'Brion Vibber', + 'homepage' => 'http://status.net/wiki/Plugin:PostDebug', + 'rawdescription' => + _m('Debugging tool to record request details on POST.')); + return true; + } + + protected function doDebug() + { + $data = array('timestamp' => gmdate('r'), + 'remote_addr' => @$_SERVER['REMOTE_ADDR'], + 'url' => @$_SERVER['REQUEST_URI'], + 'have_session' => common_have_session(), + 'logged_in' => common_logged_in(), + 'is_real_login' => common_is_real_login(), + 'user' => common_logged_in() ? common_current_user()->nickname : null, + 'headers' => $this->getHttpHeaders(), + 'post_data' => $this->sanitizePostData($_POST)); + $this->saveDebug($data); + } + + protected function saveDebug($data) + { + $output = var_export($data, true); + if ($this->dir) { + $file = $this->dir . DIRECTORY_SEPARATOR . $this->logFileName(); + file_put_contents($file, $output); + } else { + common_log(LOG_DEBUG, "PostDebug: $output"); + } + } + + protected function logFileName() + { + $base = common_request_id(); + $base = preg_replace('/^(.+?) .*$/', '$1', $base); + $base = str_replace(':', '-', $base); + $base = rawurlencode($base); + return $base; + } + + protected function getHttpHeaders() + { + if (function_exists('getallheaders')) { + $headers = getallheaders(); + } else { + $headers = array(); + $prefix = 'HTTP_'; + $prefixLen = strlen($prefix); + foreach ($_SERVER as $key => $val) { + if (substr($key, 0, $prefixLen) == $prefix) { + $header = $this->normalizeHeader(substr($key, $prefixLen)); + $headers[$header] = $val; + } + } + } + foreach ($headers as $header => $val) { + if (strtolower($header) == 'cookie') { + $headers[$header] = $this->sanitizeCookies($val); + } + } + return $headers; + } + + protected function normalizeHeader($key) + { + return implode('-', + array_map('ucfirst', + explode("_", + strtolower($key)))); + } + + function sanitizeCookies($val) + { + $blacklist = array(session_name(), 'rememberme'); + foreach ($blacklist as $name) { + $val = preg_replace("/(^|;\s*)({$name}=)(.*?)(;|$)/", + "$1$2########$4", + $val); + } + return $val; + } + + function sanitizePostData($data) + { + $blacklist = array('password', 'confirm', 'token'); + foreach ($data as $key => $val) { + if (in_array($key, $blacklist)) { + $data[$key] = '########'; + } + } + return $data; + } + +} + From 8e07926a9c0736b5a3f408465dded92676ac1862 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 17 Feb 2010 12:02:59 -0500 Subject: [PATCH 020/190] parse_url returns an associative array - not an object --- lib/htmloutputter.php | 2 +- plugins/Minify/MinifyPlugin.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 317f5ea612..4a88337bc5 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -428,7 +428,7 @@ class HTMLOutputter extends XMLOutputter { if(Event::handle('StartCssLinkElement', array($this,&$src,&$theme,&$media))) { $url = parse_url($src); - if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment)) + if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) { if(file_exists(Theme::file($src,$theme))){ $src = Theme::path($src, $theme); diff --git a/plugins/Minify/MinifyPlugin.php b/plugins/Minify/MinifyPlugin.php index b49b6a4bad..fe1883ded4 100644 --- a/plugins/Minify/MinifyPlugin.php +++ b/plugins/Minify/MinifyPlugin.php @@ -96,7 +96,7 @@ class MinifyPlugin extends Plugin && is_null(common_config('theme', 'path')) && is_null(common_config('theme', 'server')); $url = parse_url($src); - if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment)) + if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) { if(!isset($theme)) { $theme = common_config('site', 'theme'); From e8275aa60abd381de9e95c29fd00819c81d3db79 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 17 Feb 2010 10:12:37 -0800 Subject: [PATCH 021/190] Fix exception on bad plugin load --- lib/statusnet.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/statusnet.php b/lib/statusnet.php index 9c7ede5a5d..257bd861da 100644 --- a/lib/statusnet.php +++ b/lib/statusnet.php @@ -63,7 +63,7 @@ class StatusNet } } if (!class_exists($pluginclass)) { - throw new ServerException(500, "Plugin $name not found."); + throw new ServerException("Plugin $name not found.", 500); } } From 6b887728b2c84fec39a576e6f2a76909b6318774 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 19:24:38 +0000 Subject: [PATCH 022/190] Better logging for Twitter bridge account linking process --- .../TwitterBridge/twitterauthorization.php | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index c154932bbc..8bfdacee91 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -131,8 +131,7 @@ class TwitterauthorizationAction extends Action } else if ($this->arg('connect')) { $this->connectNewUser(); } else { - common_debug('Twitter Connect Plugin - ' . - print_r($this->args, true)); + common_debug('Twitter bridge - ' . print_r($this->args, true)); $this->showForm(_('Something weird happened.'), $this->trimmed('newname')); } @@ -172,9 +171,15 @@ class TwitterauthorizationAction extends Action $auth_link = $client->getAuthorizeLink($req_tok, $this->signin); } catch (OAuthClientException $e) { - $msg = sprintf('OAuth client error - code: %1s, msg: %2s', - $e->getCode(), $e->getMessage()); - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $msg = sprintf( + 'OAuth client error - code: %1s, msg: %2s', + $e->getCode(), + $e->getMessage() + ); + common_log(LOG_INFO, 'Twitter bridge - ' . $msg); + $this->serverError( + _m('Couldn\'t link your Twitter account: ') . $e->getMessage() + ); } common_redirect($auth_link); @@ -192,7 +197,9 @@ class TwitterauthorizationAction extends Action // token we sent them if ($_SESSION['twitter_request_token'] != $this->oauth_token) { - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $this->serverError( + _m('Couldn\'t link your Twitter account: oauth_token mismatch.') + ); } $twitter_user = null; @@ -212,9 +219,15 @@ class TwitterauthorizationAction extends Action $twitter_user = $client->verifyCredentials(); } catch (OAuthClientException $e) { - $msg = sprintf('OAuth client error - code: %1$s, msg: %2$s', - $e->getCode(), $e->getMessage()); - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $msg = sprintf( + 'OAuth client error - code: %1$s, msg: %2$s', + $e->getCode(), + $e->getMessage() + ); + common_log(LOG_INFO, 'Twitter bridge - ' . $msg); + $this->serverError( + _m('Couldn\'t link your Twitter account: ') . $e-getMessage() + ); } if (common_logged_in()) { From 4d97f83740401ca98f4cd6d6d285dba0000d34dd Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 19:24:38 +0000 Subject: [PATCH 023/190] Better logging for Twitter bridge account linking process --- .../TwitterBridge/twitterauthorization.php | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index c154932bbc..8bfdacee91 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -131,8 +131,7 @@ class TwitterauthorizationAction extends Action } else if ($this->arg('connect')) { $this->connectNewUser(); } else { - common_debug('Twitter Connect Plugin - ' . - print_r($this->args, true)); + common_debug('Twitter bridge - ' . print_r($this->args, true)); $this->showForm(_('Something weird happened.'), $this->trimmed('newname')); } @@ -172,9 +171,15 @@ class TwitterauthorizationAction extends Action $auth_link = $client->getAuthorizeLink($req_tok, $this->signin); } catch (OAuthClientException $e) { - $msg = sprintf('OAuth client error - code: %1s, msg: %2s', - $e->getCode(), $e->getMessage()); - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $msg = sprintf( + 'OAuth client error - code: %1s, msg: %2s', + $e->getCode(), + $e->getMessage() + ); + common_log(LOG_INFO, 'Twitter bridge - ' . $msg); + $this->serverError( + _m('Couldn\'t link your Twitter account: ') . $e->getMessage() + ); } common_redirect($auth_link); @@ -192,7 +197,9 @@ class TwitterauthorizationAction extends Action // token we sent them if ($_SESSION['twitter_request_token'] != $this->oauth_token) { - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $this->serverError( + _m('Couldn\'t link your Twitter account: oauth_token mismatch.') + ); } $twitter_user = null; @@ -212,9 +219,15 @@ class TwitterauthorizationAction extends Action $twitter_user = $client->verifyCredentials(); } catch (OAuthClientException $e) { - $msg = sprintf('OAuth client error - code: %1$s, msg: %2$s', - $e->getCode(), $e->getMessage()); - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $msg = sprintf( + 'OAuth client error - code: %1$s, msg: %2$s', + $e->getCode(), + $e->getMessage() + ); + common_log(LOG_INFO, 'Twitter bridge - ' . $msg); + $this->serverError( + _m('Couldn\'t link your Twitter account: ') . $e-getMessage() + ); } if (common_logged_in()) { From c498f6e1ba50d8c17cd1d8698f05f7604d5cfcf8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 20:53:16 +0000 Subject: [PATCH 024/190] Twitter bridge - fix for Ticket #2192 --- plugins/TwitterBridge/twitter.php | 14 +++++++++----- plugins/TwitterBridge/twitterauthorization.php | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index e5afde62ca..ceb83b037f 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -1,7 +1,7 @@ delete(); - if ($result != false) { - common_log(LOG_INFO, - "Twitter bridge - removed old Twitter user: $screen_name ($twitter_id)."); + if (!empty($luser)) { + $result = $luser->delete(); + if ($result != false) { + common_log( + LOG_INFO, + "Twitter bridge - removed old Twitter user: $screen_name ($twitter_id)." + ); + } } $fuser = new Foreign_user(); diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index 8bfdacee91..cabf69d7a8 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -178,7 +178,7 @@ class TwitterauthorizationAction extends Action ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); $this->serverError( - _m('Couldn\'t link your Twitter account: ') . $e->getMessage() + _m('Couldn\'t link your Twitter account.') ); } @@ -226,7 +226,7 @@ class TwitterauthorizationAction extends Action ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); $this->serverError( - _m('Couldn\'t link your Twitter account: ') . $e-getMessage() + _m('Couldn\'t link your Twitter account.') ); } @@ -292,7 +292,7 @@ class TwitterauthorizationAction extends Action if (empty($flink_id)) { common_log_db_error($flink, 'INSERT', __FILE__); - $this->serverError(_('Couldn\'t link your Twitter account.')); + $this->serverError(_('Couldn\'t link your Twitter account.')); } return $flink_id; From a80fdf3142d05bdae77874acc7413cbbd70fad3d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 20:53:16 +0000 Subject: [PATCH 025/190] Twitter bridge - fix for Ticket #2192 --- plugins/TwitterBridge/twitter.php | 12 ++++++++---- plugins/TwitterBridge/twitterauthorization.php | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 2dd815d3ce..13e499d65e 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -33,11 +33,15 @@ function add_twitter_user($twitter_id, $screen_name) // repoed, and things like that. $luser = Foreign_user::getForeignUser($twitter_id, TWITTER_SERVICE); - $result = $luser->delete(); - if ($result != false) { - common_log(LOG_INFO, - "Twitter bridge - removed old Twitter user: $screen_name ($twitter_id)."); + if (!empty($luser)) { + $result = $luser->delete(); + if ($result != false) { + common_log( + LOG_INFO, + "Twitter bridge - removed old Twitter user: $screen_name ($twitter_id)." + ); + } } $fuser = new Foreign_user(); diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index 8bfdacee91..cabf69d7a8 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -178,7 +178,7 @@ class TwitterauthorizationAction extends Action ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); $this->serverError( - _m('Couldn\'t link your Twitter account: ') . $e->getMessage() + _m('Couldn\'t link your Twitter account.') ); } @@ -226,7 +226,7 @@ class TwitterauthorizationAction extends Action ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); $this->serverError( - _m('Couldn\'t link your Twitter account: ') . $e-getMessage() + _m('Couldn\'t link your Twitter account.') ); } @@ -292,7 +292,7 @@ class TwitterauthorizationAction extends Action if (empty($flink_id)) { common_log_db_error($flink, 'INSERT', __FILE__); - $this->serverError(_('Couldn\'t link your Twitter account.')); + $this->serverError(_('Couldn\'t link your Twitter account.')); } return $flink_id; From c201baffbfbf812ecba504e6829dd9e9d17a4bac Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Feb 2010 06:12:08 +0000 Subject: [PATCH 026/190] Upgrade Twitter bridge to use OAuth 1.0a. It's more secure, and allows us to automatically send in a callback url instead of having to manually configure one for each StatusNet instance. --- lib/oauthclient.php | 88 ++++++++++++++----- .../TwitterBridge/twitterauthorization.php | 10 +-- plugins/TwitterBridge/twitteroauthclient.php | 28 ++++++ 3 files changed, 98 insertions(+), 28 deletions(-) diff --git a/lib/oauthclient.php b/lib/oauthclient.php index b22fd78974..bc7587183b 100644 --- a/lib/oauthclient.php +++ b/lib/oauthclient.php @@ -90,20 +90,47 @@ class OAuthClient /** * Gets a request token from the given url * - * @param string $url OAuth endpoint for grabbing request tokens + * @param string $url OAuth endpoint for grabbing request tokens + * @param string $callback authorized request token callback * * @return OAuthToken $token the request token */ - function getRequestToken($url) + function getRequestToken($url, $callback = null) { - $response = $this->oAuthGet($url); + $params = null; + + if (!is_null($callback)) { + $params['oauth_callback'] = $callback; + } + + $response = $this->oAuthGet($url, $params); + $arr = array(); parse_str($response, $arr); - if (isset($arr['oauth_token']) && isset($arr['oauth_token_secret'])) { - $token = new OAuthToken($arr['oauth_token'], @$arr['oauth_token_secret']); + + $token = $arr['oauth_token']; + $secret = $arr['oauth_token_secret']; + $confirm = $arr['oauth_callback_confirmed']; + + if (isset($token) && isset($secret)) { + + $token = new OAuthToken($token, $secret); + + if (isset($confirm)) { + if ($confirm == 'true') { + common_debug('Twitter bridge - callback confirmed.'); + return $token; + } else { + throw new OAuthClientException( + 'Callback was not confirmed by Twitter.' + ); + } + } return $token; } else { - throw new OAuthClientException(); + throw new OAuthClientException( + 'Could not get a request token from Twitter.' + ); } } @@ -113,49 +140,64 @@ class OAuthClient * * @param string $url endpoint for authorizing request tokens * @param OAuthToken $request_token the request token to be authorized - * @param string $oauth_callback optional callback url * * @return string $authorize_url the url to redirect to */ - function getAuthorizeLink($url, $request_token, $oauth_callback = null) + function getAuthorizeLink($url, $request_token) { $authorize_url = $url . '?oauth_token=' . $request_token->key; - if (isset($oauth_callback)) { - $authorize_url .= '&oauth_callback=' . urlencode($oauth_callback); - } - return $authorize_url; } /** * Fetches an access token * - * @param string $url OAuth endpoint for exchanging authorized request tokens - * for access tokens + * @param string $url OAuth endpoint for exchanging authorized request tokens + * for access tokens + * @param string $verifier 1.0a verifier * * @return OAuthToken $token the access token */ - function getAccessToken($url) + function getAccessToken($url, $verifier = null) { - $response = $this->oAuthPost($url); - parse_str($response); - $token = new OAuthToken($oauth_token, $oauth_token_secret); - return $token; + $params = array(); + + if (!is_null($verifier)) { + $params['oauth_verifier'] = $verifier; + } + + $response = $this->oAuthPost($url, $params); + + $arr = array(); + parse_str($response, $arr); + + $token = $arr['oauth_token']; + $secret = $arr['oauth_token_secret']; + + if (isset($token) && isset($secret)) { + $token = new OAuthToken($token, $secret); + return $token; + } else { + throw new OAuthClientException( + 'Could not get a access token from Twitter.' + ); + } } /** - * Use HTTP GET to make a signed OAuth request + * Use HTTP GET to make a signed OAuth requesta * - * @param string $url OAuth endpoint + * @param string $url OAuth request token endpoint + * @param array $params additional parameters * * @return mixed the request */ - function oAuthGet($url) + function oAuthGet($url, $params = null) { $request = OAuthRequest::from_consumer_and_token($this->consumer, - $this->token, 'GET', $url, null); + $this->token, 'GET', $url, $params); $request->sign_request($this->sha1_method, $this->consumer, $this->token); diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index 6822d33dd1..c154932bbc 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -56,6 +56,7 @@ class TwitterauthorizationAction extends Action var $tw_fields = null; var $access_token = null; var $signin = null; + var $verifier = null; /** * Initialize class members. Looks for 'oauth_token' parameter. @@ -70,6 +71,7 @@ class TwitterauthorizationAction extends Action $this->signin = $this->boolean('signin'); $this->oauth_token = $this->arg('oauth_token'); + $this->verifier = $this->arg('oauth_verifier'); return true; } @@ -160,8 +162,7 @@ class TwitterauthorizationAction extends Action // Get a new request token and authorize it $client = new TwitterOAuthClient(); - $req_tok = - $client->getRequestToken(TwitterOAuthClient::$requestTokenURL); + $req_tok = $client->getRequestToken(); // Sock the request token away in the session temporarily @@ -171,7 +172,7 @@ class TwitterauthorizationAction extends Action $auth_link = $client->getAuthorizeLink($req_tok, $this->signin); } catch (OAuthClientException $e) { - $msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s', + $msg = sprintf('OAuth client error - code: %1s, msg: %2s', $e->getCode(), $e->getMessage()); $this->serverError(_m('Couldn\'t link your Twitter account.')); } @@ -187,7 +188,6 @@ class TwitterauthorizationAction extends Action */ function saveAccessToken() { - // Check to make sure Twitter returned the same request // token we sent them @@ -204,7 +204,7 @@ class TwitterauthorizationAction extends Action // Exchange the request token for an access token - $atok = $client->getAccessToken(TwitterOAuthClient::$accessTokenURL); + $atok = $client->getAccessToken($this->verifier); // Test the access token and get the user's Twitter info diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index 277e7ab409..ba45b533dc 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -91,6 +91,19 @@ class TwitterOAuthClient extends OAuthClient } } + /** + * Gets a request token from Twitter + * + * @return OAuthToken $token the request token + */ + function getRequestToken() + { + return parent::getRequestToken( + self::$requestTokenURL, + common_local_url('twitterauthorization') + ); + } + /** * Builds a link to Twitter's endpoint for authorizing a request token * @@ -107,6 +120,21 @@ class TwitterOAuthClient extends OAuthClient common_local_url('twitterauthorization')); } + /** + * Fetches an access token from Twitter + * + * @param string $verifier 1.0a verifier + * + * @return OAuthToken $token the access token + */ + function getAccessToken($verifier = null) + { + return parent::getAccessToken( + self::$accessTokenURL, + $verifier + ); + } + /** * Calls Twitter's /account/verify_credentials API method * From 05c50499c31b80d2a1c41e5256fae96cc06252ad Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 19:24:38 +0000 Subject: [PATCH 027/190] Better logging for Twitter bridge account linking process --- .../TwitterBridge/twitterauthorization.php | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index c154932bbc..8bfdacee91 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -131,8 +131,7 @@ class TwitterauthorizationAction extends Action } else if ($this->arg('connect')) { $this->connectNewUser(); } else { - common_debug('Twitter Connect Plugin - ' . - print_r($this->args, true)); + common_debug('Twitter bridge - ' . print_r($this->args, true)); $this->showForm(_('Something weird happened.'), $this->trimmed('newname')); } @@ -172,9 +171,15 @@ class TwitterauthorizationAction extends Action $auth_link = $client->getAuthorizeLink($req_tok, $this->signin); } catch (OAuthClientException $e) { - $msg = sprintf('OAuth client error - code: %1s, msg: %2s', - $e->getCode(), $e->getMessage()); - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $msg = sprintf( + 'OAuth client error - code: %1s, msg: %2s', + $e->getCode(), + $e->getMessage() + ); + common_log(LOG_INFO, 'Twitter bridge - ' . $msg); + $this->serverError( + _m('Couldn\'t link your Twitter account: ') . $e->getMessage() + ); } common_redirect($auth_link); @@ -192,7 +197,9 @@ class TwitterauthorizationAction extends Action // token we sent them if ($_SESSION['twitter_request_token'] != $this->oauth_token) { - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $this->serverError( + _m('Couldn\'t link your Twitter account: oauth_token mismatch.') + ); } $twitter_user = null; @@ -212,9 +219,15 @@ class TwitterauthorizationAction extends Action $twitter_user = $client->verifyCredentials(); } catch (OAuthClientException $e) { - $msg = sprintf('OAuth client error - code: %1$s, msg: %2$s', - $e->getCode(), $e->getMessage()); - $this->serverError(_m('Couldn\'t link your Twitter account.')); + $msg = sprintf( + 'OAuth client error - code: %1$s, msg: %2$s', + $e->getCode(), + $e->getMessage() + ); + common_log(LOG_INFO, 'Twitter bridge - ' . $msg); + $this->serverError( + _m('Couldn\'t link your Twitter account: ') . $e-getMessage() + ); } if (common_logged_in()) { From 73ba26efe3d9d97c478a507d351ac92d28d82655 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Feb 2010 20:53:16 +0000 Subject: [PATCH 028/190] Twitter bridge - fix for Ticket #2192 --- plugins/TwitterBridge/twitter.php | 14 +++++++++----- plugins/TwitterBridge/twitterauthorization.php | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index e5afde62ca..ceb83b037f 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -1,7 +1,7 @@ delete(); - if ($result != false) { - common_log(LOG_INFO, - "Twitter bridge - removed old Twitter user: $screen_name ($twitter_id)."); + if (!empty($luser)) { + $result = $luser->delete(); + if ($result != false) { + common_log( + LOG_INFO, + "Twitter bridge - removed old Twitter user: $screen_name ($twitter_id)." + ); + } } $fuser = new Foreign_user(); diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index 8bfdacee91..cabf69d7a8 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -178,7 +178,7 @@ class TwitterauthorizationAction extends Action ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); $this->serverError( - _m('Couldn\'t link your Twitter account: ') . $e->getMessage() + _m('Couldn\'t link your Twitter account.') ); } @@ -226,7 +226,7 @@ class TwitterauthorizationAction extends Action ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); $this->serverError( - _m('Couldn\'t link your Twitter account: ') . $e-getMessage() + _m('Couldn\'t link your Twitter account.') ); } @@ -292,7 +292,7 @@ class TwitterauthorizationAction extends Action if (empty($flink_id)) { common_log_db_error($flink, 'INSERT', __FILE__); - $this->serverError(_('Couldn\'t link your Twitter account.')); + $this->serverError(_('Couldn\'t link your Twitter account.')); } return $flink_id; From ce6be4f83624d8c39a93d2b54567cc2f33580812 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 17 Feb 2010 16:49:00 -0800 Subject: [PATCH 029/190] Queues: redid the breakout control model so we can start up and subscribe to queues without running through the complete site list, which is ok at 1k sites but too slow at 10k. All breakout queues that we're going to need to listen to now need to be explicitly listed in $config['queue']['breakout']. Until XMPP is moved to component model, this setting will let the individual processes work with their own queues: $config['queue']['breakout'][] = 'xmpp/xmppout/' . $config['site']['nickname']; --- lib/default.php | 11 ++-- lib/iomaster.php | 23 +++----- lib/stompqueuemanager.php | 117 ++++++++++++++++++++------------------ scripts/queuedaemon.php | 3 +- 4 files changed, 76 insertions(+), 78 deletions(-) diff --git a/lib/default.php b/lib/default.php index a74cccae12..c969c3b337 100644 --- a/lib/default.php +++ b/lib/default.php @@ -91,10 +91,13 @@ $default = 'spawndelay' => 1, // Wait at least N seconds between (re)spawns of child processes to avoid slamming the queue server with subscription startup 'debug_memory' => false, // true to spit memory usage to log 'inboxes' => true, // true to do inbox distribution & output queueing from in background via 'distrib' queue - 'breakout' => array('*' => 'shared'), // set global or per-handler queue breakout - // 'shared': use a shared queue for all sites - // 'handler': share each/this handler over multiple sites - // 'site': break out for each/this handler on this site + 'breakout' => array(), // List queue specifiers to break out when using Stomp queue. + // Default will share all queues for all sites within each group. + // Specify as / or //, + // using nickname identifier as site. + // + // 'main/distrib' separate "distrib" queue covering all sites + // 'xmpp/xmppout/mysite' separate "xmppout" queue covering just 'mysite' 'max_retries' => 10, // drop messages after N failed attempts to process (Stomp) 'dead_letter_dir' => false, // set to directory to save dropped messages into (Stomp) ), diff --git a/lib/iomaster.php b/lib/iomaster.php index 54e2dfe841..d20837ba54 100644 --- a/lib/iomaster.php +++ b/lib/iomaster.php @@ -55,27 +55,18 @@ abstract class IoMaster if ($multiSite !== null) { $this->multiSite = $multiSite; } - if ($this->multiSite) { - $this->sites = StatusNet::findAllSites(); - } else { - $this->sites = array(StatusNet::currentSite()); - } - if (empty($this->sites)) { - throw new Exception("Empty status_network table, cannot init"); - } - - foreach ($this->sites as $site) { - StatusNet::switchSite($site); - $this->initManagers(); - } + $this->initManagers(); } /** - * Initialize IoManagers for the currently configured site - * which are appropriate to this instance. + * Initialize IoManagers which are appropriate to this instance; + * pass class names or instances into $this->instantiate(). * - * Pass class names into $this->instantiate() + * If setup and configuration may vary between sites in multi-site + * mode, it's the subclass's responsibility to set them up here. + * + * Switching site configurations is an acceptable side effect. */ abstract function initManagers(); diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php index bfeeb23b7f..9af8b2f482 100644 --- a/lib/stompqueuemanager.php +++ b/lib/stompqueuemanager.php @@ -63,7 +63,7 @@ class StompQueueManager extends QueueManager $this->password = common_config('queue', 'stomp_password'); $this->base = common_config('queue', 'queue_basename'); $this->control = common_config('queue', 'control_channel'); - $this->subscriptions = array($this->control => $this->control); + $this->breakout = common_config('queue', 'breakout'); } /** @@ -75,28 +75,6 @@ class StompQueueManager extends QueueManager return IoManager::INSTANCE_PER_PROCESS; } - /** - * Record queue subscriptions we'll need to handle the current site. - */ - public function addSite() - { - $this->sites[] = StatusNet::currentSite(); - - // Set up handlers active for this site... - $this->initialize(); - - foreach ($this->activeGroups as $group) { - if (isset($this->groups[$group])) { - // Actual queues may be broken out or consolidated... - // Subscribe to all the target queues we'll need. - foreach ($this->groups[$group] as $transport => $class) { - $target = $this->queueName($transport); - $this->subscriptions[$target] = $target; - } - } - } - } - /** * Optional; ping any running queue handler daemons with a notification * such as announcing a new site to handle or requesting clean shutdown. @@ -166,14 +144,15 @@ class StompQueueManager extends QueueManager $con = $this->cons[$idx]; $host = $con->getServer(); - $result = $con->send($this->queueName($queue), $msg, $props); + $target = $this->queueName($queue); + $result = $con->send($target, $msg, $props); if (!$result) { - $this->_log(LOG_ERR, "Error sending $rep to $queue queue on $host"); + $this->_log(LOG_ERR, "Error sending $rep to $queue queue on $host $target"); return false; } - $this->_log(LOG_DEBUG, "complete remote queueing $rep for $queue on $host"); + $this->_log(LOG_DEBUG, "complete remote queueing $rep for $queue on $host $target"); $this->stats('enqueued', $queue); return true; } @@ -432,11 +411,42 @@ class StompQueueManager extends QueueManager protected function doSubscribe(LiberalStomp $con) { $host = $con->getServer(); - foreach ($this->subscriptions as $queue) { - $this->_log(LOG_INFO, "Subscribing to $queue on $host"); - $con->subscribe($queue); + foreach ($this->subscriptions() as $sub) { + $this->_log(LOG_INFO, "Subscribing to $sub on $host"); + $con->subscribe($sub); } } + + /** + * Grab a full list of stomp-side queue subscriptions. + * Will include: + * - control broadcast channel + * - shared group queues for active groups + * - per-handler and per-site breakouts from $config['queue']['breakout'] + * that are rooted in the active groups. + * + * @return array of strings + */ + protected function subscriptions() + { + $subs = array(); + $subs[] = $this->control; + + foreach ($this->activeGroups as $group) { + $subs[] = $this->base . $group; + } + + foreach ($this->breakout as $spec) { + $parts = explode('/', $spec); + if (count($parts) < 2 || count($parts) > 3) { + common_log(LOG_ERR, "Bad queue breakout specifier $spec"); + } + if (in_array($parts[0], $this->activeGroups)) { + $subs[] = $this->base . $spec; + } + } + return array_unique($subs); + } /** * Handle and acknowledge an event that's come in through a queue. @@ -612,32 +622,26 @@ class StompQueueManager extends QueueManager } /** - * Set us up with queue subscriptions for a new site added at runtime, + * (Re)load runtime configuration for a given site by nickname, * triggered by a broadcast to the 'statusnet-control' topic. * + * Configuration changes in database should update, but config + * files might not. + * * @param array $frame Stomp frame * @return bool true to continue; false to stop further processing. */ protected function updateSiteConfig($nickname) { - if (empty($this->sites)) { - if ($nickname == common_config('site', 'nickname')) { - StatusNet::init(common_config('site', 'server')); - } else { - $this->_log(LOG_INFO, "Ignoring update ping for other site $nickname"); + $sn = Status_network::staticGet($nickname); + if ($sn) { + $this->switchSite($nickname); + if (!in_array($nickname, $this->sites)) { + $this->addSite(); } + $this->stats('siteupdate'); } else { - $sn = Status_network::staticGet($nickname); - if ($sn) { - $this->switchSite($nickname); - if (!in_array($nickname, $this->sites)) { - $this->addSite(); - } - // @fixme update subscriptions, if applicable - $this->stats('siteupdate'); - } else { - $this->_log(LOG_ERR, "Ignoring ping for unrecognized new site $nickname"); - } + $this->_log(LOG_ERR, "Ignoring ping for unrecognized new site $nickname"); } } @@ -646,24 +650,25 @@ class StompQueueManager extends QueueManager * group name for this queue to give eg: * * /queue/statusnet/main + * /queue/statusnet/main/distrib + * /queue/statusnet/xmpp/xmppout/site01 * * @param string $queue * @return string */ protected function queueName($queue) { - $base = common_config('queue', 'queue_basename'); $group = $this->queueGroup($queue); - $breakout = $this->breakoutMode($queue); - if ($breakout == 'shared') { - return $base . "$group"; - } else if ($breakout == 'handler') { - return $base . "$group/$queue"; - } else if ($breakout == 'site') { - $site = StatusNet::currentSite(); - return $base . "$group/$queue/$site"; + $site = StatusNet::currentSite(); + + $specs = array("$group/$queue/$site", + "$group/$queue"); + foreach ($specs as $spec) { + if (in_array($spec, $this->breakout)) { + return $this->base . $spec; + } } - throw Exception("Unrecognized queue breakout mode '$breakout' for '$queue'"); + return $this->base . $group; } /** diff --git a/scripts/queuedaemon.php b/scripts/queuedaemon.php index d372d898fa..6dba16f953 100755 --- a/scripts/queuedaemon.php +++ b/scripts/queuedaemon.php @@ -126,8 +126,7 @@ class QueueDaemon extends SpawningDaemon class QueueMaster extends IoMaster { /** - * Initialize IoManagers for the currently configured site - * which are appropriate to this instance. + * Initialize IoManagers which are appropriate to this instance. */ function initManagers() { From 1aeca3947d7c938b9d14334d74f0fecd57a4eaf5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Feb 2010 01:47:44 +0000 Subject: [PATCH 030/190] Fix for cross site OMB posting problem --- lib/omb.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/omb.php b/lib/omb.php index 0f38a49369..17132a594f 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -29,11 +29,9 @@ require_once 'Auth/Yadis/Yadis.php'; function omb_oauth_consumer() { - static $con = null; - if (is_null($con)) { - $con = new OAuthConsumer(common_root_url(), ''); - } - return $con; + // Don't try to make this static. Leads to issues in + // multi-site setups - Z + return new OAuthConsumer(common_root_url(), ''); } function omb_oauth_server() From 5e60bf2ca65f5e862fa1741e42d35e2ae7bb5559 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Feb 2010 01:47:44 +0000 Subject: [PATCH 031/190] Fix for cross site OMB posting problem --- lib/omb.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/omb.php b/lib/omb.php index 0f38a49369..17132a594f 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -29,11 +29,9 @@ require_once 'Auth/Yadis/Yadis.php'; function omb_oauth_consumer() { - static $con = null; - if (is_null($con)) { - $con = new OAuthConsumer(common_root_url(), ''); - } - return $con; + // Don't try to make this static. Leads to issues in + // multi-site setups - Z + return new OAuthConsumer(common_root_url(), ''); } function omb_oauth_server() From 80ef3946d016eeeef1682e73eddffb222d8db149 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Feb 2010 06:36:32 -0500 Subject: [PATCH 032/190] more work on salmon --- plugins/OStatus/actions/salmon.php | 140 +++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 7 deletions(-) diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index c79d09c95a..9ca0198266 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -62,20 +62,146 @@ class SalmonAction extends Action // XXX: check the signature $this->act = new Activity($dom->documentElement); + + return true; } function handle($args) { - common_log(LOG_DEBUG, 'Salmon: incoming post for user: '. $user_id); + common_log(LOG_INFO, 'Salmon: incoming post for user '. $this->user->id); // TODO : Insert new $xml -> notice code - switch ($this->act->verb) - { - case Activity::POST: - case Activity::SHARE: - case Activity::FAVORITE: - case Activity::FOLLOW: + if (Event::handle('StartHandleSalmon', array($this->user, $this->activity))) { + switch ($this->act->verb) + { + case ActivityVerb::POST: + $this->handlePost(); + break; + case ActivityVerb::SHARE: + $this->handleShare(); + break; + case ActivityVerb::FAVORITE: + $this->handleFavorite(); + break; + case ActivityVerb::FOLLOW: + case ActivityVerb::FRIEND: + $this->handleFollow(); + break; + } + Event::handle('EndHandleSalmon', array($this->user, $this->activity)); + } + } + + function handlePost() + { + switch ($this->act->object->type) { + case ActivityObject::ARTICLE: + case ActivityObject::BLOGENTRY: + case ActivityObject::NOTE: + case ActivityObject::STATUS: + case ActivityObject::COMMENT: + break; + default: + throw new Exception("Can't handle that kind of post."); + } + + $profile = $this->ensureProfile(); + } + + function handleFollow() + { + } + + function handleFavorite() + { + } + + function handleShare() + { + } + + function ensureProfile() + { + $actor = $this->act->actor; + + if (empty($actor->id)) { + throw new Exception("Received a salmon slap from unidentified actor."); + } + + $ostatusProfile = Ostatus_profile::staticGet('homeuri', $actor->id); + + if (empty($ostatusProfile)) { + return $this->createProfile(); + } else { + // XXX: can we receive a salmon slap from a group...? + assert(!empty($ostatusProfile->profile_id)); + return Profile::staticGet($ostatusProfile->profile_id); + } + } + + function createProfile() + { + $actor = $this->act->actor; + + $profile = new Profile(); + + $profile->nickname = $this->nicknameFromURI($actor->id); + + if (empty($profile->nickname)) { + $profile->nickname = common_nicknamize($actor->title); + } + + $profile->fullname = $actor->title; + $profile->bio = $actor->summary; // XXX: is that right? + $profile->profileurl = $actor->link; // XXX: is that right? + $profile->created = common_sql_now(); + + $id = $profile->insert(); + + if (empty($id)) { + common_log_db_error($profile, 'INSERT', __FILE__); + throw new Exception("Couldn't save new profile for $actor->id\n"); + } + + // XXX: add avatars + + $op = new Ostatus_profile(); + + $op->profile_id = $id; + $op->homeuri = $actor->id; + $op->created = $profile->created; + + // XXX: determine feed URI from source or Webfinger or whatever + + $id = $op->insert(); + + if (empty($id)) { + common_log_db_error($op, 'INSERT', __FILE__); + throw new Exception("Couldn't save new ostatus profile for $actor->id\n"); + } + + return $profile; + } + + function nicknameFromURI($uri) + { + preg_match('/(\w+):/', $uri, $matches); + + $protocol = $matches[1]; + + switch ($protocol) { + case 'acct': + case 'mailto': + if (preg_match("/^$protocol:(.*)?@.*\$/", $uri, $matches)) { + return common_canonical_nickname($matches[1]); + } + return null; + case 'http': + return common_url_to_nickname($uri); + break; + default: + return null; } } } From c2ba7645359242590c8ac60b66f012110ae889ef Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Feb 2010 07:11:20 -0500 Subject: [PATCH 033/190] always distribute to inbox of author immediately --- classes/Notice.php | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index b0edb6de60..7e2b8b4a69 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -681,7 +681,20 @@ class Notice extends Memcached_DataObject { $ni = $this->whoGets($groups, $recipients); - Inbox::bulkInsert($this->id, array_keys($ni)); + $ids = array_keys($ni); + + // We remove the author (if they're a local user), + // since we'll have already done this in distribute() + + $i = array_search($this->profile_id, $ids); + + if ($i !== false) { + unset($ids[$i]); + } + + // Bulk insert + + Inbox::bulkInsert($this->id, $ids); return; } @@ -1487,6 +1500,14 @@ class Notice extends Memcached_DataObject function distribute() { + // We always insert for the author so they don't + // have to wait + + $user = User::staticGet('id', $this->profile_id); + if (!empty($user)) { + Inbox::insertNotice($user->id, $this->id); + } + if (common_config('queue', 'inboxes')) { // If there's a failure, we want to _force_ // distribution at this point. From c36155e2381df5bc00a3f89e6e35768fb822960a Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Feb 2010 18:12:08 +0100 Subject: [PATCH 034/190] Fixes long strings from not breaking --- theme/base/css/display.css | 1 + 1 file changed, 1 insertion(+) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 89fe810c69..380975e324 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -1035,6 +1035,7 @@ text-decoration:underline; .notice .entry-title { overflow:hidden; +word-wrap:break-word; } .notice .entry-title.ov { overflow:visible; From 310ac319957d437ab3bc0619419c750c98ebeaf0 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Feb 2010 18:12:47 +0100 Subject: [PATCH 035/190] Minor adjustment to edit icon position --- theme/default/css/display.css | 2 +- theme/identica/css/display.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/theme/default/css/display.css b/theme/default/css/display.css index a2f1013428..71470d55d2 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -306,7 +306,7 @@ background-position:5px -1181px; } .entity_edit a { -background-position: 5px -718px; +background-position: 5px -719px; } .entity_send-a-message a { background-position: 5px -852px; diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index e214047451..14a82a8def 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -305,7 +305,7 @@ background-position:5px -1181px; } .entity_edit a { -background-position: 5px -718px; +background-position: 5px -719px; } .entity_send-a-message a { background-position: 5px -852px; From 22ff358ba8d1fd0396136e1de570d788dd0727b6 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 18 Feb 2010 18:20:48 +0000 Subject: [PATCH 036/190] OStatus sub/unsub updates: - fix for PuSH unsub verification - send Salmon notification on unsub --- lib/atom10entry.php | 5 +- lib/atom10feed.php | 11 +++- lib/atomnoticefeed.php | 8 +-- plugins/OStatus/OStatusPlugin.php | 55 +++++++++++++++++-- plugins/OStatus/actions/pushcallback.php | 2 +- plugins/OStatus/actions/pushhub.php | 9 ++- plugins/OStatus/actions/salmon.php | 2 + plugins/OStatus/classes/HubSub.php | 11 ++-- plugins/OStatus/classes/Ostatus_profile.php | 44 ++++++++------- plugins/OStatus/lib/activity.php | 6 ++ plugins/OStatus/lib/hubverifyqueuehandler.php | 3 +- 11 files changed, 108 insertions(+), 48 deletions(-) diff --git a/lib/atom10entry.php b/lib/atom10entry.php index 5710c80fc5..f8f16d5946 100644 --- a/lib/atom10entry.php +++ b/lib/atom10entry.php @@ -27,8 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') -{ +if (!defined('STATUSNET')) { exit(1); } @@ -87,7 +86,7 @@ class Atom10Entry extends XMLStringer * * @return void */ - function validate + function validate() { } diff --git a/lib/atom10feed.php b/lib/atom10feed.php index 14a3beb83e..5e17b20d3a 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -78,7 +78,7 @@ class Atom10Feed extends XMLStringer $this->authors = array(); $this->links = array(); $this->entries = array(); - $this->addNamespace('xmlns', 'http://www.w3.org/2005/Atom'); + $this->addNamespace('', 'http://www.w3.org/2005/Atom'); } /** @@ -162,7 +162,14 @@ class Atom10Feed extends XMLStringer { $this->xw->startDocument('1.0', 'UTF-8'); $commonAttrs = array('xml:lang' => 'en-US'); - $commonAttrs = array_merge($commonAttrs, $this->namespaces); + foreach ($this->namespaces as $prefix => $uri) { + if ($prefix == '') { + $attr = 'xmlns'; + } else { + $attr = 'xmlns:' . $prefix; + } + $commonAttrs[$attr] = $uri; + } $this->elementStart('feed', $commonAttrs); $this->element('id', null, $this->id); diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index b7a60bde6e..7653f91544 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -50,23 +50,23 @@ class AtomNoticeFeed extends Atom10Feed // Feeds containing notice info use these namespaces $this->addNamespace( - 'xmlns:thr', + 'thr', 'http://purl.org/syndication/thread/1.0' ); $this->addNamespace( - 'xmlns:georss', + 'georss', 'http://www.georss.org/georss' ); $this->addNamespace( - 'xmlns:activity', + 'activity', 'http://activitystrea.ms/spec/1.0/' ); // XXX: What should the uri be? $this->addNamespace( - 'xmlns:ostatus', + 'ostatus', 'http://ostatus.org/schema/1.0' ); } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index b6c9fa1d4c..e548a151c7 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -112,7 +112,7 @@ class OStatusPlugin extends Plugin * Set up a PuSH hub link to our internal link for canonical timeline * Atom feeds for users and groups. */ - function onStartApiAtom(AtomNoticeFeed $feed) + function onStartApiAtom($feed) { $id = null; @@ -171,6 +171,12 @@ class OStatusPlugin extends Plugin { $base = dirname(__FILE__); $lower = strtolower($cls); + $map = array('activityverb' => 'activity', + 'activityobject' => 'activity', + 'activityutils' => 'activity'); + if (isset($map[$lower])) { + $lower = $map[$lower]; + } $files = array("$base/classes/$cls.php", "$base/lib/$lower.php"); if (substr($lower, -6) == 'action') { @@ -253,18 +259,45 @@ class OStatusPlugin extends Plugin } /** - * Garbage collect unused feeds on unsubscribe + * Notify remote server when one of our users subscribes. + * @fixme Check and restart the PuSH subscription if needed + * + * @param User $user + * @param Profile $other + * @return hook return value + */ + function onEndSubscribe($user, $other) + { + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + if ($oprofile) { + // Notify the remote server of the unsub, if supported. + $oprofile->notify($user->getProfile(), ActivityVerb::FOLLOW, $oprofile); + } + return true; + } + + /** + * Notify remote server and garbage collect unused feeds on unsubscribe. + * @fixme send these operations to background queues + * + * @param User $user + * @param Profile $other + * @return hook return value */ function onEndUnsubscribe($user, $other) { - $profile = Ostatus_profile::staticGet('profile_id', $other->id); - if ($feed) { + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + if ($oprofile) { + // Notify the remote server of the unsub, if supported. + $oprofile->notify($user->getProfile(), ActivityVerb::UNFOLLOW, $oprofile); + + // Drop the PuSH subscription if there are no other subscribers. $sub = new Subscription(); $sub->subscribed = $other->id; $sub->limit(1); if (!$sub->find(true)) { - common_log(LOG_INFO, "Unsubscribing from now-unused feed $feed->feeduri on hub $feed->huburi"); - $profile->unsubscribe(); + common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri on hub $oprofile->huburi"); + $oprofile->unsubscribe(); } } return true; @@ -290,6 +323,16 @@ class OStatusPlugin extends Plugin return true; } + /** + * Override the "from ostatus" bit in notice lists to link to the + * original post and show the domain it came from. + * + * @param Notice in $notice + * @param string out &$name + * @param string out &$url + * @param string out &$title + * @return mixed hook return code + */ function onStartNoticeSourceLink($notice, &$name, &$url, &$title) { if ($notice->source == 'ostatus') { diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index 388c8f9c3d..ed859a32f8 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -89,7 +89,7 @@ class PushCallbackAction extends Action if ($profile->verify_token !== $verify_token) { common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad token \"$verify_token\" for feed $topic"); - throw new ServerError("Bogus hub callback: bad token", 404); + throw new ServerException("Bogus hub callback: bad token", 404); } if ($mode != $profile->sub_state) { diff --git a/plugins/OStatus/actions/pushhub.php b/plugins/OStatus/actions/pushhub.php index 13ec09d528..19599d815f 100644 --- a/plugins/OStatus/actions/pushhub.php +++ b/plugins/OStatus/actions/pushhub.php @@ -83,6 +83,7 @@ class PushHubAction extends Action { $feed = $this->argUrl('hub.topic'); $callback = $this->argUrl('hub.callback'); + $token = $this->arg('hub.verify_token', null); common_log(LOG_DEBUG, __METHOD__ . ": checking sub'd to $feed $callback"); if ($this->getSub($feed, $callback)) { @@ -96,7 +97,6 @@ class PushHubAction extends Action $sub = new HubSub(); $sub->topic = $feed; $sub->callback = $callback; - $sub->verify_token = $this->arg('hub.verify_token', null); $sub->secret = $this->arg('hub.secret', null); if (strlen($sub->secret) > 200) { throw new ClientException("hub.secret must be no longer than 200 chars", 400); @@ -115,7 +115,7 @@ class PushHubAction extends Action // @fixme check errors ;) - $data = array('sub' => $sub, 'mode' => 'subscribe'); + $data = array('sub' => $sub, 'mode' => 'subscribe', 'token' => $token); $qm = QueueManager::get(); $qm->enqueue($data, 'hubverify'); @@ -130,6 +130,8 @@ class PushHubAction extends Action * 202 Accepted - request saved and awaiting verification * 204 No Content - already subscribed * 400 Bad Request - invalid params or rejected feed + * + * @fixme background this */ function unsubscribe() { @@ -138,7 +140,8 @@ class PushHubAction extends Action $sub = $this->getSub($feed, $callback); if ($sub) { - if ($sub->verify('unsubscribe')) { + $token = $this->arg('hub.verify_token', null); + if ($sub->verify('unsubscribe', $token)) { $sub->delete(); common_log(LOG_INFO, "PuSH unsubscribed $feed for $callback"); } else { diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index 9ca0198266..224134cd7c 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -34,6 +34,8 @@ class SalmonAction extends Action function prepare($args) { + parent::prepare($args); + if ($_SERVER['REQUEST_METHOD'] != 'POST') { $this->clientError(_('This method requires a POST.')); } diff --git a/plugins/OStatus/classes/HubSub.php b/plugins/OStatus/classes/HubSub.php index 7071ee5b4f..0cd4281f8f 100644 --- a/plugins/OStatus/classes/HubSub.php +++ b/plugins/OStatus/classes/HubSub.php @@ -30,7 +30,6 @@ class HubSub extends Memcached_DataObject public $topic; public $callback; public $secret; - public $verify_token; public $challenge; public $lease; public $sub_start; @@ -62,7 +61,6 @@ class HubSub extends Memcached_DataObject 'topic' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'callback' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'secret' => DB_DATAOBJECT_STR, - 'verify_token' => DB_DATAOBJECT_STR, 'challenge' => DB_DATAOBJECT_STR, 'lease' => DB_DATAOBJECT_INT, 'sub_start' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, @@ -84,8 +82,6 @@ class HubSub extends Memcached_DataObject 255, false), new ColumnDef('secret', 'text', null, true), - new ColumnDef('verify_token', 'text', - null, true), new ColumnDef('challenge', 'varchar', 32, true), new ColumnDef('lease', 'int', @@ -154,8 +150,9 @@ class HubSub extends Memcached_DataObject /** * Send a verification ping to subscriber * @param string $mode 'subscribe' or 'unsubscribe' + * @param string $token hub.verify_token value, if provided by client */ - function verify($mode) + function verify($mode, $token=null) { assert($mode == 'subscribe' || $mode == 'unsubscribe'); @@ -172,8 +169,8 @@ class HubSub extends Memcached_DataObject if ($mode == 'subscribe') { $params['hub.lease_seconds'] = $this->lease; } - if ($this->verify_token) { - $params['hub.verify_token'] = $this->verify_token; + if ($token !== null) { + $params['hub.verify_token'] = $token; } $url = $this->callback . '?' . http_build_query($params, '', '&'); // @fixme ugly urls diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index be01cdfe19..486417617c 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -484,7 +484,7 @@ class Ostatus_profile extends Memcached_DataObject } else { $this->sub_end = null; } - $this->lastupdate = common_sql_date(); + $this->lastupdate = common_sql_now(); return $this->update($original); } @@ -497,12 +497,13 @@ class Ostatus_profile extends Memcached_DataObject { $original = clone($this); - $this->verify_token = null; - $this->secret = null; - $this->sub_state = null; - $this->sub_start = null; - $this->sub_end = null; - $this->lastupdate = common_sql_date(); + // @fixme these should all be null, but DB_DataObject doesn't save null values...????? + $this->verify_token = ''; + $this->secret = ''; + $this->sub_state = ''; + $this->sub_start = ''; + $this->sub_end = ''; + $this->lastupdate = common_sql_now(); return $this->update($original); } @@ -527,24 +528,25 @@ class Ostatus_profile extends Memcached_DataObject ':' . $actor->id . ':' . time(); // @fixme - $entry = new Atom10Entry(); + //$entry = new Atom10Entry(); + $entry = new XMLStringer(); $entry->elementStart('entry'); $entry->element('id', null, $id); $entry->element('title', null, $text); $entry->element('summary', null, $text); - $entry->element('published', null, common_date_w3dtf()); + $entry->element('published', null, common_date_w3dtf(time())); $entry->element('activity:verb', null, $verb); - $entry->raw($profile->asAtomAuthor()); - $entry->raw($profile->asActivityActor()); + $entry->raw($actor->asAtomAuthor()); + $entry->raw($actor->asActivityActor()); $entry->raw($object->asActivityNoun('object')); - $entry->elmentEnd('entry'); + $entry->elementEnd('entry'); $feed = $this->atomFeed($actor); - $feed->initFeed(); + #$feed->initFeed(); $feed->addEntry($entry); - $feed->renderEntries(); - $feed->endFeed(); + #$feed->renderEntries(); + #$feed->endFeed(); $xml = $feed->getString(); common_log(LOG_INFO, "Posting to Salmon endpoint $salmon: $xml"); @@ -568,7 +570,7 @@ class Ostatus_profile extends Memcached_DataObject $feed = new Atom10Feed(); // @fixme should these be set up somewhere else? $feed->addNamespace('activity', 'http://activitystrea.ms/spec/1.0/'); - $feed->addNamesapce('thr', 'http://purl.org/syndication/thread/1.0'); + $feed->addNamespace('thr', 'http://purl.org/syndication/thread/1.0'); $feed->addNamespace('georss', 'http://www.georss.org/georss'); $feed->addNamespace('ostatus', 'http://ostatus.org/schema/1.0'); @@ -579,14 +581,14 @@ class Ostatus_profile extends Memcached_DataObject $feed->setUpdated(time()); $feed->setPublished(time()); - $feed->addLink(common_url('ApiTimelineUser', - array('id' => $actor->id, - 'type' => 'atom')), + $feed->addLink(common_local_url('ApiTimelineUser', + array('id' => $actor->id, + 'type' => 'atom')), array('rel' => 'self', 'type' => 'application/atom+xml')); - $feed->addLink(common_url('userbyid', - array('id' => $actor->id)), + $feed->addLink(common_local_url('userbyid', + array('id' => $actor->id)), array('rel' => 'alternate', 'type' => 'text/html')); diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index f137946ab4..3ed613dc7f 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -303,6 +303,12 @@ class ActivityVerb const FRIEND = 'http://activitystrea.ms/schema/1.0/make-friend'; const JOIN = 'http://activitystrea.ms/schema/1.0/join'; const TAG = 'http://activitystrea.ms/schema/1.0/tag'; + + // Custom OStatus verbs for the flipside until they're standardized + const DELETE = 'http://ostatus.org/schema/1.0/unfollow'; + const UNFAVORITE = 'http://ostatus.org/schema/1.0/unfavorite'; + const UNFOLLOW = 'http://ostatus.org/schema/1.0/unfollow'; + const LEAVE = 'http://ostatus.org/schema/1.0/leave'; } /** diff --git a/plugins/OStatus/lib/hubverifyqueuehandler.php b/plugins/OStatus/lib/hubverifyqueuehandler.php index 125d13a777..7ce9e14312 100644 --- a/plugins/OStatus/lib/hubverifyqueuehandler.php +++ b/plugins/OStatus/lib/hubverifyqueuehandler.php @@ -33,13 +33,14 @@ class HubVerifyQueueHandler extends QueueHandler { $sub = $data['sub']; $mode = $data['mode']; + $token = $data['token']; assert($sub instanceof HubSub); assert($mode === 'subscribe' || $mode === 'unsubscribe'); common_log(LOG_INFO, __METHOD__ . ": $mode $sub->callback $sub->topic"); try { - $sub->verify($mode); + $sub->verify($mode, $token); } catch (Exception $e) { common_log(LOG_ERR, "Failed PuSH $mode verify to $sub->callback for $sub->topic: " . $e->getMessage()); From 0b5308dea97bae5211ede91e9821cf0834e078a3 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Fri, 19 Feb 2010 00:00:05 +0100 Subject: [PATCH 037/190] Localisation updates for !StatusNet from !translatewiki.net !sntrans Signed-off-by: Siebrand Mazeland --- locale/ar/LC_MESSAGES/statusnet.po | 156 ++++++------- locale/arz/LC_MESSAGES/statusnet.po | 186 +++++++-------- locale/bg/LC_MESSAGES/statusnet.po | 232 +++++++++---------- locale/ca/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/cs/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/de/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/el/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/en_GB/LC_MESSAGES/statusnet.po | 156 ++++++------- locale/es/LC_MESSAGES/statusnet.po | 316 ++++++++++++-------------- locale/fa/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/fi/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/fr/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/ga/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/he/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/hsb/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/ia/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/is/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/it/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/ja/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/ko/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/mk/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/nb/LC_MESSAGES/statusnet.po | 280 +++++++++++------------ locale/nl/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/nn/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/pl/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/pt/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/pt_BR/LC_MESSAGES/statusnet.po | 163 +++++++------ locale/ru/LC_MESSAGES/statusnet.po | 156 ++++++------- locale/statusnet.po | 152 ++++++------- locale/sv/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/te/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/tr/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/uk/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/vi/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/zh_CN/LC_MESSAGES/statusnet.po | 204 ++++++++--------- locale/zh_TW/LC_MESSAGES/statusnet.po | 204 ++++++++--------- 36 files changed, 3636 insertions(+), 3669 deletions(-) diff --git a/locale/ar/LC_MESSAGES/statusnet.po b/locale/ar/LC_MESSAGES/statusnet.po index c7276b56f7..3d3fca98c3 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-02-14 20:05+0000\n" -"PO-Revision-Date: 2010-02-14 20:05:58+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:55:38+0000\n" "Language-Team: Arabic\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62476); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -185,11 +185,11 @@ msgstr "" #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 #: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 -#: actions/apitimelinegroup.php:182 actions/apitimelinehome.php:184 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 #: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 #: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 -#: actions/apitimelineuser.php:194 actions/apiusershow.php:101 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "لم يتم العثور على وسيلة API." @@ -543,7 +543,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "الحساب" @@ -738,7 +738,7 @@ msgid "Preview" msgstr "عاين" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "احذف" @@ -918,7 +918,7 @@ msgstr "أنت لست مالك هذا التطبيق." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -976,7 +976,7 @@ msgstr "أمتأكد من أنك تريد حذف هذا الإشعار؟" msgid "Do not delete this notice" msgstr "لا تحذف هذا الإشعار" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "احذف هذا الإشعار" @@ -1638,7 +1638,7 @@ msgstr "%1$s أعضاء المجموعة, الصفحة %2$d" msgid "A list of the users in this group." msgstr "قائمة بمستخدمي هذه المجموعة." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "إداري" @@ -1968,7 +1968,7 @@ msgstr "اسم المستخدم أو كلمة السر غير صحيحان." msgid "Error setting user. You are probably not authorized." msgstr "خطأ أثناء ضبط المستخدم. لست مُصرحًا على الأرجح." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "لُج" @@ -2212,7 +2212,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "ليس نسق بيانات مدعوم." @@ -2896,7 +2896,7 @@ msgstr "عذرا، رمز دعوة غير صالح." msgid "Registration successful" msgstr "نجح التسجيل" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "سجّل" @@ -3020,7 +3020,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "اشترك" @@ -3056,7 +3056,7 @@ msgstr "لا يمكنك تكرار ملاحظتك الشخصية." msgid "You already repeated that notice." msgstr "أنت كررت هذه الملاحظة بالفعل." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "مكرر" @@ -4148,7 +4148,7 @@ msgstr "" msgid "Plugins" msgstr "ملحقات" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "النسخة" @@ -4230,21 +4230,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "مشكلة أثناء حفظ الإشعار." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "مشكلة أثناء حفظ الإشعار." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1271 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "آر تي @%1$s %2$s" @@ -4299,124 +4299,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "صفحة غير مُعنونة" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "الرئيسية" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "الملف الشخصي ومسار الأصدقاء الزمني" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "اتصل" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "غيّر ضبط الموقع" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "ادعُ" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "اخرج" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "اخرج من الموقع" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "أنشئ حسابًا" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "لُج إلى الموقع" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "مساعدة" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "ساعدني!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "ابحث" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "ابحث عن أشخاص أو نص" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "إشعار الموقع" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "المشاهدات المحلية" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "إشعار الصفحة" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "عن" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "الأسئلة المكررة" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "الشروط" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "خصوصية" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "المصدر" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "اتصل" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "رخصة برنامج StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4425,12 +4425,12 @@ msgstr "" "**%%site.name%%** خدمة تدوين مصغر يقدمها لك [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4441,41 +4441,41 @@ msgstr "" "المتوفر تحت [رخصة غنو أفيرو العمومية](http://www.fsf.org/licensing/licenses/" "agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "رخصة محتوى الموقع" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "الرخصة." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "بعد" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "قبل" @@ -5329,7 +5329,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "من" @@ -5449,48 +5449,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "ش" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "ج" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "ر" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "غ" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "في" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "في السياق" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "مكرر بواسطة" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "رُد على هذا الإشعار" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "رُد" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "الإشعار مكرر" @@ -5780,23 +5780,23 @@ msgstr "عدّل الأفتار" msgid "User actions" msgstr "تصرفات المستخدم" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "عدّل إعدادات الملف الشخصي" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "عدّل" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "أرسل رسالة مباشرة إلى هذا المستخدم" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "رسالة" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" diff --git a/locale/arz/LC_MESSAGES/statusnet.po b/locale/arz/LC_MESSAGES/statusnet.po index 2940486d81..2163be1b4f 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-02-14 20:05+0000\n" -"PO-Revision-Date: 2010-02-14 20:06:01+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:55:41+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.16alpha (r62476); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -189,13 +189,13 @@ msgstr "" #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 #: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 -#: actions/apitimelinegroup.php:182 actions/apitimelinehome.php:184 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 #: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 #: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 -#: actions/apitimelineuser.php:194 actions/apiusershow.php:101 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." -msgstr "لم يتم العثور على وسيله API." +msgstr "الـ API method مش موجوده." #: actions/apiaccountupdatedeliverydevice.php:85 #: actions/apiaccountupdateprofile.php:89 @@ -263,7 +263,7 @@ msgstr "تعذّر تحديث تصميمك." #: actions/apiblockcreate.php:105 msgid "You cannot block yourself!" -msgstr "لا يمكنك منع نفسك!" +msgstr "ما ينفعش تمنع نفسك!" #: actions/apiblockcreate.php:126 msgid "Block user failed." @@ -547,7 +547,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "الحساب" @@ -591,11 +591,11 @@ msgstr "لا إشعار كهذا." #: actions/apistatusesretweet.php:83 msgid "Cannot repeat your own notice." -msgstr "لا يمكنك تكرار ملحوظتك الخاصه." +msgstr "مش نافعه تتكرر الملاحظتك بتاعتك." #: actions/apistatusesretweet.php:91 msgid "Already repeated that notice." -msgstr "كرر بالفعل هذه الملاحظه." +msgstr "الملاحظه اتكررت فعلا." #: actions/apistatusesshow.php:138 msgid "Status deleted." @@ -742,7 +742,7 @@ msgid "Preview" msgstr "عاين" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "احذف" @@ -922,7 +922,7 @@ msgstr "انت مش بتملك الapplication دى." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -980,7 +980,7 @@ msgstr "أمتأكد من أنك تريد حذف هذا الإشعار؟" msgid "Do not delete this notice" msgstr "لا تحذف هذا الإشعار" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "احذف هذا الإشعار" @@ -1468,11 +1468,11 @@ msgstr "اختيار لبعض المستخدمين المتميزين على %s" #: actions/file.php:34 msgid "No notice ID." -msgstr "لا رقم ملاحظه." +msgstr "ما فيش ملاحظة ID." #: actions/file.php:38 msgid "No notice." -msgstr "لا ملاحظه." +msgstr "ما فيش ملاحظه." #: actions/file.php:42 msgid "No attachments." @@ -1480,7 +1480,7 @@ msgstr "لا مرفقات." #: actions/file.php:51 msgid "No uploaded attachments." -msgstr "لا مرفقات مرفوعه." +msgstr "ما فيش فايلات اتعمللها upload." #: actions/finishremotesubscribe.php:69 msgid "Not expecting this response!" @@ -1642,7 +1642,7 @@ msgstr "%1$s اعضاء الجروپ, صفحه %2$d" msgid "A list of the users in this group." msgstr "قائمه بمستخدمى هذه المجموعه." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "إداري" @@ -1972,7 +1972,7 @@ msgstr "اسم المستخدم أو كلمه السر غير صحيحان." msgid "Error setting user. You are probably not authorized." msgstr "خطأ أثناء ضبط المستخدم. لست مُصرحًا على الأرجح." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "لُج" @@ -2214,7 +2214,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr " مش نظام بيانات مدعوم." @@ -2897,7 +2897,7 @@ msgstr "عذرا، رمز دعوه غير صالح." msgid "Registration successful" msgstr "نجح التسجيل" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "سجّل" @@ -3021,7 +3021,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "اشترك" @@ -3047,17 +3047,17 @@ msgstr "" #: actions/repeat.php:64 actions/repeat.php:71 msgid "No notice specified." -msgstr "لا ملاحظه محدده." +msgstr "ما فيش ملاحظه متحدده." #: actions/repeat.php:76 msgid "You can't repeat your own notice." -msgstr "لا يمكنك تكرار ملاحظتك الشخصيه." +msgstr "ما ينفعش تكرر الملاحظه بتاعتك." #: actions/repeat.php:90 msgid "You already repeated that notice." -msgstr "أنت كررت هذه الملاحظه بالفعل." +msgstr "انت عيدت الملاحظه دى فعلا." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "مكرر" @@ -3858,7 +3858,7 @@ msgstr "صورة" #: actions/tagother.php:141 msgid "Tag user" -msgstr "اوسم المستخدم" +msgstr "اعمل tag لليوزر" #: actions/tagother.php:151 msgid "" @@ -3893,7 +3893,7 @@ msgstr "لم تمنع هذا المستخدم." #: actions/unsandbox.php:72 msgid "User is not sandboxed." -msgstr "المستخدم ليس فى صندوق الرمل." +msgstr "اليوزر مش فى السبوره." #: actions/unsilence.php:72 msgid "User is not silenced." @@ -4149,7 +4149,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "النسخه" @@ -4189,7 +4189,7 @@ msgstr "الخروج من الجروپ فشل." #: classes/Login_token.php:76 #, php-format msgid "Could not create login token for %s" -msgstr "لم يمكن إنشاء توكن الولوج ل%s" +msgstr "ما نفعش يتعمل امارة تسجيل دخول لـ %s" #: classes/Message.php:45 msgid "You are banned from sending direct messages." @@ -4231,21 +4231,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "مشكله أثناء حفظ الإشعار." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "مشكله أثناء حفظ الإشعار." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1271 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "آر تى @%1$s %2$s" @@ -4300,124 +4300,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "صفحه غير مُعنونة" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "الرئيسية" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "الملف الشخصى ومسار الأصدقاء الزمني" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "اتصل" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "غيّر ضبط الموقع" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "ادعُ" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "اخرج" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "اخرج من الموقع" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "أنشئ حسابًا" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "لُج إلى الموقع" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "مساعدة" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "ساعدني!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "ابحث" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "ابحث عن أشخاص أو نص" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "إشعار الموقع" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "المشاهدات المحلية" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "إشعار الصفحة" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "عن" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "الأسئله المكررة" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "الشروط" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "خصوصية" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "المصدر" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "اتصل" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4426,12 +4426,12 @@ msgstr "" "**%%site.name%%** خدمه تدوين مصغر يقدمها لك [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4442,41 +4442,41 @@ msgstr "" "المتوفر تحت [رخصه غنو أفيرو العمومية](http://www.fsf.org/licensing/licenses/" "agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "رخصه محتوى الموقع" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "الرخصه." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "بعد" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "قبل" @@ -5320,7 +5320,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "من" @@ -5440,48 +5440,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "ش" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "ج" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "ر" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "غ" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "في" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "فى السياق" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" -msgstr "مكرر بواسطة" +msgstr "متكرر من" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "رُد على هذا الإشعار" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "رُد" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "الإشعار مكرر" @@ -5715,7 +5715,7 @@ msgstr "غير مشترك!" #: lib/subs.php:142 msgid "Couldn't delete self-subscription." -msgstr "لم يمكن حذف اشتراك ذاتى." +msgstr "ما نفعش يمسح الاشتراك الشخصى." #: lib/subs.php:158 msgid "Couldn't delete subscription." @@ -5771,23 +5771,23 @@ msgstr "عدّل الأفتار" msgid "User actions" msgstr "تصرفات المستخدم" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "عدّل إعدادات الملف الشخصي" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "عدّل" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "أرسل رساله مباشره إلى هذا المستخدم" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "رسالة" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" diff --git a/locale/bg/LC_MESSAGES/statusnet.po b/locale/bg/LC_MESSAGES/statusnet.po index efe49b56ab..973f57496a 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:17+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:55:44+0000\n" "Language-Team: Bulgarian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -25,9 +25,8 @@ msgid "Access" msgstr "Достъп" #: actions/accessadminpanel.php:65 -#, fuzzy msgid "Site access settings" -msgstr "Запазване настройките на сайта" +msgstr "Настройки за достъп до сайта" #: actions/accessadminpanel.php:158 msgid "Registration" @@ -70,9 +69,8 @@ msgid "Save" msgstr "Запазване" #: actions/accessadminpanel.php:189 -#, fuzzy msgid "Save access settings" -msgstr "Запазване настройките на сайта" +msgstr "Запазване настройките за достъп" #: actions/all.php:63 actions/public.php:97 actions/replies.php:92 #: actions/showfavorites.php:137 actions/tag.php:51 @@ -163,8 +161,8 @@ msgstr "" msgid "You and friends" msgstr "Вие и приятелите" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Бележки от %1$s и приятели в %2$s." @@ -185,12 +183,12 @@ msgstr "Бележки от %1$s и приятели в %2$s." #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Не е открит методът в API." @@ -555,7 +553,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Сметка" @@ -638,7 +636,7 @@ msgstr "Неподдържан формат." msgid "%1$s / Favorites from %2$s" msgstr "%s / Отбелязани като любими от %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s бележки отбелязани като любими от %s / %s." @@ -649,7 +647,7 @@ msgstr "%s бележки отбелязани като любими от %s / % msgid "%s timeline" msgstr "Поток на %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -665,12 +663,12 @@ msgstr "%1$s / Реплики на %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s реплики на съобщения от %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Общ поток на %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "" @@ -680,7 +678,7 @@ msgstr "" msgid "Repeated to %s" msgstr "Повторено за %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Повторения на %s" @@ -690,7 +688,7 @@ msgstr "Повторения на %s" msgid "Notices tagged with %s" msgstr "Бележки с етикет %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Бележки от %1$s в %2$s." @@ -753,7 +751,7 @@ msgid "Preview" msgstr "Преглед" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Изтриване" @@ -936,7 +934,7 @@ msgstr "Не членувате в тази група." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Имаше проблем със сесията ви в сайта." @@ -994,7 +992,7 @@ msgstr "Наистина ли искате да изтриете тази бел msgid "Do not delete this notice" msgstr "Да не се изтрива бележката" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Изтриване на бележката" @@ -1248,7 +1246,7 @@ msgstr "Описанието е твърде дълго (до %d символа) msgid "Could not update group." msgstr "Грешка при обновяване на групата." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "Грешка при отбелязване като любима." @@ -1258,7 +1256,6 @@ msgid "Options saved." msgstr "Настройките са запазени." #: actions/emailsettings.php:60 -#, fuzzy msgid "Email settings" msgstr "Настройки на е-поща" @@ -1297,9 +1294,8 @@ msgid "Cancel" msgstr "Отказ" #: actions/emailsettings.php:121 -#, fuzzy msgid "Email address" -msgstr "Адреси на е-поща" +msgstr "Адрес на е-поща" #: actions/emailsettings.php:123 msgid "Email address, like \"UserName@example.org\"" @@ -1695,7 +1691,7 @@ msgstr "Членове на групата %s, страница %d" msgid "A list of the users in this group." msgstr "Списък с потребителите в тази група." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Настройки" @@ -2072,14 +2068,14 @@ msgstr "Грешно име или парола." msgid "Error setting user. You are probably not authorized." msgstr "Забранено." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Вход" #: actions/login.php:227 msgid "Login to site" -msgstr "" +msgstr "Вход в сайта" #: actions/login.php:236 actions/register.php:478 msgid "Remember me" @@ -2328,7 +2324,7 @@ msgid "Only " msgstr "Само " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Неподдържан формат на данните" @@ -3021,7 +3017,7 @@ msgstr "Грешка в кода за потвърждение." msgid "Registration successful" msgstr "Записването е успешно." -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Регистриране" @@ -3168,7 +3164,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Адрес на профила ви в друга, съвместима услуга за микроблогване" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Абониране" @@ -3206,7 +3202,7 @@ msgstr "Не можете да повтаряте собствена бележ msgid "You already repeated that notice." msgstr "Вече сте повторили тази бележка." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Повторено" @@ -3267,9 +3263,8 @@ msgid "Replies to %1$s on %2$s!" msgstr "Отговори до %1$s в %2$s!" #: actions/rsd.php:146 actions/version.php:157 -#, fuzzy msgid "StatusNet" -msgstr "Бележката е изтрита." +msgstr "StatusNet" #: actions/sandbox.php:65 actions/unsandbox.php:65 #, fuzzy @@ -3564,9 +3559,9 @@ msgid " tagged %s" msgstr "Бележки с етикет %s" #: actions/showstream.php:79 -#, fuzzy, php-format +#, php-format msgid "%1$s, page %2$d" -msgstr "Блокирани за %s, страница %d" +msgstr "%1$s, страница %2$d" #: actions/showstream.php:122 #, fuzzy, php-format @@ -3785,7 +3780,6 @@ msgid "How long users must wait (in seconds) to post the same thing again." msgstr "" #: actions/smssettings.php:58 -#, fuzzy msgid "SMS settings" msgstr "Настройки за SMS" @@ -3816,7 +3810,6 @@ msgid "Enter the code you received on your phone." msgstr "Въведете кода, който получихте по телефона." #: actions/smssettings.php:138 -#, fuzzy msgid "SMS phone number" msgstr "Телефонен номер за SMS" @@ -4279,9 +4272,8 @@ msgid "%1$s groups, page %2$d" msgstr "Членове на групата %s, страница %d" #: actions/usergroups.php:130 -#, fuzzy msgid "Search for more groups" -msgstr "Търсене за хора или бележки" +msgstr "Търсене на още групи" #: actions/usergroups.php:153 #, php-format @@ -4336,7 +4328,7 @@ msgstr "" msgid "Plugins" msgstr "Приставки" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Версия" @@ -4428,21 +4420,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Забранено ви е да публикувате бележки в този сайт." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Проблем при записване на бележката." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Проблем при записване на бележката." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Грешка в базата от данни — отговор при вмъкването: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4452,11 +4444,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Добре дошли в %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Грешка при създаване на групата." -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "Грешка при създаване на нов абонамент." @@ -4491,136 +4483,136 @@ msgid "Other options" msgstr "Други настройки" #: lib/action.php:144 -#, fuzzy, php-format +#, php-format msgid "%1$s - %2$s" -msgstr "%1$s (%2$s)" +msgstr "%1$s - %2$s" #: lib/action.php:159 msgid "Untitled page" msgstr "Неозаглавена страница" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Начало" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Промяна на поща, аватар, парола, профил" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Свързване" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Свързване към услуги" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Промяна настройките на сайта" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Покани" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Поканете приятели и колеги да се присъединят към вас в %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Изход" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Излизане от сайта" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Създаване на нова сметка" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Влизане в сайта" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Помощ" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "Помощ" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Търсене" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Търсене за хора или бележки" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "Нова бележка" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "Нова бележка" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "Абонаменти" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Относно" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Въпроси" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "Условия" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Поверителност" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Изходен код" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Контакт" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Табелка" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Лиценз на програмата StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4629,12 +4621,12 @@ msgstr "" "**%%site.name%%** е услуга за микроблогване, предоставена ви от [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** е услуга за микроблогване. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4645,41 +4637,41 @@ msgstr "" "достъпна под [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Лиценз на съдържанието" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Всички " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "лиценз." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Страниране" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "След" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Преди" @@ -5542,7 +5534,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "от" @@ -5665,48 +5657,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "С" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "Ю" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "И" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "З" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "в контекст" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Повторено от" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Отговаряне на тази бележка" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Отговор" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Бележката е повторена." @@ -6009,67 +6001,67 @@ msgstr "Редактиране на аватара" msgid "User actions" msgstr "Потребителски действия" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Редактиране на профила" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Редактиране" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Изпращате на пряко съобщение до този потребител." -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Съобщение" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "преди няколко секунди" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "преди около минута" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "преди около %d минути" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "преди около час" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "преди около %d часа" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "преди около ден" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "преди около %d дни" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "преди около месец" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "преди около %d месеца" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "преди около година" diff --git a/locale/ca/LC_MESSAGES/statusnet.po b/locale/ca/LC_MESSAGES/statusnet.po index d0b228c08c..e141f0a0dd 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:20+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:55:48+0000\n" "Language-Team: Catalan\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -169,8 +169,8 @@ msgstr "" msgid "You and friends" msgstr "Un mateix i amics" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Actualitzacions de %1$s i amics a %2$s!" @@ -191,12 +191,12 @@ msgstr "Actualitzacions de %1$s i amics a %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "No s'ha trobat el mètode API!" @@ -569,7 +569,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Compte" @@ -655,7 +655,7 @@ msgstr "El format no està implementat." msgid "%1$s / Favorites from %2$s" msgstr "%s / Preferits de %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s actualitzacions favorites per %s / %s." @@ -666,7 +666,7 @@ msgstr "%s actualitzacions favorites per %s / %s." msgid "%s timeline" msgstr "%s línia temporal" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -682,12 +682,12 @@ msgstr "%1$s / Notificacions contestant a %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s notificacions que responen a notificacions de %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s línia temporal pública" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s notificacions de tots!" @@ -697,7 +697,7 @@ msgstr "%s notificacions de tots!" msgid "Repeated to %s" msgstr "Respostes a %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Repeticions de %s" @@ -707,7 +707,7 @@ msgstr "Repeticions de %s" msgid "Notices tagged with %s" msgstr "Aviso etiquetats amb %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Actualitzacions etiquetades amb %1$s el %2$s!" @@ -769,7 +769,7 @@ msgid "Preview" msgstr "Vista prèvia" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Suprimeix" @@ -954,7 +954,7 @@ msgstr "No sou un membre del grup." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Ha ocorregut algun problema amb la teva sessió." @@ -1016,7 +1016,7 @@ msgstr "N'estàs segur que vols eliminar aquesta notificació?" msgid "Do not delete this notice" msgstr "No es pot esborrar la notificació." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Eliminar aquesta nota" @@ -1266,7 +1266,7 @@ msgstr "la descripció és massa llarga (màx. %d caràcters)." msgid "Could not update group." msgstr "No s'ha pogut actualitzar el grup." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "No s'han pogut crear els àlies." @@ -1711,7 +1711,7 @@ msgstr "%s membre/s en el grup, pàgina %d" msgid "A list of the users in this group." msgstr "La llista dels usuaris d'aquest grup." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2091,7 +2091,7 @@ msgstr "Nom d'usuari o contrasenya incorrectes." msgid "Error setting user. You are probably not authorized." msgstr "No autoritzat." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Inici de sessió" @@ -2351,7 +2351,7 @@ msgid "Only " msgstr "Només " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Format de data no suportat." @@ -3061,7 +3061,7 @@ msgstr "El codi d'invitació no és vàlid." msgid "Registration successful" msgstr "Registre satisfactori" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registre" @@ -3210,7 +3210,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL del teu perfil en un altre servei de microblogging compatible" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Subscriure's" @@ -3253,7 +3253,7 @@ msgstr "No pots registrar-te si no estàs d'acord amb la llicència." msgid "You already repeated that notice." msgstr "Ja heu blocat l'usuari." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Repetit" @@ -4396,7 +4396,7 @@ msgstr "" msgid "Plugins" msgstr "Connectors" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Sessions" @@ -4489,21 +4489,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Ha estat bandejat de publicar notificacions en aquest lloc." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problema en guardar l'avís." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Problema en guardar l'avís." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Error de BD en inserir resposta: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4513,11 +4513,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "Us donem la benvinguda a %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "No s'ha pogut crear el grup." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "No s'ha pogut establir la pertinença d'aquest grup." @@ -4559,125 +4559,125 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Pàgina sense titol" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Navegació primària del lloc" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Inici" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Perfil personal i línia temporal dels amics" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Canviar correu electrònic, avatar, contrasenya, perfil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Connexió" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "No s'ha pogut redirigir al servidor: %s" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Canvia la configuració del lloc" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Convida" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Convidar amics i companys perquè participin a %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Finalitza la sessió" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Finalitza la sessió del lloc" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Crea un compte" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Inicia una sessió al lloc" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Ajuda" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Ajuda'm" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Cerca" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Cerca gent o text" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Avís del lloc" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Vistes locals" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Notificació pàgina" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Navegació del lloc secundària" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Quant a" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Preguntes més freqüents" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privadesa" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Font" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contacte" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Insígnia" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Llicència del programari StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4686,12 +4686,12 @@ msgstr "" "**%%site.name%%** és un servei de microblogging de [%%site.broughtby%%**](%%" "site.broughtbyurl%%)." -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** és un servei de microblogging." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4702,41 +4702,41 @@ msgstr "" "%s, disponible sota la [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Llicència de contingut del lloc" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Tot " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "llicència." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginació" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Posteriors" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Anteriors" @@ -5600,7 +5600,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "de" @@ -5723,49 +5723,49 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "No" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "en context" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Repetit per" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "respondre a aquesta nota" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Respon" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Notificació publicada" @@ -6065,67 +6065,67 @@ msgstr "Edita l'avatar" msgid "User actions" msgstr "Accions de l'usuari" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Edita la configuració del perfil" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Edita" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Enviar un missatge directe a aquest usuari" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Missatge" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Modera" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "fa pocs segons" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "fa un minut" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "fa %d minuts" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "fa una hora" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "fa %d hores" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "fa un dia" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "fa %d dies" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "fa un mes" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "fa %d mesos" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "fa un any" diff --git a/locale/cs/LC_MESSAGES/statusnet.po b/locale/cs/LC_MESSAGES/statusnet.po index a5d6db6003..192a6572eb 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:23+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:55:51+0000\n" "Language-Team: Czech\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -169,8 +169,8 @@ msgstr "" msgid "You and friends" msgstr "%s a přátelé" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -191,12 +191,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "Potvrzující kód nebyl nalezen" @@ -564,7 +564,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 #, fuzzy msgid "Account" msgstr "O nás" @@ -652,7 +652,7 @@ msgstr "Nepodporovaný formát obrázku." msgid "%1$s / Favorites from %2$s" msgstr "%1 statusů na %2" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "Mikroblog od %s" @@ -663,7 +663,7 @@ msgstr "Mikroblog od %s" msgid "%s timeline" msgstr "" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -679,12 +679,12 @@ msgstr "%1 statusů na %2" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "" @@ -694,7 +694,7 @@ msgstr "" msgid "Repeated to %s" msgstr "Odpovědi na %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "Odpovědi na %s" @@ -704,7 +704,7 @@ msgstr "Odpovědi na %s" msgid "Notices tagged with %s" msgstr "" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Mikroblog od %s" @@ -768,7 +768,7 @@ msgid "Preview" msgstr "" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Odstranit" @@ -957,7 +957,7 @@ msgstr "Neodeslal jste nám profil" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -1016,7 +1016,7 @@ msgstr "" msgid "Do not delete this notice" msgstr "Žádné takové oznámení." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Odstranit toto oznámení" @@ -1270,7 +1270,7 @@ msgstr "Text je příliš dlouhý (maximální délka je 140 zanků)" msgid "Could not update group." msgstr "Nelze aktualizovat uživatele" -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "Nelze uložin informace o obrázku" @@ -1719,7 +1719,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2069,7 +2069,7 @@ msgstr "Neplatné jméno nebo heslo" msgid "Error setting user. You are probably not authorized." msgstr "Neautorizován." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Přihlásit" @@ -2320,7 +2320,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -3030,7 +3030,7 @@ msgstr "Chyba v ověřovacím kódu" msgid "Registration successful" msgstr "Registrace úspěšná" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrovat" @@ -3161,7 +3161,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Adresa profilu na jiných kompatibilních mikroblozích." #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Odebírat" @@ -3202,7 +3202,7 @@ msgstr "Nemůžete se registrovat, pokud nesouhlasíte s licencí." msgid "You already repeated that notice." msgstr "Již jste přihlášen" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Vytvořit" @@ -4342,7 +4342,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Osobní" @@ -4430,21 +4430,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problém při ukládání sdělení" -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Problém při ukládání sdělení" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Chyba v DB při vkládání odpovědi: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4454,12 +4454,12 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 #, fuzzy msgid "Could not create group." msgstr "Nelze uložin informace o obrázku" -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "Nelze vytvořit odebírat" @@ -4503,130 +4503,130 @@ msgstr "%1 statusů na %2" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Domů" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Připojit" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Nelze přesměrovat na server: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Odběry" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Odhlásit" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "Vytvořit nový účet" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Nápověda" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Pomoci mi!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Hledat" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "Nové sdělení" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "Nové sdělení" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "Odběry" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "O nás" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Soukromí" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Zdroj" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4635,12 +4635,12 @@ msgstr "" "**%%site.name%%** je služba microblogů, kterou pro vás poskytuje [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** je služba mikroblogů." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4651,43 +4651,43 @@ msgstr "" "dostupná pod [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "Nové sdělení" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 #, fuzzy msgid "After" msgstr "« Novější" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "Starší »" @@ -5559,7 +5559,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr " od " @@ -5685,51 +5685,51 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "Žádný obsah!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Vytvořit" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 #, fuzzy msgid "Reply" msgstr "odpověď" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Sdělení" @@ -6035,68 +6035,68 @@ msgstr "Upravit avatar" msgid "User actions" msgstr "Akce uživatele" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "Nastavené Profilu" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Zpráva" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "před pár sekundami" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "asi před minutou" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "asi před %d minutami" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "asi před hodinou" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "asi před %d hodinami" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "asi přede dnem" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "před %d dny" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "asi před měsícem" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "asi před %d mesíci" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "asi před rokem" diff --git a/locale/de/LC_MESSAGES/statusnet.po b/locale/de/LC_MESSAGES/statusnet.po index b9e53e2544..6578c2f5c5 100644 --- a/locale/de/LC_MESSAGES/statusnet.po +++ b/locale/de/LC_MESSAGES/statusnet.po @@ -13,12 +13,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:26+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:55:55+0000\n" "Language-Team: German\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -181,8 +181,8 @@ msgstr "" msgid "You and friends" msgstr "Du und Freunde" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Aktualisierungen von %1$s und Freunden auf %2$s!" @@ -203,12 +203,12 @@ msgstr "Aktualisierungen von %1$s und Freunden auf %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "API-Methode nicht gefunden." @@ -568,7 +568,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Konto" @@ -654,7 +654,7 @@ msgstr "Bildformat wird nicht unterstützt." msgid "%1$s / Favorites from %2$s" msgstr "%s / Favoriten von %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s Aktualisierung in den Favoriten von %s / %s." @@ -665,7 +665,7 @@ msgstr "%s Aktualisierung in den Favoriten von %s / %s." msgid "%s timeline" msgstr "%s Zeitleiste" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -681,12 +681,12 @@ msgstr "%1$s / Aktualisierungen erwähnen %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "Nachrichten von %1$, die auf Nachrichten von %2$ / %3$ antworten." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s öffentliche Zeitleiste" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s Nachrichten von allen!" @@ -696,7 +696,7 @@ msgstr "%s Nachrichten von allen!" msgid "Repeated to %s" msgstr "Antworten an %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "Antworten an %s" @@ -706,7 +706,7 @@ msgstr "Antworten an %s" msgid "Notices tagged with %s" msgstr "Nachrichten, die mit %s getagt sind" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Aktualisierungen mit %1$s getagt auf %2$s!" @@ -768,7 +768,7 @@ msgid "Preview" msgstr "Vorschau" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Löschen" @@ -951,7 +951,7 @@ msgstr "Du bist kein Mitglied dieser Gruppe." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Es gab ein Problem mit deinem Sessiontoken." @@ -1011,7 +1011,7 @@ msgstr "Bist du sicher, dass du diese Nachricht löschen möchtest?" msgid "Do not delete this notice" msgstr "Diese Nachricht nicht löschen" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Nachricht löschen" @@ -1263,7 +1263,7 @@ msgstr "Die Beschreibung ist zu lang (max. %d Zeichen)." msgid "Could not update group." msgstr "Konnte Gruppe nicht aktualisieren." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Konnte keinen Favoriten erstellen." @@ -1702,7 +1702,7 @@ msgstr "%s Gruppen-Mitglieder, Seite %d" msgid "A list of the users in this group." msgstr "Liste der Benutzer in dieser Gruppe." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2090,7 +2090,7 @@ msgid "Error setting user. You are probably not authorized." msgstr "" "Fehler beim setzen des Benutzers. Du bist vermutlich nicht autorisiert." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Anmelden" @@ -2348,7 +2348,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Kein unterstütztes Datenformat." @@ -3048,7 +3048,7 @@ msgstr "Entschuldigung, ungültiger Bestätigungscode." msgid "Registration successful" msgstr "Registrierung erfolgreich" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrieren" @@ -3200,7 +3200,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Profil-URL bei einem anderen kompatiblen Microbloggingdienst" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Abonnieren" @@ -3238,7 +3238,7 @@ msgstr "Du kannst deine eigene Nachricht nicht wiederholen." msgid "You already repeated that notice." msgstr "Du hast diesen Benutzer bereits blockiert." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Erstellt" @@ -4403,7 +4403,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Eigene" @@ -4497,21 +4497,21 @@ msgid "You are banned from posting notices on this site." msgstr "" "Du wurdest für das Schreiben von Nachrichten auf dieser Seite gesperrt." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problem bei Speichern der Nachricht." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Problem bei Speichern der Nachricht." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Datenbankfehler beim Einfügen der Antwort: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4521,11 +4521,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "Herzlich willkommen bei %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Konnte Gruppe nicht erstellen." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Konnte Gruppenmitgliedschaft nicht setzen." @@ -4567,127 +4567,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Seite ohne Titel" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Hauptnavigation" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Startseite" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Persönliches Profil und Freundes-Zeitleiste" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Ändere deine E-Mail, dein Avatar, Passwort, Profil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Verbinden" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Konnte nicht zum Server umleiten: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Hauptnavigation" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Einladen" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Lade Freunde und Kollegen ein dir auf %s zu folgen" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Abmelden" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Von der Seite abmelden" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Neues Konto erstellen" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Auf der Seite anmelden" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Hilfe" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Hilf mir!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Suchen" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Suche nach Leuten oder Text" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Seitennachricht" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Lokale Ansichten" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Neue Nachricht" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Unternavigation" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Über" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "AGB" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privatsphäre" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Quellcode" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:751 +#: lib/action.php:752 #, fuzzy msgid "Badge" msgstr "Stups" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNet-Software-Lizenz" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4696,12 +4696,12 @@ msgstr "" "**%%site.name%%** ist ein Microbloggingdienst von [%%site.broughtby%%](%%" "site.broughtbyurl%%)." -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** ist ein Microbloggingdienst." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4712,42 +4712,42 @@ msgstr "" "(Version %s) betrieben, die unter der [GNU Affero General Public License]" "(http://www.fsf.org/licensing/licenses/agpl-3.0.html) erhältlich ist." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "StatusNet-Software-Lizenz" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 #, fuzzy msgid "All " msgstr "Alle " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "Lizenz." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Seitenerstellung" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Später" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Vorher" @@ -5665,7 +5665,7 @@ msgstr "" "schicken, um sie in eine Konversation zu verwickeln. Andere Leute können Dir " "Nachrichten schicken, die nur Du sehen kannst." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr "von" @@ -5792,50 +5792,50 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "Nein" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "im Zusammenhang" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Erstellt" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Auf diese Nachricht antworten" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Antworten" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Nachricht gelöscht." @@ -6141,67 +6141,67 @@ msgstr "Avatar bearbeiten" msgid "User actions" msgstr "Benutzeraktionen" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Profil Einstellungen ändern" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Direkte Nachricht an Benutzer verschickt" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Nachricht" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "vor wenigen Sekunden" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "vor einer Minute" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "vor %d Minuten" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "vor einer Stunde" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "vor %d Stunden" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "vor einem Tag" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "vor %d Tagen" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "vor einem Monat" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "vor %d Monaten" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "vor einem Jahr" diff --git a/locale/el/LC_MESSAGES/statusnet.po b/locale/el/LC_MESSAGES/statusnet.po index 20365e04ad..f28a6623d4 100644 --- a/locale/el/LC_MESSAGES/statusnet.po +++ b/locale/el/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:30+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:55:58+0000\n" "Language-Team: Greek\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -164,8 +164,8 @@ msgstr "" msgid "You and friends" msgstr "Εσείς και οι φίλοι σας" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -186,12 +186,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "Η μέθοδος του ΑΡΙ δε βρέθηκε!" @@ -554,7 +554,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Λογαριασμός" @@ -638,7 +638,7 @@ msgstr "" msgid "%1$s / Favorites from %2$s" msgstr "" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "" @@ -649,7 +649,7 @@ msgstr "" msgid "%s timeline" msgstr "χρονοδιάγραμμα του χρήστη %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -665,12 +665,12 @@ msgstr "" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "" @@ -680,7 +680,7 @@ msgstr "" msgid "Repeated to %s" msgstr "" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "" @@ -690,7 +690,7 @@ msgstr "" msgid "Notices tagged with %s" msgstr "" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "" @@ -751,7 +751,7 @@ msgid "Preview" msgstr "" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Διαγραφή" @@ -937,7 +937,7 @@ msgstr "Ομάδες με τα περισσότερα μέλη" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -997,7 +997,7 @@ msgstr "Είσαι σίγουρος ότι θες να διαγράψεις αυ msgid "Do not delete this notice" msgstr "Αδυναμία διαγραφής αυτού του μηνύματος." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "" @@ -1247,7 +1247,7 @@ msgstr "Το βιογραφικό είναι πολύ μεγάλο (μέγιστ msgid "Could not update group." msgstr "Αδύνατη η αποθήκευση του προφίλ." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "Αδύνατη η αποθήκευση του προφίλ." @@ -1688,7 +1688,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Διαχειριστής" @@ -2028,7 +2028,7 @@ msgstr "Λάθος όνομα χρήστη ή κωδικός" msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Σύνδεση" @@ -2278,7 +2278,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -2978,7 +2978,7 @@ msgstr "" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -3123,7 +3123,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "" @@ -3162,7 +3162,7 @@ msgstr "" msgid "You already repeated that notice." msgstr "Αδυναμία διαγραφής αυτού του μηνύματος." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Δημιουργία" @@ -4273,7 +4273,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Προσωπικά" @@ -4359,20 +4359,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Σφάλμα βάσης δεδομένων κατά την εισαγωγή απάντησης: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4382,11 +4382,11 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Δεν ήταν δυνατή η δημιουργία ομάδας." -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "Αδύνατη η αποθήκευση των νέων πληροφοριών του προφίλ" @@ -4428,125 +4428,125 @@ msgstr "" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Αρχή" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Σύνδεση" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Αδυναμία ανακατεύθηνσης στο διακομιστή: %s" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Προσκάλεσε φίλους και συναδέλφους σου να γίνουν μέλη στο %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Αποσύνδεση" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Δημιουργία ενός λογαριασμού" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Βοήθεια" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Βοηθήστε με!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Περί" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Συχνές ερωτήσεις" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Επικοινωνία" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, fuzzy, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4555,13 +4555,13 @@ msgstr "" "To **%%site.name%%** είναι μία υπηρεσία microblogging (μικρο-ιστολογίου) που " "έφερε κοντά σας το [%%site.broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, fuzzy, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" "Το **%%site.name%%** είναι μία υπηρεσία microblogging (μικρο-ιστολογίου). " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4569,41 +4569,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "" @@ -5449,7 +5449,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "από" @@ -5572,48 +5572,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Επαναλαμβάνεται από" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Ρυθμίσεις OpenID" @@ -5913,67 +5913,67 @@ msgstr "" msgid "User actions" msgstr "" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Επεξεργασία ρυθμίσεων προφίλ" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Επεξεργασία" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Μήνυμα" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "" diff --git a/locale/en_GB/LC_MESSAGES/statusnet.po b/locale/en_GB/LC_MESSAGES/statusnet.po index 0e7acedc07..50431ddfa5 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-02-14 20:05+0000\n" -"PO-Revision-Date: 2010-02-14 20:06:20+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:01+0000\n" "Language-Team: British English\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62476); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -192,11 +192,11 @@ msgstr "Updates from %1$s and friends on %2$s!" #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 #: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 -#: actions/apitimelinegroup.php:182 actions/apitimelinehome.php:184 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 #: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 #: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 -#: actions/apitimelineuser.php:194 actions/apiusershow.php:101 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "API method not found." @@ -558,7 +558,7 @@ msgstr "" "the ability to %3$s your %4$s account data. You should only " "give access to your %4$s account to third parties you trust." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Account" @@ -753,7 +753,7 @@ msgid "Preview" msgstr "Preview" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Delete" @@ -934,7 +934,7 @@ msgstr "You are not the owner of this application." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "There was a problem with your session token." @@ -994,7 +994,7 @@ msgstr "Are you sure you want to delete this notice?" msgid "Do not delete this notice" msgstr "Do not delete this notice" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Delete this notice" @@ -1685,7 +1685,7 @@ msgstr "%s group members, page %d" msgid "A list of the users in this group." msgstr "A list of the users in this group." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2065,7 +2065,7 @@ msgstr "Incorrect username or password." msgid "Error setting user. You are probably not authorized." msgstr "Error setting user. You are probably not authorised." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Login" @@ -2324,7 +2324,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Not a supported data format." @@ -3035,7 +3035,7 @@ msgstr "Error with confirmation code." msgid "Registration successful" msgstr "Registration successful" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Register" @@ -3182,7 +3182,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL of your profile on another compatible microblogging service" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Subscribe" @@ -3224,7 +3224,7 @@ msgstr "You can't repeat your own notice." msgid "You already repeated that notice." msgstr "You have already blocked this user." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Created" @@ -4396,7 +4396,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Personal" @@ -4487,21 +4487,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "You are banned from posting notices on this site." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problem saving notice." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Problem saving notice." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "DB error inserting reply: %s" -#: classes/Notice.php:1271 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4556,126 +4556,126 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Untitled page" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Primary site navigation" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Home" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Personal profile and friends timeline" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Change your e-mail, avatar, password, profile" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Connect" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Could not redirect to server: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Primary site navigation" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invite" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invite friends and colleagues to join you on %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Logout" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Logout from the site" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Create an account" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Login to the site" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Help" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Help me!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Search" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Search for people or text" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Site notice" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Local views" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Page notice" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Secondary site navigation" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "About" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "F.A.Q." -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privacy" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Source" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contact" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Badge" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNet software licence" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4684,12 +4684,12 @@ msgstr "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%)." -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** is a microblogging service." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4700,41 +4700,41 @@ msgstr "" "s, available under the [GNU Affero General Public Licence](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Site content license" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "All " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licence." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Pagination" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "After" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Before" @@ -5606,7 +5606,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr "from" @@ -5730,50 +5730,50 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "No" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "in context" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Created" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Reply to this notice" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Reply" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Notice deleted." @@ -6071,23 +6071,23 @@ msgstr "Edit Avatar" msgid "User actions" msgstr "User actions" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Edit profile settings" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Send a direct message to this user" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Message" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" diff --git a/locale/es/LC_MESSAGES/statusnet.po b/locale/es/LC_MESSAGES/statusnet.po index 0d7c9384a1..06c3ee045a 100644 --- a/locale/es/LC_MESSAGES/statusnet.po +++ b/locale/es/LC_MESSAGES/statusnet.po @@ -12,12 +12,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-14 20:05+0000\n" -"PO-Revision-Date: 2010-02-14 20:06:23+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:07+0000\n" "Language-Team: Spanish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62476); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -195,11 +195,11 @@ msgstr "¡Actualizaciones de %1$s y amigos en %2$s!" #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 #: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 -#: actions/apitimelinegroup.php:182 actions/apitimelinehome.php:184 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 #: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 #: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 -#: actions/apitimelineuser.php:194 actions/apiusershow.php:101 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Método de API no encontrado." @@ -564,7 +564,7 @@ msgstr "" "permiso para %3$s la información de tu cuenta %4$s. Sólo " "debes dar acceso a tu cuenta %4$s a terceras partes en las que confíes." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Cuenta" @@ -761,7 +761,7 @@ msgid "Preview" msgstr "Vista previa" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Borrar" @@ -943,7 +943,7 @@ msgstr "No eres el propietario de esta aplicación." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Hubo problemas con tu clave de sesión." @@ -1003,7 +1003,7 @@ msgstr "¿Estás seguro de que quieres eliminar este aviso?" msgid "Do not delete this notice" msgstr "No eliminar este mensaje" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Borrar este aviso" @@ -1691,7 +1691,7 @@ msgstr "%1$s miembros de grupo, página %2$d" msgid "A list of the users in this group." msgstr "Lista de los usuarios en este grupo." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2075,7 +2075,7 @@ msgstr "Nombre de usuario o contraseña incorrectos." msgid "Error setting user. You are probably not authorized." msgstr "Error al configurar el usuario. Posiblemente no tengas autorización." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Inicio de sesión" @@ -2335,7 +2335,7 @@ msgid "Only " msgstr "Sólo " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "No es un formato de dato soportado" @@ -2624,7 +2624,7 @@ msgstr "Servidor SSL" #: actions/pathsadminpanel.php:336 msgid "Server to direct SSL requests to" -msgstr "" +msgstr "Servidor hacia el cual dirigir las solicitudes SSL" #: actions/pathsadminpanel.php:352 #, fuzzy @@ -2724,7 +2724,7 @@ msgstr "Dónde estás, por ejemplo \"Ciudad, Estado (o Región), País\"" #: actions/profilesettings.php:138 msgid "Share my current location when posting notices" -msgstr "" +msgstr "Compartir mi ubicación actual al publicar los mensajes" #: actions/profilesettings.php:145 actions/tagother.php:149 #: actions/tagother.php:209 lib/subscriptionlist.php:106 @@ -2893,6 +2893,8 @@ msgid "" "Why not [register an account](%%action.register%%) and be the first to post " "one!" msgstr "" +"¿Por qué no [registras una cuenta](%%action.register%%) y te conviertes en " +"la primera persona en publicar uno?" #: actions/publictagcloud.php:134 msgid "Tag cloud" @@ -3031,15 +3033,14 @@ msgid "Sorry, only invited people can register." msgstr "Disculpa, sólo personas invitadas pueden registrarse." #: actions/register.php:92 -#, fuzzy msgid "Sorry, invalid invitation code." -msgstr "Error con el código de confirmación." +msgstr "El código de invitación no es válido." #: actions/register.php:112 msgid "Registration successful" msgstr "Registro exitoso." -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrarse" @@ -3111,7 +3112,7 @@ msgstr "" "electrónico, dirección de mensajería instantánea y número de teléfono." #: actions/register.php:538 -#, fuzzy, php-format +#, php-format msgid "" "Congratulations, %1$s! And welcome to %%%%site.name%%%%. From here, you may " "want to...\n" @@ -3128,20 +3129,20 @@ msgid "" "\n" "Thanks for signing up and we hope you enjoy using this service." msgstr "" -"¡Felicitaciones, %s! Y bienvenido a %%%%site.name%%%%. Desde aquí, " -"puedes...\n" +"¡Felicitaciones, %1$s! Te damos la bienvenida a %%%%site.name%%%%. Desde " +"este momento, puede que quieras...\n" "\n" -"* Ir a [tu perfil](%s) y enviar tu primer mensaje.\n" -"* Agregar una [cuenta Jabber/Gtalk](%%%%action.imsettings%%%%) para enviar " -"avisos por mensajes instantáneos.\n" -"* [Buscar personas](%%%%action.peoplesearch%%%%) que podrías conoces o que " -"comparte tus intereses.\n" -"* Actualizar tus [opciones de perfil](%%%%action.profilesettings%%%%) para " -"contar más sobre tí.\n" -"* Leer la [documentación en línea](%%%%doc.help%%%%) para encontrar " -"características pasadas por alto.\n" +"* Ir a [tu perfil](%2$s) y publicar tu primer mensaje.\n" +"* Añadir una [dirección Jabber/GTalk](%%%%action.imsettings%%%%) para poder " +"enviar mensajes a través de mensajería instantanea.\n" +"* [Buscar personas](%%%%action.peoplesearch%%%%) que conozcas o que " +"compartan tus intereses. \n" +"* Actualizar tu [configuración de perfil](%%%%action.profilesettings%%%%) " +"para contarle a otros más sobre tí. \n" +"* Leer los [documentos en línea](%%%%doc.help%%%%) para encontrar " +"características que te hayas podido perder. \n" "\n" -"Gracias por suscribirte y esperamos que disfrutes el uso de este servicio." +"¡Gracias por apuntarte! Esperamos que disfrutes usando este servicio." #: actions/register.php:562 msgid "" @@ -3188,7 +3189,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "El URL de tu perfil en otro servicio de microblogueo compatible" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Suscribirse" @@ -3226,7 +3227,7 @@ msgstr "No puedes repetir tus propios mensajes." msgid "You already repeated that notice." msgstr "Ya has repetido este mensaje." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Repetido" @@ -3327,9 +3328,8 @@ msgstr "" #: actions/sessionsadminpanel.php:199 actions/siteadminpanel.php:336 #: actions/useradminpanel.php:293 -#, fuzzy msgid "Save site settings" -msgstr "Configuración de Avatar" +msgstr "Guardar la configuración del sitio" #: actions/showapplication.php:82 #, fuzzy @@ -3390,11 +3390,11 @@ msgstr "" #: actions/showapplication.php:273 msgid "Request token URL" -msgstr "" +msgstr "URL del token de solicitud" #: actions/showapplication.php:278 msgid "Access token URL" -msgstr "" +msgstr "URL del token de acceso" #: actions/showapplication.php:283 msgid "Authorize URL" @@ -3641,19 +3641,20 @@ msgid "" msgstr "" #: actions/showstream.php:248 -#, fuzzy, php-format +#, php-format msgid "" "**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en." "wikipedia.org/wiki/Micro-blogging) service based on the Free Software " "[StatusNet](http://status.net/) tool. " msgstr "" -"**%s** tiene una cuenta en %%%%site.name%%%%, un servicio [micro-blogging]" -"(http://en.wikipedia.org/wiki/Micro-blogging) " +"**% s ** tiene una cuenta en %%%%site.name%%%%, un servicio de " +"[microblogueo] (http://en.wikipedia.org/wiki/Micro-blogging), basado en la " +"herramienta de software libre [StatusNet] (http://status.net/). " #: actions/showstream.php:305 -#, fuzzy, php-format +#, php-format msgid "Repeat of %s" -msgstr "Respuestas a %s" +msgstr "Repetición de %s" #: actions/silence.php:65 actions/unsilence.php:65 #, fuzzy @@ -3693,7 +3694,7 @@ msgstr "" #: actions/siteadminpanel.php:177 msgid "Snapshot frequency must be a number." -msgstr "" +msgstr "La frecuencia de captura debe ser un número." #: actions/siteadminpanel.php:183 msgid "Minimum text limit is 140 characters." @@ -3750,13 +3751,12 @@ msgid "Default timezone for the site; usually UTC." msgstr "Zona horaria predeterminada del sitio; generalmente UTC." #: actions/siteadminpanel.php:281 -#, fuzzy msgid "Default site language" -msgstr "Lenguaje de preferencia" +msgstr "Idioma predeterminado del sitio" #: actions/siteadminpanel.php:289 msgid "Snapshots" -msgstr "" +msgstr "Capturas" #: actions/siteadminpanel.php:292 msgid "Randomly during Web hit" @@ -3764,11 +3764,11 @@ msgstr "" #: actions/siteadminpanel.php:293 msgid "In a scheduled job" -msgstr "" +msgstr "En un trabajo programado" #: actions/siteadminpanel.php:295 msgid "Data snapshots" -msgstr "" +msgstr "Capturas de datos" #: actions/siteadminpanel.php:296 msgid "When to send statistical data to status.net servers" @@ -3776,7 +3776,7 @@ msgstr "" #: actions/siteadminpanel.php:301 msgid "Frequency" -msgstr "" +msgstr "Frecuencia" #: actions/siteadminpanel.php:302 msgid "Snapshots will be sent once every N web hits" @@ -3808,7 +3808,7 @@ msgstr "" #: actions/siteadminpanel.php:322 msgid "How long users must wait (in seconds) to post the same thing again." -msgstr "" +msgstr "Cuántos segundos es necesario esperar para publicar lo mismo de nuevo." #: actions/smssettings.php:58 msgid "SMS settings" @@ -3913,14 +3913,12 @@ msgid "No code entered" msgstr "No ingresó código" #: actions/subedit.php:70 -#, fuzzy msgid "You are not subscribed to that profile." -msgstr "No estás suscrito a ese perfil." +msgstr "No te has suscrito a ese perfil." #: actions/subedit.php:83 -#, fuzzy msgid "Could not save subscription." -msgstr "No se pudo guardar suscripción." +msgstr "No se ha podido guardar la suscripción." #: actions/subscribe.php:55 #, fuzzy @@ -3932,9 +3930,9 @@ msgid "Subscribed" msgstr "Suscrito" #: actions/subscribers.php:50 -#, fuzzy, php-format +#, php-format msgid "%s subscribers" -msgstr "Suscriptores %s" +msgstr "%s suscriptores" #: actions/subscribers.php:52 #, fuzzy, php-format @@ -3998,14 +3996,13 @@ msgid "" msgstr "" #: actions/subscriptions.php:123 actions/subscriptions.php:127 -#, fuzzy, php-format +#, php-format msgid "%s is not listening to anyone." -msgstr "%1$s ahora está escuchando " +msgstr "%s no está escuchando a nadie." #: actions/subscriptions.php:194 -#, fuzzy msgid "Jabber" -msgstr "Jabber " +msgstr "Jabber" #: actions/subscriptions.php:199 lib/connectsettingsaction.php:115 msgid "SMS" @@ -4100,9 +4097,8 @@ msgid "User is not silenced." msgstr "El usuario no tiene un perfil." #: actions/unsubscribe.php:77 -#, fuzzy msgid "No profile id in request." -msgstr "Ningún perfil de Id en solicitud." +msgstr "No hay id de perfil solicitado." #: actions/unsubscribe.php:98 msgid "Unsubscribed" @@ -4121,20 +4117,20 @@ msgstr "Usuario" #: actions/useradminpanel.php:69 msgid "User settings for this StatusNet site." -msgstr "" +msgstr "Configuración de usuarios en este sitio StatusNet." #: actions/useradminpanel.php:148 msgid "Invalid bio limit. Must be numeric." -msgstr "" +msgstr "Límite para la bio inválido: Debe ser numérico." #: actions/useradminpanel.php:154 msgid "Invalid welcome text. Max length is 255 characters." -msgstr "" +msgstr "Texto de bienvenida inválido. La longitud máx. es de 255 caracteres." #: actions/useradminpanel.php:164 #, php-format msgid "Invalid default subscripton: '%1$s' is not user." -msgstr "" +msgstr "Suscripción predeterminada inválida : '%1$s' no es un usuario" #: actions/useradminpanel.php:217 lib/accountsettingsaction.php:108 #: lib/personalgroupnav.php:109 @@ -4143,11 +4139,11 @@ msgstr "Perfil" #: actions/useradminpanel.php:221 msgid "Bio Limit" -msgstr "" +msgstr "Límite de la bio" #: actions/useradminpanel.php:222 msgid "Maximum length of a profile bio in characters." -msgstr "" +msgstr "Longitud máxima de bio de perfil en caracteres." #: actions/useradminpanel.php:230 msgid "New users" @@ -4159,27 +4155,23 @@ msgstr "Bienvenida a nuevos usuarios" #: actions/useradminpanel.php:235 msgid "Welcome text for new users (Max 255 chars)." -msgstr "" +msgstr "Texto de bienvenida para nuevos usuarios (máx. 255 caracteres)." #: actions/useradminpanel.php:240 msgid "Default subscription" msgstr "Suscripción predeterminada" #: actions/useradminpanel.php:241 -#, fuzzy msgid "Automatically subscribe new users to this user." -msgstr "" -"Suscribirse automáticamente a quien quiera que se suscriba a mí (es mejor " -"para no-humanos)" +msgstr "Suscribir automáticamente nuevos usuarios a este usuario." #: actions/useradminpanel.php:250 msgid "Invitations" msgstr "Invitaciones" #: actions/useradminpanel.php:255 -#, fuzzy msgid "Invitations enabled" -msgstr "Invitacion(es) enviada(s)" +msgstr "Invitaciones habilitadas" #: actions/useradminpanel.php:257 msgid "Whether to allow users to invite new users." @@ -4209,7 +4201,6 @@ msgstr "Aceptar" #: actions/userauthorization.php:218 lib/subscribeform.php:115 #: lib/subscribeform.php:139 -#, fuzzy msgid "Subscribe to this user" msgstr "Suscribirse a este usuario" @@ -4368,7 +4359,7 @@ msgstr "" msgid "Plugins" msgstr "Complementos" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Sesiones" @@ -4414,9 +4405,8 @@ msgid "Could not create login token for %s" msgstr "No se pudo crear favorito." #: classes/Message.php:45 -#, fuzzy msgid "You are banned from sending direct messages." -msgstr "Error al enviar mensaje directo." +msgstr "Se te ha inhabilitado para enviar mensajes directos." #: classes/Message.php:61 msgid "Could not insert message." @@ -4459,21 +4449,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Tienes prohibido publicar avisos en este sitio." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Hubo un problema al guardar el aviso." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Hubo un problema al guardar el aviso." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Error de BD al insertar respuesta: %s" -#: classes/Notice.php:1271 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4529,124 +4519,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Página sin título" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Navegación de sitio primario" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Inicio" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Perfil personal y línea de tiempo de amigos" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Cambia tu correo electrónico, avatar, contraseña, perfil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Conectarse" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Conectar a los servicios" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Cambiar la configuración del sitio" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitar" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invita a amigos y colegas a unirse a %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Salir" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Salir de sitio" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Crear una cuenta" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Ingresar a sitio" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Ayuda" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Ayúdame!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Buscar" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Buscar personas o texto" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Aviso de sitio" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Vistas locales" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Aviso de página" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Navegación de sitio secundario" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Acerca de" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Preguntas Frecuentes" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privacidad" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Fuente" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Ponerse en contacto" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Insignia" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licencia de software de StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4655,12 +4645,12 @@ msgstr "" "**%%site.name%%** es un servicio de microblogueo de [%%site.broughtby%%**](%%" "site.broughtbyurl%%)." -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** es un servicio de microblogueo." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4671,43 +4661,43 @@ msgstr "" "disponible bajo la [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licencia de contenido del sitio" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Derechos de autor de contenido y datos por los colaboradores. Todos los " "derechos reservados." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Todo" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "Licencia." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginación" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Después" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Antes" @@ -4736,19 +4726,16 @@ msgid "Unable to delete design setting." msgstr "¡No se pudo guardar tu configuración de Twitter!" #: lib/adminpanelaction.php:312 -#, fuzzy msgid "Basic site configuration" -msgstr "Confirmación de correo electrónico" +msgstr "Configuración básica del sitio" #: lib/adminpanelaction.php:317 -#, fuzzy msgid "Design configuration" -msgstr "SMS confirmación" +msgstr "Configuración del diseño" #: lib/adminpanelaction.php:322 -#, fuzzy msgid "User configuration" -msgstr "SMS confirmación" +msgstr "Configuración de usuario" #: lib/adminpanelaction.php:327 msgid "Access configuration" @@ -4774,7 +4761,7 @@ msgstr "" #: lib/applicationeditform.php:136 msgid "Edit application" -msgstr "" +msgstr "Editar aplicación" #: lib/applicationeditform.php:184 msgid "Icon for this application" @@ -4791,9 +4778,8 @@ msgid "Describe your application" msgstr "Describir al grupo o tema" #: lib/applicationeditform.php:216 -#, fuzzy msgid "Source URL" -msgstr "Fuente" +msgstr "La URL de origen" #: lib/applicationeditform.php:218 #, fuzzy @@ -4802,7 +4788,7 @@ msgstr "El URL de página de inicio o blog del grupo or tema" #: lib/applicationeditform.php:224 msgid "Organization responsible for this application" -msgstr "" +msgstr "Organización responsable de esta aplicación" #: lib/applicationeditform.php:230 #, fuzzy @@ -4815,15 +4801,15 @@ msgstr "" #: lib/applicationeditform.php:258 msgid "Browser" -msgstr "" +msgstr "Navegador" #: lib/applicationeditform.php:274 msgid "Desktop" -msgstr "" +msgstr "Escritorio" #: lib/applicationeditform.php:275 msgid "Type of application, browser or desktop" -msgstr "" +msgstr "Tipo de aplicación, de navegador o de escritorio" #: lib/applicationeditform.php:297 msgid "Read-only" @@ -4838,9 +4824,8 @@ msgid "Default access for this application: read-only, or read-write" msgstr "" #: lib/applicationlist.php:154 -#, fuzzy msgid "Revoke" -msgstr "Eliminar" +msgstr "Revocar" #: lib/attachmentlist.php:87 msgid "Attachments" @@ -4848,7 +4833,7 @@ msgstr "" #: lib/attachmentlist.php:265 msgid "Author" -msgstr "" +msgstr "Autor" #: lib/attachmentlist.php:278 msgid "Provider" @@ -4856,16 +4841,15 @@ msgstr "Proveedor" #: lib/attachmentnoticesection.php:67 msgid "Notices where this attachment appears" -msgstr "" +msgstr "Mensajes donde aparece este adjunto" #: lib/attachmenttagcloudsection.php:48 msgid "Tags for this attachment" -msgstr "" +msgstr "Etiquetas de este archivo adjunto" #: lib/authenticationplugin.php:218 lib/authenticationplugin.php:223 -#, fuzzy msgid "Password changing failed" -msgstr "Cambio de contraseña " +msgstr "El cambio de contraseña ha fallado" #: lib/authenticationplugin.php:233 #, fuzzy @@ -4889,10 +4873,9 @@ msgid "Sorry, this command is not yet implemented." msgstr "Disculpa, todavía no se implementa este comando." #: lib/command.php:88 -#, fuzzy, php-format +#, php-format msgid "Could not find a user with nickname %s" -msgstr "" -"No se pudo actualizar el usuario con la dirección de correo confirmada." +msgstr "No se pudo encontrar a nadie con el nombre de usuario %s" #: lib/command.php:92 msgid "It does not make a lot of sense to nudge yourself!" @@ -4912,9 +4895,8 @@ msgid "" msgstr "" #: lib/command.php:152 lib/command.php:390 lib/command.php:451 -#, fuzzy msgid "Notice with that id does not exist" -msgstr "Ningún perfil con ese ID." +msgstr "No existe ningún mensaje con ese id" #: lib/command.php:168 lib/command.php:406 lib/command.php:467 #: lib/command.php:523 @@ -5207,11 +5189,11 @@ msgstr "Aceptar" #: lib/feed.php:85 msgid "RSS 1.0" -msgstr "" +msgstr "RSS 1.0" #: lib/feed.php:87 msgid "RSS 2.0" -msgstr "" +msgstr "RSS 2.0" #: lib/feed.php:89 msgid "Atom" @@ -5577,7 +5559,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "desde" @@ -5702,49 +5684,49 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "S" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "E" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "en" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "en contexto" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Crear" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Responder este aviso." -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Responder" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Aviso borrado" @@ -6049,23 +6031,23 @@ msgstr "editar avatar" msgid "User actions" msgstr "Acciones de usuario" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Editar configuración del perfil" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Editar" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Enviar un mensaje directo a este usuario" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Mensaje" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Moderar" diff --git a/locale/fa/LC_MESSAGES/statusnet.po b/locale/fa/LC_MESSAGES/statusnet.po index c749a41611..1d328d4f1f 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:41+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:13+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.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" #: actions/accessadminpanel.php:54 lib/adminpanelaction.php:326 @@ -173,8 +173,8 @@ msgstr "" msgid "You and friends" msgstr "شما و دوستان" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "به روز رسانی از %1$ و دوستان در %2$" @@ -195,12 +195,12 @@ msgstr "به روز رسانی از %1$ و دوستان در %2$" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "رابط مورد نظر پیدا نشد." @@ -557,7 +557,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "حساب کاربری" @@ -641,7 +641,7 @@ msgstr "قالب پشتیبانی نشده." msgid "%1$s / Favorites from %2$s" msgstr "%s / دوست داشتنی از %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s به روز رسانی های دوست داشتنی %s / %s" @@ -652,7 +652,7 @@ msgstr "%s به روز رسانی های دوست داشتنی %s / %s" msgid "%s timeline" msgstr "خط زمانی %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -668,12 +668,12 @@ msgstr "%$1s / به روز رسانی های شامل %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s به روز رسانی هایی که در پاسخ به $2$s / %3$s" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s خط‌زمانی عمومی" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s به روز رسانی های عموم" @@ -683,7 +683,7 @@ msgstr "%s به روز رسانی های عموم" msgid "Repeated to %s" msgstr "" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "تکرار %s" @@ -693,7 +693,7 @@ msgstr "تکرار %s" msgid "Notices tagged with %s" msgstr "پیام‌هایی که با %s نشانه گزاری شده اند." -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "پیام‌های نشانه گزاری شده با %1$s در %2$s" @@ -755,7 +755,7 @@ msgid "Preview" msgstr "پیش‌نمایش" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "حذف" @@ -941,7 +941,7 @@ msgstr "شما یک عضو این گروه نیستید." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -1004,7 +1004,7 @@ msgstr "آیا اطمینان دارید که می‌خواهید این پیا msgid "Do not delete this notice" msgstr "این پیام را پاک نکن" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "این پیام را پاک کن" @@ -1255,7 +1255,7 @@ msgstr "توصیف بسیار زیاد است (حداکثر %d حرف)." msgid "Could not update group." msgstr "نمی‌توان گروه را به‌هنگام‌سازی کرد." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "نمی‌توان نام‌های مستعار را ساخت." @@ -1689,7 +1689,7 @@ msgstr "اعضای گروه %s، صفحهٔ %d" msgid "A list of the users in this group." msgstr "یک فهرست از کاربران در این گروه" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "مدیر" @@ -2042,7 +2042,7 @@ msgstr "نام کاربری یا رمز عبور نادرست." msgid "Error setting user. You are probably not authorized." msgstr "خطا در تنظیم کاربر. شما احتمالا اجازه ی این کار را ندارید." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "ورود" @@ -2302,7 +2302,7 @@ msgid "Only " msgstr " فقط" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "یک قالب دادهٔ پشتیبانی‌شده نیست." @@ -2995,7 +2995,7 @@ msgstr "با عرض تاسف، کد دعوت نا معتبر است." msgid "Registration successful" msgstr "ثبت نام با موفقیت انجام شد." -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "ثبت نام" @@ -3123,7 +3123,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "" @@ -3159,7 +3159,7 @@ msgstr "شما نمی توانید آگهی خودتان را تکرار کنی msgid "You already repeated that notice." msgstr "شما قبلا آن آگهی را تکرار کردید." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "" @@ -4266,7 +4266,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "شخصی" @@ -4355,21 +4355,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "شما از فرستادن پست در این سایت مردود شدید ." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "مشکل در ذخیره کردن آگهی." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "مشکل در ذخیره کردن آگهی." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4379,11 +4379,11 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "خوش امدید به %1$s , @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "نمیتوان گروه را تشکیل داد" -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "" @@ -4424,136 +4424,136 @@ msgstr "%s گروه %s را ترک کرد." msgid "Untitled page" msgstr "صفحه ی بدون عنوان" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "خانه" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "آدرس ایمیل، آواتار، کلمه ی عبور، پروفایل خود را تغییر دهید" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "وصل‌شدن" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "متصل شدن به خدمات" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "تغییر پیکربندی سایت" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "دعوت‌کردن" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr " به شما ملحق شوند %s دوستان و همکاران را دعوت کنید تا در" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "خروج" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "خارج شدن از سایت ." -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "یک حساب کاربری بسازید" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "ورود به وب‌گاه" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "کمک" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "به من کمک کنید!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "جست‌وجو" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "جستجو برای شخص با متن" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "خبر سایت" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "دید محلی" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "خبر صفحه" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "دربارهٔ" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "سوال‌های رایج" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "خصوصی" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "منبع" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "تماس" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNet مجوز نرم افزار" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%). " msgstr "" -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4561,41 +4561,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "مجوز محتویات سایت" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "همه " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "مجوز." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "صفحه بندى" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "بعد از" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "قبل از" @@ -5441,7 +5441,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "از" @@ -5565,48 +5565,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "در" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "در زمینه" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "تکرار از" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "به این آگهی جواب دهید" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "جواب دادن" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "آگهی تکرار شد" @@ -5897,67 +5897,67 @@ msgstr "ویرایش اواتور" msgid "User actions" msgstr "" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "ویرایش تنظیمات پروفيل" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "ویرایش" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "پیام مستقیم به این کاربر بفرستید" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "پیام" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "چند ثانیه پیش" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "حدود یک دقیقه پیش" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "حدود %d دقیقه پیش" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "حدود یک ساعت پیش" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "حدود %d ساعت پیش" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "حدود یک روز پیش" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "حدود %d روز پیش" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "حدود یک ماه پیش" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "حدود %d ماه پیش" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "حدود یک سال پیش" diff --git a/locale/fi/LC_MESSAGES/statusnet.po b/locale/fi/LC_MESSAGES/statusnet.po index 80a85e1d1b..f37da7b0f6 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:39+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:10+0000\n" "Language-Team: Finnish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -175,8 +175,8 @@ msgstr "" msgid "You and friends" msgstr "Sinä ja kaverit" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Käyttäjän %1$s ja kavereiden päivitykset palvelussa %2$s!" @@ -197,12 +197,12 @@ msgstr "Käyttäjän %1$s ja kavereiden päivitykset palvelussa %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "API-metodia ei löytynyt!" @@ -573,7 +573,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Käyttäjätili" @@ -659,7 +659,7 @@ msgstr "Formaattia ei ole tuettu." msgid "%1$s / Favorites from %2$s" msgstr "%s / Käyttäjän %s suosikit" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr " Palvelun %s päivitykset, jotka %s / %s on merkinnyt suosikikseen." @@ -670,7 +670,7 @@ msgstr " Palvelun %s päivitykset, jotka %s / %s on merkinnyt suosikikseen." msgid "%s timeline" msgstr "%s aikajana" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -687,12 +687,12 @@ msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" "%1$s -päivitykset, jotka on vastauksia käyttäjän %2$s / %3$s päivityksiin." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s julkinen aikajana" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s päivitykset kaikilta!" @@ -702,7 +702,7 @@ msgstr "%s päivitykset kaikilta!" msgid "Repeated to %s" msgstr "Vastaukset käyttäjälle %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "Vastaukset käyttäjälle %s" @@ -712,7 +712,7 @@ msgstr "Vastaukset käyttäjälle %s" msgid "Notices tagged with %s" msgstr "Päivitykset joilla on tagi %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Käyttäjän %1$s päivitykset palvelussa %2$s!" @@ -773,7 +773,7 @@ msgid "Preview" msgstr "Esikatselu" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Poista" @@ -958,7 +958,7 @@ msgstr "Sinä et kuulu tähän ryhmään." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Istuntoavaimesi kanssa oli ongelma." @@ -1018,7 +1018,7 @@ msgstr "Oletko varma että haluat poistaa tämän päivityksen?" msgid "Do not delete this notice" msgstr "Älä poista tätä päivitystä" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Poista tämä päivitys" @@ -1277,7 +1277,7 @@ msgstr "kuvaus on liian pitkä (max %d merkkiä)." msgid "Could not update group." msgstr "Ei voitu päivittää ryhmää." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Ei voitu lisätä aliasta." @@ -1722,7 +1722,7 @@ msgstr "Ryhmän %s jäsenet, sivu %d" msgid "A list of the users in this group." msgstr "Lista ryhmän käyttäjistä." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Ylläpito" @@ -2103,7 +2103,7 @@ msgstr "Väärä käyttäjätunnus tai salasana" msgid "Error setting user. You are probably not authorized." msgstr "Sinulla ei ole valtuutusta tähän." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Kirjaudu sisään" @@ -2366,7 +2366,7 @@ msgid "Only " msgstr "Vain " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Tuo ei ole tuettu tietomuoto." @@ -3083,7 +3083,7 @@ msgstr "Virheellinen kutsukoodin." msgid "Registration successful" msgstr "Rekisteröityminen onnistui" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Rekisteröidy" @@ -3235,7 +3235,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Profiilisi URL-osoite toisessa yhteensopivassa mikroblogauspalvelussa" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Tilaa" @@ -3279,7 +3279,7 @@ msgstr "Et voi rekisteröityä, jos et hyväksy lisenssiehtoja." msgid "You already repeated that notice." msgstr "Sinä olet jo estänyt tämän käyttäjän." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Luotu" @@ -4436,7 +4436,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Omat" @@ -4528,21 +4528,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Päivityksesi tähän palveluun on estetty." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Ongelma päivityksen tallentamisessa." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Ongelma päivityksen tallentamisessa." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Tietokantavirhe tallennettaessa vastausta: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4552,11 +4552,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "Viesti käyttäjälle %1$s, %2$s" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Ryhmän luonti ei onnistunut." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Ryhmän jäsenyystietoja ei voitu asettaa." @@ -4598,127 +4598,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Nimetön sivu" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Ensisijainen sivunavigointi" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Koti" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Henkilökohtainen profiili ja kavereiden aikajana" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Muuta sähköpostiosoitettasi, kuvaasi, salasanaasi, profiiliasi" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Yhdistä" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Ei voitu uudelleenohjata palvelimelle: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Ensisijainen sivunavigointi" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Kutsu" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Kutsu kavereita ja työkavereita liittymään palveluun %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Kirjaudu ulos" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Kirjaudu ulos palvelusta" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Luo uusi käyttäjätili" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Kirjaudu sisään palveluun" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Ohjeet" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Auta minua!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Haku" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Hae ihmisiä tai tekstiä" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Palvelun ilmoitus" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Paikalliset näkymät" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Sivuilmoitus" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Toissijainen sivunavigointi" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Tietoa" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "UKK" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Yksityisyys" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Lähdekoodi" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Ota yhteyttä" -#: lib/action.php:751 +#: lib/action.php:752 #, fuzzy msgid "Badge" msgstr "Tönäise" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNet-ohjelmiston lisenssi" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4727,12 +4727,12 @@ msgstr "" "**%%site.name%%** on mikroblogipalvelu, jonka tarjoaa [%%site.broughtby%%](%%" "site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** on mikroblogipalvelu. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4743,42 +4743,42 @@ msgstr "" "versio %s, saatavilla lisenssillä [GNU Affero General Public License](http://" "www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "StatusNet-ohjelmiston lisenssi" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Kaikki " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "lisenssi." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Sivutus" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Myöhemmin" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Aiemmin" @@ -5661,7 +5661,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr " lähteestä " @@ -5785,51 +5785,51 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "Ei" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "Ei sisältöä!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Luotu" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Vastaa tähän päivitykseen" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Vastaus" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Päivitys on poistettu." @@ -6138,68 +6138,68 @@ msgstr "Kuva" msgid "User actions" msgstr "Käyttäjän toiminnot" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "Profiiliasetukset" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Lähetä suora viesti tälle käyttäjälle" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Viesti" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "muutama sekunti sitten" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "noin minuutti sitten" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "noin %d minuuttia sitten" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "noin tunti sitten" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "noin %d tuntia sitten" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "noin päivä sitten" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "noin %d päivää sitten" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "noin kuukausi sitten" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "noin %d kuukautta sitten" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "noin vuosi sitten" diff --git a/locale/fr/LC_MESSAGES/statusnet.po b/locale/fr/LC_MESSAGES/statusnet.po index 9fb5e88b2b..ad0ae7fc5a 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:44+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:16+0000\n" "Language-Team: French\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -175,8 +175,8 @@ msgstr "" msgid "You and friends" msgstr "Vous et vos amis" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Statuts de %1$s et ses amis dans %2$s!" @@ -197,12 +197,12 @@ msgstr "Statuts de %1$s et ses amis dans %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Méthode API non trouvée !" @@ -573,7 +573,7 @@ msgstr "" "devriez donner l’accès à votre compte %4$s qu’aux tiers à qui vous faites " "confiance." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Compte" @@ -657,7 +657,7 @@ msgstr "Format non supporté." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Favoris de %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s statuts favoris de %2$s / %2$s." @@ -668,7 +668,7 @@ msgstr "%1$s statuts favoris de %2$s / %2$s." msgid "%s timeline" msgstr "Activité de %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -684,12 +684,12 @@ msgstr "%1$s / Mises à jour mentionnant %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s statuts en réponses aux statuts de %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Activité publique %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s statuts de tout le monde !" @@ -699,7 +699,7 @@ msgstr "%s statuts de tout le monde !" msgid "Repeated to %s" msgstr "Repris pour %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Reprises de %s" @@ -709,7 +709,7 @@ msgstr "Reprises de %s" msgid "Notices tagged with %s" msgstr "Avis marqués avec %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Mises à jour marquées avec %1$s dans %2$s !" @@ -772,7 +772,7 @@ msgid "Preview" msgstr "Aperçu" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Supprimer" @@ -953,7 +953,7 @@ msgstr "Vous n’êtes pas le propriétaire de cette application." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Un problème est survenu avec votre jeton de session." @@ -1013,7 +1013,7 @@ msgstr "Voulez-vous vraiment supprimer cet avis ?" msgid "Do not delete this notice" msgstr "Ne pas supprimer cet avis" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Supprimer cet avis" @@ -1254,7 +1254,7 @@ msgstr "la description est trop longue (%d caractères maximum)." msgid "Could not update group." msgstr "Impossible de mettre à jour le groupe." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Impossible de créer les alias." @@ -1698,7 +1698,7 @@ msgstr "Membres du groupe %1$s - page %2$d" msgid "A list of the users in this group." msgstr "Liste des utilisateurs inscrits à ce groupe." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Administrer" @@ -2093,7 +2093,7 @@ msgstr "" "Erreur lors de la mise en place de l’utilisateur. Vous n’y êtes probablement " "pas autorisé." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Ouvrir une session" @@ -2357,7 +2357,7 @@ msgid "Only " msgstr "Seulement " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Format de données non supporté." @@ -3068,7 +3068,7 @@ msgstr "Désolé, code d’invitation invalide." msgid "Registration successful" msgstr "Compte créé avec succès" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Créer un compte" @@ -3220,7 +3220,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL de votre profil sur un autre service de micro-blogging compatible" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "S’abonner" @@ -3257,7 +3257,7 @@ msgstr "Vous ne pouvez pas reprendre votre propre avis." msgid "You already repeated that notice." msgstr "Vous avez déjà repris cet avis." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Repris" @@ -4445,7 +4445,7 @@ msgstr "" msgid "Plugins" msgstr "Extensions" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Version" @@ -4533,20 +4533,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Il vous est interdit de poster des avis sur ce site." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problème lors de l’enregistrement de l’avis." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Problème lors de l’enregistrement de la boîte de réception du groupe." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Erreur de base de donnée en insérant la réponse :%s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4556,11 +4556,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Bienvenue à %1$s, @%2$s !" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Impossible de créer le groupe." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Impossible d’établir l’inscription au groupe." @@ -4601,124 +4601,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Page sans nom" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Navigation primaire du site" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Accueil" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Profil personnel et flux des amis" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Modifier votre courriel, avatar, mot de passe, profil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Connecter" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Se connecter aux services" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Modifier la configuration du site" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Inviter" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Inviter des amis et collègues à vous rejoindre dans %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Fermeture de session" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Fermer la session" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Créer un compte" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Ouvrir une session" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Aide" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "À l’aide !" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Rechercher" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Rechercher des personnes ou du texte" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Notice du site" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Vues locales" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Avis de la page" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Navigation secondaire du site" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "À propos" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "CGU" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Confidentialité" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Source" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contact" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Insigne" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licence du logiciel StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4727,12 +4727,12 @@ msgstr "" "**%%site.name%%** est un service de microblogging qui vous est proposé par " "[%%site.broughtby%%](%%site.broughtbyurl%%)." -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** est un service de micro-blogging." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4743,45 +4743,45 @@ msgstr "" "version %s, disponible sous la licence [GNU Affero General Public License] " "(http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licence du contenu du site" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Le contenu et les données de %1$s sont privés et confidentiels." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Le contenu et les données sont sous le droit d’auteur de %1$s. Tous droits " "réservés." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Le contenu et les données sont sous le droit d’auteur du contributeur. Tous " "droits réservés." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Tous " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licence." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Pagination" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Après" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Avant" @@ -5754,7 +5754,7 @@ msgstr "" "pour démarrer des conversations avec d’autres utilisateurs. Ceux-ci peuvent " "vous envoyer des messages destinés à vous seul(e)." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "de" @@ -5880,48 +5880,48 @@ msgstr "" "Désolé, l’obtention de votre localisation prend plus de temps que prévu. " "Veuillez réessayer plus tard." -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u° %2$u' %3$u\" %4$s %5$u° %6$u' %7$u\" %8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "S" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "E" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "O" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "chez" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "dans le contexte" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Repris par" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Répondre à cet avis" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Répondre" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Avis repris" @@ -6211,67 +6211,67 @@ msgstr "Modifier l’avatar" msgid "User actions" msgstr "Actions de l’utilisateur" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Modifier les paramètres du profil" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Modifier" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Envoyer un message à cet utilisateur" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Message" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Modérer" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "il y a quelques secondes" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "il y a 1 minute" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "il y a %d minutes" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "il y a 1 heure" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "il y a %d heures" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "il y a 1 jour" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "il y a %d jours" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "il y a 1 mois" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "il y a %d mois" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "il y a environ 1 an" diff --git a/locale/ga/LC_MESSAGES/statusnet.po b/locale/ga/LC_MESSAGES/statusnet.po index 0358b8ecd0..25adc99870 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:47+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:19+0000\n" "Language-Team: Irish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -170,8 +170,8 @@ msgstr "" msgid "You and friends" msgstr "%s e amigos" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Actualizacións dende %1$s e amigos en %2$s!" @@ -192,12 +192,12 @@ msgstr "Actualizacións dende %1$s e amigos en %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "Método da API non atopado" @@ -569,7 +569,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 #, fuzzy msgid "Account" msgstr "Sobre" @@ -658,7 +658,7 @@ msgstr "Formato de ficheiro de imaxe non soportado." msgid "%1$s / Favorites from %2$s" msgstr "%s / Favoritos dende %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s updates favorited by %s / %s." @@ -669,7 +669,7 @@ msgstr "%s updates favorited by %s / %s." msgid "%s timeline" msgstr "Liña de tempo de %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -685,12 +685,12 @@ msgstr "%1$s / Chíos que respostan a %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "Hai %1$s chíos en resposta a chíos dende %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Liña de tempo pública de %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s chíos de calquera!" @@ -700,7 +700,7 @@ msgstr "%s chíos de calquera!" msgid "Repeated to %s" msgstr "Replies to %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "Replies to %s" @@ -710,7 +710,7 @@ msgstr "Replies to %s" msgid "Notices tagged with %s" msgstr "Chíos tagueados con %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Actualizacións dende %1$s en %2$s!" @@ -773,7 +773,7 @@ msgid "Preview" msgstr "" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 #, fuzzy msgid "Delete" msgstr "eliminar" @@ -968,7 +968,7 @@ msgstr "Non estás suscrito a ese perfil" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 #, fuzzy msgid "There was a problem with your session token." msgstr "Houbo un problema co teu token de sesión. Tentao de novo, anda..." @@ -1031,7 +1031,7 @@ msgstr "Estas seguro que queres eliminar este chío?" msgid "Do not delete this notice" msgstr "Non se pode eliminar este chíos." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 #, fuzzy msgid "Delete this notice" msgstr "Eliminar chío" @@ -1298,7 +1298,7 @@ msgstr "O teu Bio é demasiado longo (max 140 car.)." msgid "Could not update group." msgstr "Non se puido actualizar o usuario." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "Non se puido crear o favorito." @@ -1756,7 +1756,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2137,7 +2137,7 @@ msgstr "Usuario ou contrasinal incorrectos." msgid "Error setting user. You are probably not authorized." msgstr "Non está autorizado." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Inicio de sesión" @@ -2397,7 +2397,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Non é un formato de datos soportado." @@ -3122,7 +3122,7 @@ msgstr "Acounteceu un erro co código de confirmación." msgid "Registration successful" msgstr "Xa estas rexistrado!!" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Rexistrar" @@ -3276,7 +3276,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Enderezo do teu perfil en outro servizo de microblogaxe compatíbel" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Subscribir" @@ -3319,7 +3319,7 @@ msgstr "Non podes rexistrarte se non estas de acordo coa licenza." msgid "You already repeated that notice." msgstr "Xa bloqueaches a este usuario." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Crear" @@ -4492,7 +4492,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Persoal" @@ -4585,21 +4585,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Tes restrinxido o envio de chíos neste sitio." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Aconteceu un erro ó gardar o chío." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Aconteceu un erro ó gardar o chío." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Erro ó inserir a contestación na BD: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4609,12 +4609,12 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "Mensaxe de %1$s en %2$s" -#: classes/User_group.php:380 +#: classes/User_group.php:413 #, fuzzy msgid "Could not create group." msgstr "Non se puido crear o favorito." -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "Non se pode gardar a subscrición." @@ -4658,134 +4658,134 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Persoal" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 #, fuzzy msgid "Change your email, avatar, password, profile" msgstr "Cambiar contrasinal" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Conectar" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Non se pode redireccionar ao servidor: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Navegación de subscricións" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitar" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, fuzzy, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" "Emprega este formulario para invitar ós teus amigos e colegas a empregar " "este servizo." -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Sair" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "Crear nova conta" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Axuda" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "Axuda" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Buscar" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "Novo chío" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "Novo chío" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "Navegación de subscricións" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Sobre" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Preguntas frecuentes" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privacidade" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Fonte" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contacto" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4794,12 +4794,12 @@ msgstr "" "**%%site.name%%** é un servizo de microbloguexo que che proporciona [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** é un servizo de microbloguexo." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4810,44 +4810,44 @@ msgstr "" "%s, dispoñible baixo licenza [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "Atopar no contido dos chíos" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 #, fuzzy msgid "All " msgstr "Todos" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 #, fuzzy msgid "After" msgstr "« Despois" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "Antes »" @@ -5821,7 +5821,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr " dende " @@ -5948,53 +5948,53 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "No" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "Sen contido!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Crear" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 #, fuzzy msgid "Reply to this notice" msgstr "Non se pode eliminar este chíos." -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 #, fuzzy msgid "Reply" msgstr "contestar" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Chío publicado" @@ -6313,70 +6313,70 @@ msgstr "Avatar" msgid "User actions" msgstr "Outras opcions" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "Configuración de perfil" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 #, fuzzy msgid "Send a direct message to this user" msgstr "Non podes enviar mensaxes a este usurio." -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 #, fuzzy msgid "Message" msgstr "Nova mensaxe" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "fai uns segundos" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "fai un minuto" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "fai %d minutos" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "fai unha hora" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "fai %d horas" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "fai un día" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "fai %d días" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "fai un mes" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "fai %d meses" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "fai un ano" diff --git a/locale/he/LC_MESSAGES/statusnet.po b/locale/he/LC_MESSAGES/statusnet.po index fb8f120319..c67c14fc22 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:50+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:22+0000\n" "Language-Team: Hebrew\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -167,8 +167,8 @@ msgstr "" msgid "You and friends" msgstr "%s וחברים" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -189,12 +189,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "קוד האישור לא נמצא." @@ -562,7 +562,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 #, fuzzy msgid "Account" msgstr "אודות" @@ -649,7 +649,7 @@ msgstr "פורמט התמונה אינו נתמך." msgid "%1$s / Favorites from %2$s" msgstr "הסטטוס של %1$s ב-%2$s " -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "מיקרובלוג מאת %s" @@ -660,7 +660,7 @@ msgstr "מיקרובלוג מאת %s" msgid "%s timeline" msgstr "" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -676,12 +676,12 @@ msgstr "הסטטוס של %1$s ב-%2$s " msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "" @@ -691,7 +691,7 @@ msgstr "" msgid "Repeated to %s" msgstr "תגובת עבור %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "תגובת עבור %s" @@ -701,7 +701,7 @@ msgstr "תגובת עבור %s" msgid "Notices tagged with %s" msgstr "" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "מיקרובלוג מאת %s" @@ -765,7 +765,7 @@ msgid "Preview" msgstr "" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 #, fuzzy msgid "Delete" msgstr "מחק" @@ -957,7 +957,7 @@ msgstr "לא שלחנו אלינו את הפרופיל הזה" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -1016,7 +1016,7 @@ msgstr "" msgid "Do not delete this notice" msgstr "אין הודעה כזו." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "" @@ -1276,7 +1276,7 @@ msgstr "הביוגרפיה ארוכה מידי (לכל היותר 140 אותיו msgid "Could not update group." msgstr "עידכון המשתמש נכשל." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "שמירת מידע התמונה נכשל" @@ -1727,7 +1727,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2077,7 +2077,7 @@ msgstr "שם משתמש או סיסמה לא נכונים." msgid "Error setting user. You are probably not authorized." msgstr "לא מורשה." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "היכנס" @@ -2328,7 +2328,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -3036,7 +3036,7 @@ msgstr "שגיאה באישור הקוד." msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "הירשם" @@ -3164,7 +3164,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "כתובת הפרופיל שלך בשרות ביקרובלוג תואם אחר" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "הירשם כמנוי" @@ -3205,7 +3205,7 @@ msgstr "לא ניתן להירשם ללא הסכמה לרשיון" msgid "You already repeated that notice." msgstr "כבר נכנסת למערכת!" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "צור" @@ -4342,7 +4342,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "אישי" @@ -4430,21 +4430,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "בעיה בשמירת ההודעה." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "בעיה בשמירת ההודעה." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "שגיאת מסד נתונים בהכנסת התגובה: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4454,12 +4454,12 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 #, fuzzy msgid "Could not create group." msgstr "שמירת מידע התמונה נכשל" -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "יצירת המנוי נכשלה." @@ -4503,131 +4503,131 @@ msgstr "הסטטוס של %1$s ב-%2$s " msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "בית" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "התחבר" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "נכשלה ההפניה לשרת: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "הרשמות" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "צא" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "צור חשבון חדש" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "עזרה" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "עזרה" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "חיפוש" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "הודעה חדשה" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "הודעה חדשה" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "הרשמות" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "אודות" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "רשימת שאלות נפוצות" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "פרטיות" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "מקור" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "צור קשר" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4636,12 +4636,12 @@ msgstr "" "**%%site.name%%** הוא שרות ביקרובלוג הניתן על ידי [%%site.broughtby%%](%%" "site.broughtbyurl%%)." -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** הוא שרות ביקרובלוג." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4652,43 +4652,43 @@ msgstr "" "s, המופצת תחת רשיון [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)" -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "הודעה חדשה" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 #, fuzzy msgid "After" msgstr "<< אחרי" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "לפני >>" @@ -5558,7 +5558,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "" @@ -5683,52 +5683,52 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "לא" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "אין תוכן!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "צור" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 #, fuzzy msgid "Reply" msgstr "הגב" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "הודעות" @@ -6038,69 +6038,69 @@ msgstr "תמונה" msgid "User actions" msgstr "" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "הגדרות הפרופיל" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 #, fuzzy msgid "Message" msgstr "הודעה חדשה" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "לפני מספר שניות" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "לפני כדקה" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "לפני כ-%d דקות" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "לפני כשעה" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "לפני כ-%d שעות" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "לפני כיום" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "לפני כ-%d ימים" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "לפני כחודש" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "לפני כ-%d חודשים" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "לפני כשנה" diff --git a/locale/hsb/LC_MESSAGES/statusnet.po b/locale/hsb/LC_MESSAGES/statusnet.po index daecf17e80..c9ed505a2a 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:54+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:25+0000\n" "Language-Team: Dutch\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -165,8 +165,8 @@ msgstr "" msgid "You and friends" msgstr "Ty a přećeljo" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -187,12 +187,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "API-metoda njenamakana." @@ -546,7 +546,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Konto" @@ -628,7 +628,7 @@ msgstr "Njepodpěrany format." msgid "%1$s / Favorites from %2$s" msgstr "" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "" @@ -639,7 +639,7 @@ msgstr "" msgid "%s timeline" msgstr "" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -655,12 +655,12 @@ msgstr "" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "" @@ -670,7 +670,7 @@ msgstr "" msgid "Repeated to %s" msgstr "" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "" @@ -680,7 +680,7 @@ msgstr "" msgid "Notices tagged with %s" msgstr "" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "" @@ -742,7 +742,7 @@ msgid "Preview" msgstr "Přehlad" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Zničić" @@ -922,7 +922,7 @@ msgstr "Njejsy wobsedźer tuteje aplikacije." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -980,7 +980,7 @@ msgstr "Chceš woprawdźe tutu zdźělenku wušmórnyć?" msgid "Do not delete this notice" msgstr "Tutu zdźělenku njewušmórnyć" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Tutu zdźělenku wušmórnyć" @@ -1220,7 +1220,7 @@ msgstr "wopisanje je předołho (maks. %d znamješkow)." msgid "Could not update group." msgstr "Skupina njeje so dała aktualizować." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Aliasy njejsu so dali wutworić." @@ -1646,7 +1646,7 @@ msgstr "%1$s skupinskich čłonow, strona %2$d" msgid "A list of the users in this group." msgstr "Lisćina wužiwarjow w tutej skupinje." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -1978,7 +1978,7 @@ msgstr "Wopačne wužiwarske mjeno abo hesło." msgid "Error setting user. You are probably not authorized." msgstr "Zmylk při nastajenju wužiwarja. Snano njejsy awtorizowany." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Přizjewić" @@ -2220,7 +2220,7 @@ msgid "Only " msgstr "Jenož " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Njeje podpěrany datowy format." @@ -2898,7 +2898,7 @@ msgstr "Wodaj, njepłaćiwy přeprošenski kod." msgid "Registration successful" msgstr "Registrowanje wuspěšne" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrować" @@ -3022,7 +3022,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Abonować" @@ -3058,7 +3058,7 @@ msgstr "Njemóžeš swójsku zdźělenku wospjetować." msgid "You already repeated that notice." msgstr "Sy tutu zdźělenku hižo wospjetował." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Wospjetowany" @@ -4146,7 +4146,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Wersija" @@ -4228,20 +4228,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4251,11 +4251,11 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "" -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "" @@ -4296,136 +4296,136 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Strona bjez titula" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Zwjazać" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Přeprosyć" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Konto załožić" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Pomoc" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Pomhaj!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Pytać" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Za ludźimi abo tekstom pytać" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Wo" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Huste prašenja" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Priwatnosć" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Žórło" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%). " msgstr "" -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4433,41 +4433,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "" @@ -5302,7 +5302,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "wot" @@ -5422,48 +5422,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "S" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "J" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "W" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "Z" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Wospjetowany wot" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Na tutu zdźělenku wotmołwić" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Wotmołwić" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Zdźělenka wospjetowana" @@ -5753,67 +5753,67 @@ msgstr "Awatar wobdźěłać" msgid "User actions" msgstr "Wužiwarske akcije" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Profilowe nastajenja wobdźěłać" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Wobdźěłać" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Tutomu wužiwarja direktnu powěsć pósłać" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Powěsć" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "před něšto sekundami" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "před něhdźe jednej mjeńšinu" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "před %d mjeńšinami" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "před něhdźe jednej hodźinu" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "před něhdźe %d hodźinami" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "před něhdźe jednym dnjom" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "před něhdźe %d dnjemi" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "před něhdźe jednym měsacom" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "před něhdźe %d měsacami" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "před něhdźe jednym lětom" diff --git a/locale/ia/LC_MESSAGES/statusnet.po b/locale/ia/LC_MESSAGES/statusnet.po index 698f779dd0..a8d95a851e 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:14:57+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:28+0000\n" "Language-Team: Interlingua\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -168,8 +168,8 @@ msgstr "" msgid "You and friends" msgstr "Tu e amicos" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Actualisationes de %1$s e su amicos in %2$s!" @@ -190,12 +190,12 @@ msgstr "Actualisationes de %1$s e su amicos in %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Methodo API non trovate." @@ -558,7 +558,7 @@ msgstr "" "%3$s le datos de tu conto de %4$s. Tu debe solmente dar " "accesso a tu conto de %4$s a tertie personas in le quales tu ha confidentia." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Conto" @@ -643,7 +643,7 @@ msgstr "Formato non supportate." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Favorites de %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s actualisationes favoritisate per %2$s / %2$s." @@ -654,7 +654,7 @@ msgstr "%1$s actualisationes favoritisate per %2$s / %2$s." msgid "%s timeline" msgstr "Chronologia de %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -671,12 +671,12 @@ msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" "Actualisationes de %1$s que responde al actualisationes de %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Chronologia public de %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "Actualisationes de totes in %s!" @@ -686,7 +686,7 @@ msgstr "Actualisationes de totes in %s!" msgid "Repeated to %s" msgstr "Repetite a %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Repetitiones de %s" @@ -696,7 +696,7 @@ msgstr "Repetitiones de %s" msgid "Notices tagged with %s" msgstr "Notas con etiquetta %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Actualisationes con etiquetta %1$s in %2$s!" @@ -758,7 +758,7 @@ msgid "Preview" msgstr "Previsualisation" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Deler" @@ -939,7 +939,7 @@ msgstr "Tu non es le proprietario de iste application." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Il habeva un problema con tu indicio de session." @@ -999,7 +999,7 @@ msgstr "Es tu secur de voler deler iste nota?" msgid "Do not delete this notice" msgstr "Non deler iste nota" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Deler iste nota" @@ -1240,7 +1240,7 @@ msgstr "description es troppo longe (max %d chars)." msgid "Could not update group." msgstr "Non poteva actualisar gruppo." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Non poteva crear aliases." @@ -1682,7 +1682,7 @@ msgstr "Membros del gruppo %1$s, pagina %2$d" msgid "A list of the users in this group." msgstr "Un lista de usatores in iste gruppo." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2068,7 +2068,7 @@ msgid "Error setting user. You are probably not authorized." msgstr "" "Error de acceder al conto de usator. Tu probabilemente non es autorisate." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Aperir session" @@ -2328,7 +2328,7 @@ msgid "Only " msgstr "Solmente " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Formato de datos non supportate." @@ -3032,7 +3032,7 @@ msgstr "Pardono, le codice de invitation es invalide." msgid "Registration successful" msgstr "Registration succedite" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Crear conto" @@ -3181,7 +3181,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL de tu profilo in un altere servicio de microblogging compatibile" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Subscriber" @@ -3219,7 +3219,7 @@ msgstr "Tu non pote repeter tu proprie nota." msgid "You already repeated that notice." msgstr "Tu ha ja repetite iste nota." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Repetite" @@ -4392,7 +4392,7 @@ msgstr "" msgid "Plugins" msgstr "Plug-ins" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Version" @@ -4480,20 +4480,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Il te es prohibite publicar notas in iste sito." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problema salveguardar nota." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Problema salveguardar le cassa de entrata del gruppo." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Error del base de datos durante le insertion del responsa: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4503,11 +4503,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Benvenite a %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Non poteva crear gruppo." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Non poteva configurar le membrato del gruppo." @@ -4548,124 +4548,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Pagina sin titulo" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Navigation primari del sito" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Initio" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Profilo personal e chronologia de amicos" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Cambiar tu e-mail, avatar, contrasigno, profilo" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Connecter" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Connecter con servicios" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Modificar le configuration del sito" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitar" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invitar amicos e collegas a accompaniar te in %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Clauder session" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Terminar le session del sito" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Crear un conto" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Identificar te a iste sito" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Adjuta" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Adjuta me!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Cercar" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Cercar personas o texto" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Aviso del sito" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Vistas local" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Aviso de pagina" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Navigation secundari del sito" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "A proposito" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "CdS" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Confidentialitate" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Fonte" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contacto" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Insignia" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licentia del software StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4674,12 +4674,12 @@ msgstr "" "**%%site.name%%** es un servicio de microblog offerite per [%%site.broughtby%" "%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** es un servicio de microblog. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4690,42 +4690,42 @@ msgstr "" "net/), version %s, disponibile sub le [GNU Affero General Public License]" "(http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licentia del contento del sito" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Le contento e datos de %1$s es private e confidential." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Contento e datos sub copyright de %1$s. Tote le derectos reservate." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Contento e datos sub copyright del contributores. Tote le derectos reservate." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Totes " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licentia." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Pagination" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Post" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Ante" @@ -5689,7 +5689,7 @@ msgstr "" "altere usatores in conversation. Altere personas pote inviar te messages que " "solmente tu pote leger." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "de" @@ -5815,48 +5815,48 @@ msgstr "" "Pardono, le obtention de tu geolocalisation prende plus tempore que " "previste. Per favor reproba plus tarde." -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "S" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "E" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "W" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "a" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "in contexto" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Repetite per" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Responder a iste nota" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Responder" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Nota repetite" @@ -6146,67 +6146,67 @@ msgstr "Modificar avatar" msgid "User actions" msgstr "Actiones de usator" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Modificar configuration de profilo" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Modificar" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Inviar un message directe a iste usator" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Message" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Moderar" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "alcun secundas retro" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "circa un minuta retro" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "circa %d minutas retro" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "circa un hora retro" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "circa %d horas retro" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "circa un die retro" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "circa %d dies retro" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "circa un mense retro" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "circa %d menses retro" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "circa un anno retro" diff --git a/locale/is/LC_MESSAGES/statusnet.po b/locale/is/LC_MESSAGES/statusnet.po index e885830258..3c17728611 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:11+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:30+0000\n" "Language-Team: Icelandic\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -169,8 +169,8 @@ msgstr "" msgid "You and friends" msgstr "" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Færslur frá %1$s og vinum á %2$s!" @@ -191,12 +191,12 @@ msgstr "Færslur frá %1$s og vinum á %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "Aðferð í forritsskilum fannst ekki!" @@ -564,7 +564,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Aðgangur" @@ -650,7 +650,7 @@ msgstr "Skráarsnið myndar ekki stutt." msgid "%1$s / Favorites from %2$s" msgstr "%s / Uppáhaldsbabl frá %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s færslur gerðar að uppáhaldsbabli af %s / %s." @@ -661,7 +661,7 @@ msgstr "%s færslur gerðar að uppáhaldsbabli af %s / %s." msgid "%s timeline" msgstr "Rás %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -677,12 +677,12 @@ msgstr "" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s færslur sem svara færslum frá %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Almenningsrás %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s færslur frá öllum!" @@ -692,7 +692,7 @@ msgstr "%s færslur frá öllum!" msgid "Repeated to %s" msgstr "Svör við %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "Svör við %s" @@ -702,7 +702,7 @@ msgstr "Svör við %s" msgid "Notices tagged with %s" msgstr "Babl merkt með %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "" @@ -763,7 +763,7 @@ msgid "Preview" msgstr "Forsýn" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Eyða" @@ -950,7 +950,7 @@ msgstr "Þú ert ekki meðlimur í þessum hópi." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Það komu upp vandamál varðandi setutókann þinn." @@ -1008,7 +1008,7 @@ msgstr "Ertu viss um að þú viljir eyða þessu babli?" msgid "Do not delete this notice" msgstr "" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Eyða þessu babli" @@ -1267,7 +1267,7 @@ msgstr "Lýsing er of löng (í mesta lagi 140 tákn)." msgid "Could not update group." msgstr "Gat ekki uppfært hóp." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "" @@ -1709,7 +1709,7 @@ msgstr "Hópmeðlimir %s, síða %d" msgid "A list of the users in this group." msgstr "Listi yfir notendur í þessum hóp." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Stjórnandi" @@ -2087,7 +2087,7 @@ msgstr "Rangt notendanafn eða lykilorð." msgid "Error setting user. You are probably not authorized." msgstr "Engin heimild." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Innskráning" @@ -2348,7 +2348,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Enginn stuðningur við gagnasnið." @@ -3060,7 +3060,7 @@ msgstr "" msgid "Registration successful" msgstr "Nýskráning tókst" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Nýskrá" @@ -3206,7 +3206,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Veffang persónulegrar síðu á samvirkandi örbloggsþjónustu" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Gerast áskrifandi" @@ -3251,7 +3251,7 @@ msgstr "Þú getur ekki nýskráð þig nema þú samþykkir leyfið." msgid "You already repeated that notice." msgstr "Þú hefur nú þegar lokað á þennan notanda." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Í sviðsljósinu" @@ -4389,7 +4389,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Persónulegt" @@ -4478,21 +4478,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Það hefur verið lagt bann við babli frá þér á þessari síðu." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Vandamál komu upp við að vista babl." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Vandamál komu upp við að vista babl." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Gagnagrunnsvilla við innsetningu svars: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4502,11 +4502,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Gat ekki búið til hóp." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Gat ekki skráð hópmeðlimi." @@ -4547,128 +4547,128 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Ónafngreind síða" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Stikl aðalsíðu" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Heim" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Persónuleg síða og vinarás" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" "Breyttu tölvupóstinum þínum, einkennismyndinni þinni, lykilorðinu þínu, " "persónulegu síðunni þinni" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Tengjast" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Gat ekki framsent til vefþjóns: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Stikl aðalsíðu" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Bjóða" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Bjóða vinum og vandamönnum að slást í hópinn á %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Útskráning" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Skrá þig út af síðunni" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Búa til aðgang" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Skrá þig inn á síðuna" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Hjálp" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Hjálp!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Leita" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Leita að fólki eða texta" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Babl vefsíðunnar" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Staðbundin sýn" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Babl síðunnar" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Stikl undirsíðu" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Um" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Spurt og svarað" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Friðhelgi" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Frumþula" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Tengiliður" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Hugbúnaðarleyfi StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4677,12 +4677,12 @@ msgstr "" "**%%site.name%%** er örbloggsþjónusta í boði [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** er örbloggsþjónusta." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4693,42 +4693,42 @@ msgstr "" "sem er gefinn út undir [GNU Affero almenningsleyfinu](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "Hugbúnaðarleyfi StatusNet" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Allt " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "leyfi." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Uppröðun" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Eftir" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Áður" @@ -5596,7 +5596,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr "frá" @@ -5720,50 +5720,50 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "Nei" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Í sviðsljósinu" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Svara þessu babli" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Svara" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Babl sent inn" @@ -6068,67 +6068,67 @@ msgstr "" msgid "User actions" msgstr "Notandaaðgerðir" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Senda bein skilaboð til þessa notanda" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Skilaboð" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "fyrir nokkrum sekúndum" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "fyrir um einni mínútu síðan" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "fyrir um %d mínútum síðan" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "fyrir um einum klukkutíma síðan" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "fyrir um %d klukkutímum síðan" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "fyrir um einum degi síðan" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "fyrir um %d dögum síðan" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "fyrir um einum mánuði síðan" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "fyrir um %d mánuðum síðan" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "fyrir um einu ári síðan" diff --git a/locale/it/LC_MESSAGES/statusnet.po b/locale/it/LC_MESSAGES/statusnet.po index 37ac228b23..ec02b5363b 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:14+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:42+0000\n" "Language-Team: Italian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -172,8 +172,8 @@ msgstr "" msgid "You and friends" msgstr "Tu e i tuoi amici" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Messaggi da %1$s e amici su %2$s!" @@ -194,12 +194,12 @@ msgstr "Messaggi da %1$s e amici su %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Metodo delle API non trovato." @@ -562,7 +562,7 @@ msgstr "" "%3$s ai dati del tuo account %4$s. È consigliato fornire " "accesso al proprio account %4$s solo ad applicazioni di cui ci si può fidare." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Account" @@ -645,7 +645,7 @@ msgstr "Formato non supportato." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Preferiti da %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s aggiornamenti preferiti da %2$s / %3$s" @@ -656,7 +656,7 @@ msgstr "%1$s aggiornamenti preferiti da %2$s / %3$s" msgid "%s timeline" msgstr "Attività di %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -672,12 +672,12 @@ msgstr "%1$s / Messaggi che citano %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s messaggi in risposta a quelli da %2$s / %3$s" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Attività pubblica di %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "Aggiornamenti di %s da tutti!" @@ -687,7 +687,7 @@ msgstr "Aggiornamenti di %s da tutti!" msgid "Repeated to %s" msgstr "Ripetuto a %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Ripetizioni di %s" @@ -697,7 +697,7 @@ msgstr "Ripetizioni di %s" msgid "Notices tagged with %s" msgstr "Messaggi etichettati con %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Messaggi etichettati con %1$s su %2$s!" @@ -759,7 +759,7 @@ msgid "Preview" msgstr "Anteprima" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Elimina" @@ -940,7 +940,7 @@ msgstr "Questa applicazione non è di tua proprietà." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Si è verificato un problema con il tuo token di sessione." @@ -999,7 +999,7 @@ msgstr "Vuoi eliminare questo messaggio?" msgid "Do not delete this notice" msgstr "Non eliminare il messaggio" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Elimina questo messaggio" @@ -1240,7 +1240,7 @@ msgstr "La descrizione è troppo lunga (max %d caratteri)." msgid "Could not update group." msgstr "Impossibile aggiornare il gruppo." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Impossibile creare gli alias." @@ -1686,7 +1686,7 @@ msgstr "Membri del gruppo %1$s, pagina %2$d" msgid "A list of the users in this group." msgstr "Un elenco degli utenti in questo gruppo." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Amministra" @@ -2070,7 +2070,7 @@ msgstr "Nome utente o password non corretto." msgid "Error setting user. You are probably not authorized." msgstr "Errore nell'impostare l'utente. Forse non hai l'autorizzazione." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Accedi" @@ -2326,7 +2326,7 @@ msgid "Only " msgstr "Solo " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Non è un formato di dati supportato." @@ -3030,7 +3030,7 @@ msgstr "Codice di invito non valido." msgid "Registration successful" msgstr "Registrazione riuscita" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registra" @@ -3181,7 +3181,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL del tuo profilo su un altro servizio di microblog compatibile" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Abbonati" @@ -3219,7 +3219,7 @@ msgstr "Non puoi ripetere i tuoi stessi messaggi." msgid "You already repeated that notice." msgstr "Hai già ripetuto quel messaggio." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Ripetuti" @@ -4390,7 +4390,7 @@ msgstr "" msgid "Plugins" msgstr "Plugin" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Versione" @@ -4480,20 +4480,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Ti è proibito inviare messaggi su questo sito." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problema nel salvare il messaggio." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Problema nel salvare la casella della posta del gruppo." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Errore del DB nell'inserire la risposta: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4503,11 +4503,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Benvenuti su %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Impossibile creare il gruppo." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Impossibile impostare la membership al gruppo." @@ -4548,124 +4548,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Pagina senza nome" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Esplorazione sito primaria" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Home" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Profilo personale e attività degli amici" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Modifica la tua email, immagine, password o il tuo profilo" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Connetti" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Connettiti con altri servizi" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Modifica la configurazione del sito" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invita" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invita amici e colleghi a seguirti su %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Esci" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Termina la tua sessione sul sito" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Crea un account" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Accedi al sito" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Aiuto" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Aiutami!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Cerca" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Cerca persone o del testo" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Messaggio del sito" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Viste locali" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Pagina messaggio" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Esplorazione secondaria del sito" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Informazioni" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "TOS" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privacy" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Sorgenti" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contatti" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Badge" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licenza del software StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4674,12 +4674,12 @@ msgstr "" "**%%site.name%%** è un servizio di microblog offerto da [%%site.broughtby%%]" "(%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** è un servizio di microblog. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4690,44 +4690,44 @@ msgstr "" "s, disponibile nei termini della licenza [GNU Affero General Public License]" "(http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licenza del contenuto del sito" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "I contenuti e i dati di %1$s sono privati e confidenziali." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "I contenuti e i dati sono copyright di %1$s. Tutti i diritti riservati." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "I contenuti e i dati sono forniti dai collaboratori. Tutti i diritti " "riservati." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Tutti " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licenza." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginazione" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Successivi" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Precedenti" @@ -5693,7 +5693,7 @@ msgstr "" "iniziare una conversazione con altri utenti. Altre persone possono mandare " "messaggi riservati solamente a te." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "via" @@ -5818,48 +5818,48 @@ msgstr "" "Il recupero della tua posizione geografica sta impiegando più tempo del " "previsto. Riprova più tardi." -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "S" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "E" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "O" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "presso" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "in una discussione" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Ripetuto da" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Rispondi a questo messaggio" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Rispondi" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Messaggio ripetuto" @@ -6149,67 +6149,67 @@ msgstr "Modifica immagine" msgid "User actions" msgstr "Azioni utente" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Modifica impostazioni del profilo" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Modifica" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Invia un messaggio diretto a questo utente" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Messaggio" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Modera" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "pochi secondi fa" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "circa un minuto fa" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "circa %d minuti fa" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "circa un'ora fa" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "circa %d ore fa" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "circa un giorno fa" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "circa %d giorni fa" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "circa un mese fa" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "circa %d mesi fa" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "circa un anno fa" diff --git a/locale/ja/LC_MESSAGES/statusnet.po b/locale/ja/LC_MESSAGES/statusnet.po index 3063f95389..ba52e7bfb0 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:17+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:45+0000\n" "Language-Team: Japanese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -169,8 +169,8 @@ msgstr "" msgid "You and friends" msgstr "あなたと友人" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "%2$s に %1$s と友人からの更新があります!" @@ -191,12 +191,12 @@ msgstr "%2$s に %1$s と友人からの更新があります!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "API メソッドが見つかりません。" @@ -556,7 +556,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "アカウント" @@ -638,7 +638,7 @@ msgstr "サポート外の形式です。" msgid "%1$s / Favorites from %2$s" msgstr "%1$s / %2$s からのお気に入り" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s は %2$s でお気に入りを更新しました / %2$s。" @@ -649,7 +649,7 @@ msgstr "%1$s は %2$s でお気に入りを更新しました / %2$s。" msgid "%s timeline" msgstr "%s のタイムライン" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -665,12 +665,12 @@ msgstr "%1$s / %2$s について更新" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%2$s からアップデートに答える %1$s アップデート" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s のパブリックタイムライン" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "皆からの %s アップデート!" @@ -680,7 +680,7 @@ msgstr "皆からの %s アップデート!" msgid "Repeated to %s" msgstr "%s への返信" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "%s の返信" @@ -690,7 +690,7 @@ msgstr "%s の返信" msgid "Notices tagged with %s" msgstr "%s とタグ付けされたつぶやき" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "%2$s に %1$s による更新があります!" @@ -751,7 +751,7 @@ msgid "Preview" msgstr "プレビュー" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "削除" @@ -933,7 +933,7 @@ msgstr "このアプリケーションのオーナーではありません。" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "あなたのセッショントークンに関する問題がありました。" @@ -993,7 +993,7 @@ msgstr "本当にこのつぶやきを削除しますか?" msgid "Do not delete this notice" msgstr "このつぶやきを削除できません。" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "このつぶやきを削除" @@ -1234,7 +1234,7 @@ msgstr "記述が長すぎます。(最長 %d 字)" msgid "Could not update group." msgstr "グループを更新できません。" -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "別名を作成できません。" @@ -1679,7 +1679,7 @@ msgstr "%1$s グループメンバー、ページ %2$d" msgid "A list of the users in this group." msgstr "このグループのユーザのリスト。" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "管理者" @@ -2062,7 +2062,7 @@ msgstr "ユーザ名またはパスワードが間違っています。" msgid "Error setting user. You are probably not authorized." msgstr "ユーザ設定エラー。 あなたはたぶん承認されていません。" -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "ログイン" @@ -2317,7 +2317,7 @@ msgid "Only " msgstr "だけ " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "サポートされていないデータ形式。" @@ -3020,7 +3020,7 @@ msgstr "すみません、不正な招待コード。" msgid "Registration successful" msgstr "登録成功" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "登録" @@ -3167,7 +3167,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "プロファイルサービスまたはマイクロブロギングサービスのURL" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "フォロー" @@ -3206,7 +3206,7 @@ msgstr "自分のつぶやきは繰り返せません。" msgid "You already repeated that notice." msgstr "すでにそのつぶやきを繰り返しています。" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "繰り返された" @@ -4371,7 +4371,7 @@ msgstr "" msgid "Plugins" msgstr "プラグイン" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "バージョン" @@ -4461,20 +4461,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "あなたはこのサイトでつぶやきを投稿するのが禁止されています。" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "つぶやきを保存する際に問題が発生しました。" -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "グループ受信箱を保存する際に問題が発生しました。" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "返信を追加する際にデータベースエラー : %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4484,11 +4484,11 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "ようこそ %1$s、@%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "グループを作成できません。" -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "グループメンバーシップをセットできません。" @@ -4529,124 +4529,124 @@ msgstr "" msgid "Untitled page" msgstr "名称未設定ページ" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "プライマリサイトナビゲーション" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "ホーム" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "パーソナルプロファイルと友人のタイムライン" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "メールアドレス、アバター、パスワード、プロパティの変更" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "接続" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "サービスへ接続" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "サイト設定の変更" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "招待" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "友人や同僚が %s で加わるよう誘ってください。" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "ログアウト" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "サイトからログアウト" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "アカウントを作成" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "サイトへログイン" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "ヘルプ" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "助けて!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "検索" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "人々かテキストを検索" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "サイトつぶやき" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "ローカルビュー" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "ページつぶやき" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "セカンダリサイトナビゲーション" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "About" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "よくある質問" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "プライバシー" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "ソース" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "連絡先" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "バッジ" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNet ソフトウェアライセンス" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4655,12 +4655,12 @@ msgstr "" "**%%site.name%%** は [%%site.broughtby%%](%%site.broughtbyurl%%) が提供するマ" "イクロブログサービスです。 " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** はマイクロブログサービスです。 " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4671,41 +4671,41 @@ msgstr "" "いています。 ライセンス [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)。" -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "サイト内容ライセンス" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "全て " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "ライセンス。" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "ページ化" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "<<後" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "前>>" @@ -5624,7 +5624,7 @@ msgstr "" "に引き込むプライベートメッセージを送ることができます。人々はあなただけへの" "メッセージを送ることができます。" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "from" @@ -5752,52 +5752,52 @@ msgstr "" "すみません、あなたの位置を検索するのが予想より長くかかっています、後でもう一" "度試みてください" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "北" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "S" msgstr "南" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 #, fuzzy msgid "E" msgstr "東" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 #, fuzzy msgid "W" msgstr "西" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "at" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "このつぶやきへ返信" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "返信" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "つぶやきを繰り返しました" @@ -6087,68 +6087,68 @@ msgstr "アバターを編集する" msgid "User actions" msgstr "利用者アクション" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "プロファイル設定編集" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "編集" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "この利用者にダイレクトメッセージを送る" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "メッセージ" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 #, fuzzy msgid "Moderate" msgstr "管理" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "数秒前" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "約 1 分前" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "約 %d 分前" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "約 1 時間前" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "約 %d 時間前" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "約 1 日前" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "約 %d 日前" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "約 1 ヵ月前" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "約 %d ヵ月前" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "約 1 年前" diff --git a/locale/ko/LC_MESSAGES/statusnet.po b/locale/ko/LC_MESSAGES/statusnet.po index 7be2acfca1..dd89d10477 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:20+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:48+0000\n" "Language-Team: Korean\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -168,8 +168,8 @@ msgstr "" msgid "You and friends" msgstr "%s 및 친구들" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "%1$s 및 %2$s에 있는 친구들의 업데이트!" @@ -190,12 +190,12 @@ msgstr "%1$s 및 %2$s에 있는 친구들의 업데이트!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "API 메서드를 찾을 수 없습니다." @@ -567,7 +567,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "계정" @@ -654,7 +654,7 @@ msgstr "지원하지 않는 그림 파일 형식입니다." msgid "%1$s / Favorites from %2$s" msgstr "%s / %s의 좋아하는 글들" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s 좋아하는 글이 업데이트 됐습니다. %S에 의해 / %s." @@ -665,7 +665,7 @@ msgstr "%s 좋아하는 글이 업데이트 됐습니다. %S에 의해 / %s." msgid "%s timeline" msgstr "%s 타임라인" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -681,12 +681,12 @@ msgstr "%1$s / %2$s에게 답신 업데이트" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s님이 %2$s/%3$s의 업데이트에 답변했습니다." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s 공개 타임라인" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "모두로부터의 업데이트 %s개!" @@ -696,7 +696,7 @@ msgstr "모두로부터의 업데이트 %s개!" msgid "Repeated to %s" msgstr "%s에 답신" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "%s에 답신" @@ -706,7 +706,7 @@ msgstr "%s에 답신" msgid "Notices tagged with %s" msgstr "%s 태그된 통지" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "%2$s에 있는 %1$s의 업데이트!" @@ -768,7 +768,7 @@ msgid "Preview" msgstr "미리보기" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "삭제" @@ -957,7 +957,7 @@ msgstr "당신은 해당 그룹의 멤버가 아닙니다." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "당신의 세션토큰관련 문제가 있습니다." @@ -1018,7 +1018,7 @@ msgstr "정말로 통지를 삭제하시겠습니까?" msgid "Do not delete this notice" msgstr "이 통지를 지울 수 없습니다." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "이 게시글 삭제하기" @@ -1281,7 +1281,7 @@ msgstr "설명이 너무 길어요. (최대 140글자)" msgid "Could not update group." msgstr "그룹을 업데이트 할 수 없습니다." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "좋아하는 게시글을 생성할 수 없습니다." @@ -1736,7 +1736,7 @@ msgstr "%s 그룹 회원, %d페이지" msgid "A list of the users in this group." msgstr "이 그룹의 회원리스트" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "관리자" @@ -2108,7 +2108,7 @@ msgstr "틀린 계정 또는 비밀 번호" msgid "Error setting user. You are probably not authorized." msgstr "인증이 되지 않았습니다." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "로그인" @@ -2366,7 +2366,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "지원하는 형식의 데이터가 아닙니다." @@ -3075,7 +3075,7 @@ msgstr "확인 코드 오류" msgid "Registration successful" msgstr "회원 가입이 성공적입니다." -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "회원가입" @@ -3222,7 +3222,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "다른 마이크로블로깅 서비스의 귀하의 프로필 URL" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "구독" @@ -3265,7 +3265,7 @@ msgstr "라이선스에 동의하지 않는다면 등록할 수 없습니다." msgid "You already repeated that notice." msgstr "당신은 이미 이 사용자를 차단하고 있습니다." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "생성" @@ -4410,7 +4410,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "개인적인" @@ -4503,21 +4503,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "이 사이트에 게시글 포스팅으로부터 당신은 금지되었습니다." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "통지를 저장하는데 문제가 발생했습니다." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "통지를 저장하는데 문제가 발생했습니다." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "답신을 추가 할 때에 데이타베이스 에러 : %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4527,11 +4527,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "%2$s에서 %1$s까지 메시지" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "새 그룹을 만들 수 없습니다." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "그룹 맴버십을 세팅할 수 없습니다." @@ -4573,127 +4573,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "제목없는 페이지" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "주 사이트 네비게이션" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "홈" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "개인 프로필과 친구 타임라인" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "당신의 이메일, 아바타, 비밀 번호, 프로필을 변경하세요." -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "연결" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "서버에 재접속 할 수 없습니다 : %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "주 사이트 네비게이션" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "초대" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "%s에 친구를 가입시키기 위해 친구와 동료를 초대합니다." -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "로그아웃" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "이 사이트로부터 로그아웃" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "계정 만들기" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "이 사이트 로그인" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "도움말" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "도움이 필요해!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "검색" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "프로필이나 텍스트 검색" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "사이트 공지" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "로컬 뷰" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "페이지 공지" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "보조 사이트 네비게이션" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "정보" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "자주 묻는 질문" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "개인정보 취급방침" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "소스 코드" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "연락하기" -#: lib/action.php:751 +#: lib/action.php:752 #, fuzzy msgid "Badge" msgstr "찔러 보기" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "라코니카 소프트웨어 라이선스" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4702,12 +4702,12 @@ msgstr "" "**%%site.name%%** 는 [%%site.broughtby%%](%%site.broughtbyurl%%)가 제공하는 " "마이크로블로깅서비스입니다." -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** 는 마이크로블로깅서비스입니다." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4718,42 +4718,42 @@ msgstr "" "을 사용합니다. StatusNet는 [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html) 라이선스에 따라 사용할 수 있습니다." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "라코니카 소프트웨어 라이선스" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "모든 것" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "라이선스" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "페이지수" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "뒷 페이지" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "앞 페이지" @@ -5619,7 +5619,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr "다음에서:" @@ -5743,51 +5743,51 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "아니오" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "내용이 없습니다!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "생성" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "이 게시글에 대해 답장하기" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "답장하기" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "게시글이 등록되었습니다." @@ -6096,68 +6096,68 @@ msgstr "아바타" msgid "User actions" msgstr "사용자 동작" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "프로필 세팅" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "이 회원에게 직접 메시지를 보냅니다." -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "메시지" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "몇 초 전" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "1분 전" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "%d분 전" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "1시간 전" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "%d시간 전" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "하루 전" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "%d일 전" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "1달 전" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "%d달 전" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "1년 전" diff --git a/locale/mk/LC_MESSAGES/statusnet.po b/locale/mk/LC_MESSAGES/statusnet.po index 92209e72ea..5e7aba59fc 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:23+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:51+0000\n" "Language-Team: Macedonian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -172,8 +172,8 @@ msgstr "" msgid "You and friends" msgstr "Вие и пријателите" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Подновувања од %1$s и пријатели на %2$s!" @@ -194,12 +194,12 @@ msgstr "Подновувања од %1$s и пријатели на %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "API методот не е пронајден." @@ -562,7 +562,7 @@ msgstr "" "%3$s податоците за Вашата %4$s сметка. Треба да дозволувате " "пристап до Вашата %4$s сметка само на трети страни на кои им верувате." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Сметка" @@ -646,7 +646,7 @@ msgstr "Неподдржан формат." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Омилени од %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "Подновувања на %1$s омилени на %2$s / %2$s." @@ -657,7 +657,7 @@ msgstr "Подновувања на %1$s омилени на %2$s / %2$s." msgid "%s timeline" msgstr "Историја на %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -673,12 +673,12 @@ msgstr "%1$s / Подновувања кои споменуваат %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s подновувања коишто се одговор на подновувањата од %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Јавна историја на %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s подновуввања од сите!" @@ -688,7 +688,7 @@ msgstr "%s подновуввања од сите!" msgid "Repeated to %s" msgstr "Повторено за %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Повторувања на %s" @@ -698,7 +698,7 @@ msgstr "Повторувања на %s" msgid "Notices tagged with %s" msgstr "Забелешки означени со %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Подновувањата се означени со %1$s на %2$s!" @@ -761,7 +761,7 @@ msgid "Preview" msgstr "Преглед" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Бриши" @@ -943,7 +943,7 @@ msgstr "Не сте сопственик на овој програм." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Се појави проблем со Вашиот сесиски жетон." @@ -1003,7 +1003,7 @@ msgstr "Дали сте сигурни дека сакате да ја избр msgid "Do not delete this notice" msgstr "Не ја бриши оваа забелешка" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Бриши ја оваа забелешка" @@ -1244,7 +1244,7 @@ msgstr "описот е предолг (максимум %d знаци)" msgid "Could not update group." msgstr "Не можев да ја подновам групата." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Не можеше да се создадат алијаси." @@ -1691,7 +1691,7 @@ msgstr "Членови на групата %1$s, стр. %2$d" msgid "A list of the users in this group." msgstr "Листа на корисниците на овааг група." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Администратор" @@ -2077,7 +2077,7 @@ msgstr "Неточно корисничко име или лозинка" msgid "Error setting user. You are probably not authorized." msgstr "Грешка при поставувањето на корисникот. Веројатно не се заверени." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Најава" @@ -2336,7 +2336,7 @@ msgid "Only " msgstr "Само " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Ова не е поддржан формат на податотека." @@ -3045,7 +3045,7 @@ msgstr "Жалиме, неважечки код за поканата." msgid "Registration successful" msgstr "Регистрацијата е успешна" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Регистрирај се" @@ -3196,7 +3196,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL на Вашиот профил на друга компатибилна служба за микроблогирање." #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Претплати се" @@ -3234,7 +3234,7 @@ msgstr "Не можете да повторувате сопствена заб msgid "You already repeated that notice." msgstr "Веќе ја имате повторено таа забелешка." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Повторено" @@ -4413,7 +4413,7 @@ msgstr "" msgid "Plugins" msgstr "Приклучоци" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Верзија" @@ -4502,20 +4502,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Забрането Ви е да објавувате забелешки на оваа веб-страница." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Проблем во зачувувањето на белешката." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Проблем при зачувувањето на групното приемно сандаче." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Одговор од внесот во базата: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4525,11 +4525,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Добредојдовте на %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Не можев да ја создадам групата." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Не можев да назначам членство во групата." @@ -4570,124 +4570,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Страница без наслов" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Главна навигација" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Дома" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Личен профил и историја на пријатели" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Промена на е-пошта, аватар, лозинка, профил" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Поврзи се" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Поврзи се со услуги" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Промена на конфигурацијата на веб-страницата" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Покани" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Поканете пријатели и колеги да Ви се придружат на %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Одјави се" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Одјава" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Создај сметка" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Најава" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Помош" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Напомош!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Барај" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Пребарајте луѓе или текст" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Напомена за веб-страницата" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Локални прегледи" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Напомена за страницата" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Споредна навигација" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "За" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "ЧПП" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "Услови" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Приватност" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Изворен код" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Контакт" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Значка" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Лиценца на програмот StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4696,12 +4696,12 @@ msgstr "" "**%%site.name%%** е сервис за микроблогирање што ви го овозможува [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** е сервис за микроблогирање." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4712,45 +4712,45 @@ msgstr "" "верзија %s, достапен пд [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Лиценца на содржините на веб-страницата" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Содржината и податоците на %1$s се лични и доверливи." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Авторските права на содржината и податоците се во сопственост на %1$s. Сите " "права задржани." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Авторските права на содржината и податоците им припаѓаат на учесниците. Сите " "права задржани." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Сите " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "лиценца." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Прелом на страници" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "По" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Пред" @@ -5714,7 +5714,7 @@ msgstr "" "впуштите во разговор со други корисници. Луѓето можат да ви испраќаат пораки " "што ќе можете да ги видите само Вие." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "од" @@ -5842,48 +5842,48 @@ msgstr "" "Жалиме, но добивањето на Вашата местоположба трае подолго од очекуваното. " "Обидете се подоцна." -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "С" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "Ј" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "И" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "З" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "во" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "во контекст" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Повторено од" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Одговори на забелешкава" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Одговор" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Забелешката е повторена" @@ -6174,67 +6174,67 @@ msgstr "Уреди аватар" msgid "User actions" msgstr "Кориснички дејства" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Уреди нагодувања на профилот" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Уреди" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Испрати му директна порака на корисников" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Порака" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Модерирај" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "пред неколку секунди" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "пред една минута" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "пред %d минути" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "пред еден час" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "пред %d часа" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "пред еден ден" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "пред %d денови" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "пред еден месец" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "пред %d месеца" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "пред една година" diff --git a/locale/nb/LC_MESSAGES/statusnet.po b/locale/nb/LC_MESSAGES/statusnet.po index ab74ad1dce..5e48b86359 100644 --- a/locale/nb/LC_MESSAGES/statusnet.po +++ b/locale/nb/LC_MESSAGES/statusnet.po @@ -8,12 +8,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:26+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:54+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.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -167,8 +167,8 @@ msgstr "" msgid "You and friends" msgstr "Du og venner" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Oppdateringer fra %1$s og venner på %2$s!" @@ -189,12 +189,12 @@ msgstr "Oppdateringer fra %1$s og venner på %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "API-metode ikke funnet!" @@ -552,7 +552,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Konto" @@ -627,14 +627,14 @@ msgstr "" #: actions/apisubscriptions.php:231 actions/apisubscriptions.php:261 msgid "Unsupported format." -msgstr "" +msgstr "Formatet støttes ikke." #: actions/apitimelinefavorites.php:108 #, php-format msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Favoritter fra %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s oppdateringer markert som favoritt av %2$s / %2$s." @@ -645,7 +645,7 @@ msgstr "%1$s oppdateringer markert som favoritt av %2$s / %2$s." msgid "%s timeline" msgstr "%s tidslinje" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -661,12 +661,12 @@ msgstr "%1$s / Oppdateringer som nevner %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s oppdateringer som svarer på oppdateringer fra %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s offentlig tidslinje" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s oppdateringer fra alle sammen!" @@ -676,17 +676,17 @@ msgstr "%s oppdateringer fra alle sammen!" msgid "Repeated to %s" msgstr "Gjentatt til %s" -#: actions/apitimelineretweetsofme.php:112 -#, fuzzy, php-format +#: actions/apitimelineretweetsofme.php:114 +#, php-format msgid "Repeats of %s" -msgstr "Svar til %s" +msgstr "Repetisjoner av %s" #: actions/apitimelinetag.php:102 actions/tag.php:66 #, php-format msgid "Notices tagged with %s" msgstr "Notiser merket med %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Oppdateringer merket med %1$s på %2$s!" @@ -733,9 +733,8 @@ msgstr "" #: actions/avatarsettings.php:119 actions/avatarsettings.php:197 #: actions/grouplogo.php:251 -#, fuzzy msgid "Avatar settings" -msgstr "Innstillinger for IM" +msgstr "Avatarinnstillinger" #: actions/avatarsettings.php:127 actions/avatarsettings.php:205 #: actions/grouplogo.php:199 actions/grouplogo.php:259 @@ -748,7 +747,7 @@ msgid "Preview" msgstr "Forhåndsvis" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Slett" @@ -774,12 +773,11 @@ msgstr "Brukerbildet har blitt oppdatert." #: actions/avatarsettings.php:369 msgid "Failed updating avatar." -msgstr "" +msgstr "Oppdatering av avatar mislyktes." #: actions/avatarsettings.php:393 -#, fuzzy msgid "Avatar deleted." -msgstr "Brukerbildet har blitt oppdatert." +msgstr "Avatar slettet." #: actions/block.php:69 msgid "You already blocked that user." @@ -858,11 +856,11 @@ msgstr "" #: actions/bookmarklet.php:50 msgid "Post to " -msgstr "" +msgstr "Post til " #: actions/confirmaddress.php:75 msgid "No confirmation code." -msgstr "" +msgstr "Ingen bekreftelseskode." #: actions/confirmaddress.php:80 msgid "Confirmation code not found." @@ -879,7 +877,7 @@ msgstr "" #: actions/confirmaddress.php:94 msgid "That address has already been confirmed." -msgstr "" +msgstr "Den adressen har allerede blitt bekreftet." #: actions/confirmaddress.php:114 actions/emailsettings.php:296 #: actions/emailsettings.php:427 actions/imsettings.php:258 @@ -892,7 +890,7 @@ msgstr "Klarte ikke å oppdatere bruker." #: actions/confirmaddress.php:126 actions/emailsettings.php:391 #: actions/imsettings.php:363 actions/smssettings.php:382 msgid "Couldn't delete email confirmation." -msgstr "" +msgstr "Kunne ikke slette e-postbekreftelse." #: actions/confirmaddress.php:144 msgid "Confirm address" @@ -901,7 +899,7 @@ msgstr "Bekreft adresse" #: actions/confirmaddress.php:159 #, php-format msgid "The address \"%s\" has been confirmed for your account." -msgstr "" +msgstr "Adressen «%s» har blitt bekreftet for din konto." #: actions/conversation.php:99 msgid "Conversation" @@ -913,31 +911,27 @@ msgid "Notices" msgstr "" #: actions/deleteapplication.php:63 -#, fuzzy msgid "You must be logged in to delete an application." -msgstr "Gjør brukeren til en administrator for gruppen" +msgstr "Du må være innlogget for å slette et program." #: actions/deleteapplication.php:71 -#, fuzzy msgid "Application not found." -msgstr "Fant ikke bekreftelseskode." +msgstr "Program ikke funnet." #: actions/deleteapplication.php:78 actions/editapplication.php:77 #: actions/showapplication.php:94 -#, fuzzy msgid "You are not the owner of this application." -msgstr "Du er allerede logget inn!" +msgstr "Du er ikke eieren av dette programmet." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" #: actions/deleteapplication.php:123 actions/deleteapplication.php:147 -#, fuzzy msgid "Delete application" -msgstr "Ingen slik side" +msgstr "Slett program" #: actions/deleteapplication.php:149 msgid "" @@ -945,16 +939,17 @@ msgid "" "about the application from the database, including all existing user " "connections." msgstr "" +"Er du sikker på at du vil slette dette programmet? Dette vil slette alle " +"data om programmet fra databasen, inkludert alle eksisterende " +"brukertilkoblinger." #: actions/deleteapplication.php:156 -#, fuzzy msgid "Do not delete this application" -msgstr "Kan ikke slette notisen." +msgstr "Ikke slett dette programmet" #: actions/deleteapplication.php:160 -#, fuzzy msgid "Delete this application" -msgstr "Beskriv degselv og dine interesser med 140 tegn" +msgstr "Slett dette programmet" #: actions/deletenotice.php:67 actions/disfavor.php:61 actions/favor.php:62 #: actions/groupblock.php:61 actions/groupunblock.php:61 actions/logout.php:69 @@ -975,6 +970,8 @@ msgid "" "You are about to permanently delete a notice. Once this is done, it cannot " "be undone." msgstr "" +"Du er i ferd med å slette en notis permanent. Når dette er gjort kan det " +"ikke gjøres om." #: actions/deletenotice.php:109 actions/deletenotice.php:141 msgid "Delete notice" @@ -988,7 +985,7 @@ msgstr "Er du sikker på at du vil slette denne notisen?" msgid "Do not delete this notice" msgstr "Ikke slett denne notisen" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Slett denne notisen" @@ -1009,6 +1006,8 @@ msgid "" "Are you sure you want to delete this user? This will clear all data about " "the user from the database, without a backup." msgstr "" +"Er du sikker på at du vil slette denne brukeren? Dette vil slette alle data " +"om brukeren fra databasen, uten sikkerhetskopi." #: actions/deleteuser.php:148 lib/deleteuserform.php:77 msgid "Delete this user" @@ -1024,9 +1023,8 @@ msgid "Design settings for this StatusNet site." msgstr "" #: actions/designadminpanel.php:275 -#, fuzzy msgid "Invalid logo URL." -msgstr "Ugyldig størrelse" +msgstr "Ugyldig logo-URL." #: actions/designadminpanel.php:279 #, php-format @@ -1126,7 +1124,7 @@ msgstr "" #: actions/disfavor.php:81 msgid "This notice is not a favorite!" -msgstr "" +msgstr "Denne notisen er ikke en favoritt!" #: actions/disfavor.php:94 msgid "Add to favorites" @@ -1135,27 +1133,24 @@ msgstr "Legg til i favoritter" #: actions/doc.php:158 #, php-format msgid "No such document \"%s\"" -msgstr "" +msgstr "Inget slikt dokument «%s»" #: actions/editapplication.php:54 -#, fuzzy msgid "Edit Application" -msgstr "Ingen slik side" +msgstr "Rediger program" #: actions/editapplication.php:66 -#, fuzzy msgid "You must be logged in to edit an application." -msgstr "Gjør brukeren til en administrator for gruppen" +msgstr "Du må være innlogget for å redigere et program." #: actions/editapplication.php:81 actions/oauthconnectionssettings.php:166 #: actions/showapplication.php:87 -#, fuzzy msgid "No such application." -msgstr "Ingen slik side" +msgstr "Inget slikt program." #: actions/editapplication.php:161 msgid "Use this form to edit your application." -msgstr "" +msgstr "Bruk dette skjemaet for å redigere programmet ditt." #: actions/editapplication.php:177 actions/newapplication.php:159 msgid "Name is required." @@ -1234,7 +1229,7 @@ msgstr "beskrivelse er for lang (maks %d tegn)" msgid "Could not update group." msgstr "Kunne ikke oppdatere gruppe." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Kunne ikke opprette alias." @@ -1243,9 +1238,8 @@ msgid "Options saved." msgstr "" #: actions/emailsettings.php:60 -#, fuzzy msgid "Email settings" -msgstr "Innstillinger for e-post" +msgstr "E-postinnstillinger" #: actions/emailsettings.php:71 #, php-format @@ -1403,7 +1397,7 @@ msgstr "Det er ikke din e-postadresse." #: actions/emailsettings.php:432 actions/imsettings.php:408 #: actions/smssettings.php:425 msgid "The address was removed." -msgstr "" +msgstr "Adressen ble fjernet." #: actions/emailsettings.php:446 actions/smssettings.php:518 msgid "No incoming email address." @@ -1433,12 +1427,12 @@ msgstr "" #: actions/favorited.php:65 lib/popularnoticesection.php:91 #: lib/publicgroupnav.php:93 msgid "Popular notices" -msgstr "" +msgstr "Populære notiser" #: actions/favorited.php:67 #, php-format msgid "Popular notices, page %d" -msgstr "" +msgstr "Populære notiser, side %d" #: actions/favorited.php:79 msgid "The most popular notices on the site right now." @@ -1669,7 +1663,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "En liste over brukerne i denne gruppen." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2027,7 +2021,7 @@ msgstr "Feil brukernavn eller passord" msgid "Error setting user. You are probably not authorized." msgstr "Ikke autorisert." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Logg inn" @@ -2272,7 +2266,7 @@ msgid "Only " msgstr "Bare " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -2965,7 +2959,7 @@ msgstr "" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -3108,7 +3102,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "" @@ -3146,7 +3140,7 @@ msgstr "" msgid "You already repeated that notice." msgstr "Du er allerede logget inn!" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Gjentatt" @@ -4266,7 +4260,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Personlig" @@ -4352,20 +4346,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4375,12 +4369,12 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 #, fuzzy msgid "Could not create group." msgstr "Klarte ikke å lagre avatar-informasjonen" -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "Klarte ikke å lagre avatar-informasjonen" @@ -4423,126 +4417,126 @@ msgstr "%1$s sin status på %2$s" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Hjem" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Koble til" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Logg ut" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "Opprett en ny konto" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Hjelp" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "Hjelp" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Søk" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Om" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "OSS/FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Kilde" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4551,12 +4545,12 @@ msgstr "" "**%%site.name%%** er en mikrobloggingtjeneste av [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** er en mikrobloggingtjeneste. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4564,41 +4558,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "Tidligere »" @@ -5458,7 +5452,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr "fra" @@ -5583,50 +5577,50 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Opprett" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 #, fuzzy msgid "Reply" msgstr "svar" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Nytt nick" @@ -5931,68 +5925,68 @@ msgstr "Brukerbilde" msgid "User actions" msgstr "" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "Endre profilinnstillingene dine" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "noen få sekunder siden" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "omtrent ett minutt siden" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "omtrent %d minutter siden" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "omtrent én time siden" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "omtrent %d timer siden" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "omtrent én dag siden" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "omtrent %d dager siden" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "omtrent én måned siden" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "omtrent %d måneder siden" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "omtrent ett år siden" diff --git a/locale/nl/LC_MESSAGES/statusnet.po b/locale/nl/LC_MESSAGES/statusnet.po index b1a54d06a2..54c042b2ff 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:32+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:00+0000\n" "Language-Team: Dutch\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -171,8 +171,8 @@ msgstr "" msgid "You and friends" msgstr "U en vrienden" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Updates van %1$s en vrienden op %2$s." @@ -193,12 +193,12 @@ msgstr "Updates van %1$s en vrienden op %2$s." #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "De API-functie is niet aangetroffen." @@ -572,7 +572,7 @@ msgstr "" "van het type \"%3$s tot uw gebruikersgegevens. Geef alleen " "toegang tot uw gebruiker bij %4$s aan derde partijen die u vertrouwt." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Gebruiker" @@ -656,7 +656,7 @@ msgstr "Niet-ondersteund bestandsformaat." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Favorieten van %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s updates op de favorietenlijst geplaatst door %2$s / %3$s" @@ -667,7 +667,7 @@ msgstr "%1$s updates op de favorietenlijst geplaatst door %2$s / %3$s" msgid "%s timeline" msgstr "%s tijdlijn" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -683,12 +683,12 @@ msgstr "%1$s / Updates over %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s updates die een reactie zijn op updates van %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s publieke tijdlijn" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s updates van iedereen" @@ -698,7 +698,7 @@ msgstr "%s updates van iedereen" msgid "Repeated to %s" msgstr "Herhaald naar %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Herhaald van %s" @@ -708,7 +708,7 @@ msgstr "Herhaald van %s" msgid "Notices tagged with %s" msgstr "Mededelingen met het label %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Updates met het label %1$s op %2$s!" @@ -770,7 +770,7 @@ msgid "Preview" msgstr "Voorvertoning" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Verwijderen" @@ -952,7 +952,7 @@ msgstr "U bent niet de eigenaar van deze applicatie." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Er is een probleem met uw sessietoken." @@ -1012,7 +1012,7 @@ msgstr "Weet u zeker dat u deze aankondiging wilt verwijderen?" msgid "Do not delete this notice" msgstr "Deze mededeling niet verwijderen" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Deze mededeling verwijderen" @@ -1254,7 +1254,7 @@ msgstr "de beschrijving is te lang (maximaal %d tekens)" msgid "Could not update group." msgstr "Het was niet mogelijk de groep bij te werken." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Het was niet mogelijk de aliassen aan te maken." @@ -1705,7 +1705,7 @@ msgstr "%1$s groeps leden, pagina %2$d" msgid "A list of the users in this group." msgstr "Ledenlijst van deze groep" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Beheerder" @@ -2095,7 +2095,7 @@ msgstr "" "Er is een fout opgetreden bij het maken van de instellingen. U hebt " "waarschijnlijk niet de juiste rechten." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Aanmelden" @@ -2355,7 +2355,7 @@ msgid "Only " msgstr "Alleen " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Geen ondersteund gegevensformaat." @@ -3068,7 +3068,7 @@ msgstr "Sorry. De uitnodigingscode is ongeldig." msgid "Registration successful" msgstr "De registratie is voltooid" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registreren" @@ -3217,7 +3217,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "De URL van uw profiel bij een andere, compatibele microblogdienst" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Abonneren" @@ -3255,7 +3255,7 @@ msgstr "U kunt uw eigen mededeling niet herhalen." msgid "You already repeated that notice." msgstr "U hent die mededeling al herhaald." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Herhaald" @@ -4440,7 +4440,7 @@ msgstr "" msgid "Plugins" msgstr "Plug-ins" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Versie" @@ -4535,23 +4535,23 @@ msgid "You are banned from posting notices on this site." msgstr "" "U bent geblokkeerd en mag geen mededelingen meer achterlaten op deze site." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Er is een probleem opgetreden bij het opslaan van de mededeling." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "" "Er is een probleem opgetreden bij het opslaan van het Postvak IN van de " "groep." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" "Er is een databasefout opgetreden bij het invoegen van het antwoord: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4561,11 +4561,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Welkom bij %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Het was niet mogelijk de groep aan te maken." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Het was niet mogelijk het groepslidmaatschap in te stellen." @@ -4606,124 +4606,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Naamloze pagina" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Primaire sitenavigatie" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Start" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Persoonlijk profiel en tijdlijn van vrienden" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Uw e-mailadres, avatar, wachtwoord of profiel wijzigen" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Koppelen" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Met diensten verbinden" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Websiteinstellingen wijzigen" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Uitnodigen" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Vrienden en collega's uitnodigen om u te vergezellen op %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Afmelden" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Van de site afmelden" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Gebruiker aanmaken" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Bij de site aanmelden" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Help" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Help me!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Zoeken" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Naar gebruikers of tekst zoeken" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Mededeling van de website" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Lokale weergaven" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Mededeling van de pagina" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Secundaire sitenavigatie" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Over" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Veel gestelde vragen" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "Gebruiksvoorwaarden" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privacy" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Broncode" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contact" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Widget" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licentie van de StatusNet-software" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4732,12 +4732,12 @@ msgstr "" "**%%site.name%%** is een microblogdienst van [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** is een microblogdienst. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4748,45 +4748,45 @@ msgstr "" "versie %s, beschikbaar onder de [GNU Affero General Public License](http://" "www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licentie voor siteinhoud" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Inhoud en gegevens van %1$s zijn persoonlijk en vertrouwelijk." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Auteursrechten op inhoud en gegevens rusten bij %1$s. Alle rechten " "voorbehouden." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Auteursrechten op inhoud en gegevens rusten bij de respectievelijke " "gebruikers. Alle rechten voorbehouden." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Alle " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licentie." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginering" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Later" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Eerder" @@ -5757,7 +5757,7 @@ msgstr "" "U hebt geen privéberichten. U kunt privéberichten verzenden aan andere " "gebruikers. Mensen kunnen u privéberichten sturen die alleen u kunt lezen." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "van" @@ -5885,48 +5885,48 @@ msgstr "" "Het ophalen van uw geolocatie duurt langer dan verwacht. Probeer het later " "nog eens" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "Z" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "O" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "W" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "op" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "in context" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Herhaald door" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Op deze mededeling antwoorden" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Antwoorden" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Mededeling herhaald" @@ -6217,67 +6217,67 @@ msgstr "Avatar bewerken" msgid "User actions" msgstr "Gebruikershandelingen" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Profielinstellingen bewerken" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Bewerken" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Deze gebruiker een direct bericht zenden" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Bericht" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Modereren" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "een paar seconden geleden" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "ongeveer een minuut geleden" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "ongeveer %d minuten geleden" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "ongeveer een uur geleden" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "ongeveer %d uur geleden" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "ongeveer een dag geleden" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "ongeveer %d dagen geleden" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "ongeveer een maand geleden" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "ongeveer %d maanden geleden" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "ongeveer een jaar geleden" diff --git a/locale/nn/LC_MESSAGES/statusnet.po b/locale/nn/LC_MESSAGES/statusnet.po index e3e2cf80ed..b82d1f96a1 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:29+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:56:57+0000\n" "Language-Team: Norwegian Nynorsk\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -168,8 +168,8 @@ msgstr "" msgid "You and friends" msgstr "%s med vener" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Oppdateringar frå %1$s og vener på %2$s!" @@ -190,12 +190,12 @@ msgstr "Oppdateringar frå %1$s og vener på %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "Fann ikkje API-metode." @@ -565,7 +565,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Konto" @@ -652,7 +652,7 @@ msgstr "Støttar ikkje bileteformatet." msgid "%1$s / Favorites from %2$s" msgstr "%s / Favorittar frå %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s oppdateringar favorisert av %s / %s." @@ -663,7 +663,7 @@ msgstr "%s oppdateringar favorisert av %s / %s." msgid "%s timeline" msgstr "%s tidsline" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -679,12 +679,12 @@ msgstr "%1$s / Oppdateringar som svarar til %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s oppdateringar som svarar på oppdateringar frå %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s offentleg tidsline" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s oppdateringar frå alle saman!" @@ -694,7 +694,7 @@ msgstr "%s oppdateringar frå alle saman!" msgid "Repeated to %s" msgstr "Svar til %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "Svar til %s" @@ -704,7 +704,7 @@ msgstr "Svar til %s" msgid "Notices tagged with %s" msgstr "Notisar merka med %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Oppdateringar frå %1$s på %2$s!" @@ -766,7 +766,7 @@ msgid "Preview" msgstr "Forhandsvis" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Slett" @@ -955,7 +955,7 @@ msgstr "Du er ikkje medlem av den gruppa." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Det var eit problem med sesjons billetten din." @@ -1017,7 +1017,7 @@ msgstr "Sikker på at du vil sletta notisen?" msgid "Do not delete this notice" msgstr "Kan ikkje sletta notisen." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Slett denne notisen" @@ -1280,7 +1280,7 @@ msgstr "skildringa er for lang (maks 140 teikn)." msgid "Could not update group." msgstr "Kann ikkje oppdatera gruppa." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "Kunne ikkje lagre favoritt." @@ -1736,7 +1736,7 @@ msgstr "%s medlemmar i gruppa, side %d" msgid "A list of the users in this group." msgstr "Ei liste over brukarane i denne gruppa." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2110,7 +2110,7 @@ msgstr "Feil brukarnamn eller passord" msgid "Error setting user. You are probably not authorized." msgstr "Ikkje autorisert." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Logg inn" @@ -2371,7 +2371,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Ikkje eit støtta dataformat." @@ -3085,7 +3085,7 @@ msgstr "Feil med stadfestingskode." msgid "Registration successful" msgstr "Registreringa gikk bra" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrér" @@ -3235,7 +3235,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL til profilsida di på ei anna kompatibel mikrobloggingteneste." #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Ting" @@ -3278,7 +3278,7 @@ msgstr "Du kan ikkje registrera deg om du ikkje godtek vilkåra i lisensen." msgid "You already repeated that notice." msgstr "Du har allereie blokkert denne brukaren." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Lag" @@ -4429,7 +4429,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Personleg" @@ -4520,21 +4520,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Du kan ikkje lengre legge inn notisar på denne sida." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Eit problem oppstod ved lagring av notis." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Eit problem oppstod ved lagring av notis." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Databasefeil, kan ikkje lagra svar: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4544,11 +4544,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "Melding til %1$s på %2$s" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Kunne ikkje laga gruppa." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Kunne ikkje bli med i gruppa." @@ -4590,127 +4590,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Ingen tittel" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Navigasjon for hovudsida" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Heim" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Personleg profil og oversyn over vener" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Endra e-posten, avataren, passordet eller profilen" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Kopla til" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Klarte ikkje å omdirigera til tenaren: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Navigasjon for hovudsida" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitér" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Inviter vennar og kollega til å bli med deg på %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Logg ut" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Logg ut or sida" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Opprett ny konto" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Logg inn or sida" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Hjelp" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Hjelp meg!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Søk" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Søk etter folk eller innhald" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Statusmelding" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Lokale syningar" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Sidenotis" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Andrenivås side navigasjon" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Om" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "OSS" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Personvern" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Kjeldekode" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:751 +#: lib/action.php:752 #, fuzzy msgid "Badge" msgstr "Dult" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNets programvarelisens" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4719,12 +4719,12 @@ msgstr "" "**%%site.name%%** er ei mikrobloggingteneste av [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** er ei mikrobloggingteneste. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4735,42 +4735,42 @@ msgstr "" "%s, tilgjengeleg under [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "StatusNets programvarelisens" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Alle" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "lisens." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginering" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "« Etter" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Før »" @@ -5646,7 +5646,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr " frå " @@ -5770,51 +5770,51 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "Nei" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "Ingen innhald." -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Lag" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Svar på denne notisen" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Svar" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Melding lagra" @@ -6123,68 +6123,68 @@ msgstr "Brukarbilete" msgid "User actions" msgstr "Brukarverkty" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "Profilinnstillingar" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Send ei direktemelding til denne brukaren" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Melding" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "eit par sekund sidan" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "omtrent eitt minutt sidan" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "~%d minutt sidan" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "omtrent ein time sidan" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "~%d timar sidan" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "omtrent ein dag sidan" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "~%d dagar sidan" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "omtrent ein månad sidan" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "~%d månadar sidan" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "omtrent eitt år sidan" diff --git a/locale/pl/LC_MESSAGES/statusnet.po b/locale/pl/LC_MESSAGES/statusnet.po index a13f6362b4..a661850277 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:35+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:04+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.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -174,8 +174,8 @@ msgstr "" msgid "You and friends" msgstr "Ty i przyjaciele" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Aktualizacje z %1$s i przyjaciół na %2$s." @@ -196,12 +196,12 @@ msgstr "Aktualizacje z %1$s i przyjaciół na %2$s." #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Nie odnaleziono metody API." @@ -562,7 +562,7 @@ msgstr "" "uzyskać możliwość %3$s danych konta %4$s. Dostęp do konta %4" "$s powinien być udostępniany tylko zaufanym osobom trzecim." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Konto" @@ -644,7 +644,7 @@ msgstr "Nieobsługiwany format." msgid "%1$s / Favorites from %2$s" msgstr "%1$s/ulubione wpisy od %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "Użytkownik %1$s aktualizuje ulubione według %2$s/%2$s." @@ -655,7 +655,7 @@ msgstr "Użytkownik %1$s aktualizuje ulubione według %2$s/%2$s." msgid "%s timeline" msgstr "Oś czasu użytkownika %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -671,12 +671,12 @@ msgstr "%1$s/aktualizacje wspominające %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s aktualizuje tę odpowiedź na aktualizacje od %2$s/%3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Publiczna oś czasu użytkownika %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "Użytkownik %s aktualizuje od każdego." @@ -686,7 +686,7 @@ msgstr "Użytkownik %s aktualizuje od każdego." msgid "Repeated to %s" msgstr "Powtórzone dla %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Powtórzenia %s" @@ -696,7 +696,7 @@ msgstr "Powtórzenia %s" msgid "Notices tagged with %s" msgstr "Wpisy ze znacznikiem %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Aktualizacje ze znacznikiem %1$s na %2$s." @@ -757,7 +757,7 @@ msgid "Preview" msgstr "Podgląd" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Usuń" @@ -938,7 +938,7 @@ msgstr "Nie jesteś właścicielem tej aplikacji." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Wystąpił problem z tokenem sesji." @@ -997,7 +997,7 @@ msgstr "Jesteś pewien, że chcesz usunąć ten wpis?" msgid "Do not delete this notice" msgstr "Nie usuwaj tego wpisu" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Usuń ten wpis" @@ -1236,7 +1236,7 @@ msgstr "opis jest za długi (maksymalnie %d znaków)." msgid "Could not update group." msgstr "Nie można zaktualizować grupy." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Nie można utworzyć aliasów." @@ -1675,7 +1675,7 @@ msgstr "Członkowie grupy %1$s, strona %2$d" msgid "A list of the users in this group." msgstr "Lista użytkowników znajdujących się w tej grupie." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2059,7 +2059,7 @@ msgstr "Niepoprawna nazwa użytkownika lub hasło." msgid "Error setting user. You are probably not authorized." msgstr "Błąd podczas ustawiania użytkownika. Prawdopodobnie brak upoważnienia." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Zaloguj się" @@ -2315,7 +2315,7 @@ msgid "Only " msgstr "Tylko " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "To nie jest obsługiwany format danych." @@ -3019,7 +3019,7 @@ msgstr "Nieprawidłowy kod zaproszenia." msgid "Registration successful" msgstr "Rejestracja powiodła się" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Zarejestruj się" @@ -3169,7 +3169,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Adres URL profilu na innej, zgodnej usłudze mikroblogowania" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Subskrybuj" @@ -3207,7 +3207,7 @@ msgstr "Nie można powtórzyć własnego wpisu." msgid "You already repeated that notice." msgstr "Już powtórzono ten wpis." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Powtórzono" @@ -4380,7 +4380,7 @@ msgstr "" msgid "Plugins" msgstr "Wtyczki" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Wersja" @@ -4471,20 +4471,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Zabroniono ci wysyłania wpisów na tej witrynie." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problem podczas zapisywania wpisu." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Problem podczas zapisywania skrzynki odbiorczej grupy." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Błąd bazy danych podczas wprowadzania odpowiedzi: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4494,11 +4494,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Witaj w %1$s, @%2$s." -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Nie można utworzyć grupy." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Nie można ustawić członkostwa w grupie." @@ -4539,124 +4539,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Strona bez nazwy" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Główna nawigacja witryny" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Strona domowa" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Profil osobisty i oś czasu przyjaciół" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Zmień adres e-mail, awatar, hasło, profil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Połącz" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Połącz z serwisami" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Zmień konfigurację witryny" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Zaproś" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Zaproś przyjaciół i kolegów do dołączenia do ciebie na %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Wyloguj się" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Wyloguj się z witryny" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Utwórz konto" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Zaloguj się na witrynie" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Pomoc" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Pomóż mi." -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Wyszukaj" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Wyszukaj osoby lub tekst" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Wpis witryny" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Lokalne widoki" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Wpis strony" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Druga nawigacja witryny" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "O usłudze" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "TOS" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Prywatność" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Kod źródłowy" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Odznaka" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licencja oprogramowania StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4665,12 +4665,12 @@ msgstr "" "**%%site.name%%** jest usługą mikroblogowania prowadzoną przez [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** jest usługą mikroblogowania. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4681,45 +4681,45 @@ msgstr "" "status.net/) w wersji %s, dostępnego na [Powszechnej Licencji Publicznej GNU " "Affero](http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licencja zawartości witryny" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Treść i dane %1$s są prywatne i poufne." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Prawa autorskie do treści i danych są własnością %1$s. Wszystkie prawa " "zastrzeżone." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Prawa autorskie do treści i danych są własnością współtwórców. Wszystkie " "prawa zastrzeżone." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Wszystko " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licencja." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginacja" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Później" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Wcześniej" @@ -5688,7 +5688,7 @@ msgstr "" "rozmowę z innymi użytkownikami. Inni mogą wysyłać ci wiadomości tylko dla " "twoich oczu." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "z" @@ -5811,48 +5811,48 @@ msgstr "" "Pobieranie danych geolokalizacji trwa dłużej niż powinno, proszę spróbować " "ponownie później" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "Północ" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "Południe" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "Wschód" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "Zachód" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "w" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "w rozmowie" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Powtórzone przez" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Odpowiedz na ten wpis" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Odpowiedz" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Powtórzono wpis" @@ -6143,67 +6143,67 @@ msgstr "Zmodyfikuj awatar" msgid "User actions" msgstr "Czynności użytkownika" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Zmodyfikuj ustawienia profilu" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Edycja" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Wyślij bezpośrednią wiadomość do tego użytkownika" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Wiadomość" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Moderuj" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "kilka sekund temu" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "około minutę temu" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "około %d minut temu" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "około godzinę temu" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "około %d godzin temu" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "blisko dzień temu" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "około %d dni temu" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "około miesiąc temu" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "około %d miesięcy temu" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "około rok temu" diff --git a/locale/pt/LC_MESSAGES/statusnet.po b/locale/pt/LC_MESSAGES/statusnet.po index a2c8fd60cc..7b700eded3 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:39+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:07+0000\n" "Language-Team: Portuguese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -171,8 +171,8 @@ msgstr "" msgid "You and friends" msgstr "Você e seus amigos" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Actualizações de %1$s e amigos no %2$s!" @@ -193,12 +193,12 @@ msgstr "Actualizações de %1$s e amigos no %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Método da API não encontrado." @@ -558,7 +558,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Conta" @@ -642,7 +642,7 @@ msgstr "Formato não suportado." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Favoritas de %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s actualizações preferidas por %2$s / %2$s." @@ -653,7 +653,7 @@ msgstr "%1$s actualizações preferidas por %2$s / %2$s." msgid "%s timeline" msgstr "Notas de %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -669,12 +669,12 @@ msgstr "%1$s / Actualizações que mencionam %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s actualizações em resposta a actualizações de %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "Notas públicas de %s" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s actualizações de todos!" @@ -684,7 +684,7 @@ msgstr "%s actualizações de todos!" msgid "Repeated to %s" msgstr "Repetida para %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Repetências de %s" @@ -694,7 +694,7 @@ msgstr "Repetências de %s" msgid "Notices tagged with %s" msgstr "Notas categorizadas com %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Actualizações categorizadas com %1$s em %2$s!" @@ -755,7 +755,7 @@ msgid "Preview" msgstr "Antevisão" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Apagar" @@ -940,7 +940,7 @@ msgstr "Não é membro deste grupo." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Ocorreu um problema com a sua sessão." @@ -1003,7 +1003,7 @@ msgstr "Tem a certeza de que quer apagar esta nota?" msgid "Do not delete this notice" msgstr "Não apagar esta nota" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Apagar esta nota" @@ -1256,7 +1256,7 @@ msgstr "descrição é demasiada extensa (máx. %d caracteres)." msgid "Could not update group." msgstr "Não foi possível actualizar o grupo." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Não foi possível criar sinónimos." @@ -1702,7 +1702,7 @@ msgstr "Membros do grupo %1$s, página %2$d" msgid "A list of the users in this group." msgstr "Uma lista dos utilizadores neste grupo." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Gestor" @@ -2086,7 +2086,7 @@ msgstr "Nome de utilizador ou senha incorrectos." msgid "Error setting user. You are probably not authorized." msgstr "Erro ao preparar o utilizador. Provavelmente não está autorizado." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Entrar" @@ -2348,7 +2348,7 @@ msgid "Only " msgstr "Apenas " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Formato de dados não suportado." @@ -3061,7 +3061,7 @@ msgstr "Desculpe, código de convite inválido." msgid "Registration successful" msgstr "Registo efectuado" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registar" @@ -3210,7 +3210,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL do seu perfil noutro serviço de microblogues compatível" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Subscrever" @@ -3248,7 +3248,7 @@ msgstr "Não pode repetir a sua própria nota." msgid "You already repeated that notice." msgstr "Já repetiu essa nota." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Repetida" @@ -4424,7 +4424,7 @@ msgstr "" msgid "Plugins" msgstr "Plugins" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Versão" @@ -4516,21 +4516,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Está proibido de publicar notas neste site." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problema na gravação da nota." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Problema na gravação da nota." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Ocorreu um erro na base de dados ao inserir a resposta: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4540,11 +4540,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "%1$s dá-lhe as boas-vindas, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Não foi possível criar o grupo." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Não foi possível configurar membros do grupo." @@ -4585,124 +4585,124 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Página sem título" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Navegação primária deste site" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Início" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Perfil pessoal e notas dos amigos" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Altere o seu endereço electrónico, avatar, senha, perfil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Ligar" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Ligar aos serviços" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Alterar a configuração do site" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Convidar" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Convidar amigos e colegas para se juntarem a si em %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Sair" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Terminar esta sessão" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Criar uma conta" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Iniciar uma sessão" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Ajuda" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Ajudem-me!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Pesquisa" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Procurar pessoas ou pesquisar texto" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Aviso do site" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Vistas locais" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Aviso da página" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Navegação secundária deste site" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Sobre" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "Termos" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privacidade" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Código" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contacto" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Emblema" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licença de software do StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4711,12 +4711,12 @@ msgstr "" "**%%site.name%%** é um serviço de microblogues disponibilizado por [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** é um serviço de microblogues. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4727,41 +4727,41 @@ msgstr "" "disponibilizado nos termos da [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licença de conteúdos do site" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Tudo " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licença." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginação" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Posteriores" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Anteriores" @@ -5727,7 +5727,7 @@ msgstr "" "conversa com outros utilizadores. Outros podem enviar-lhe mensagens, a que " "só você terá acesso." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "de" @@ -5852,48 +5852,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "S" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "E" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "O" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "coords." -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "no contexto" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Repetida por" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Responder a esta nota" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Responder" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Nota repetida" @@ -6183,67 +6183,67 @@ msgstr "Editar Avatar" msgid "User actions" msgstr "Acções do utilizador" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Editar configurações do perfil" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Editar" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Enviar mensagem directa a este utilizador" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Mensagem" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Moderar" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "há alguns segundos" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "há cerca de um minuto" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "há cerca de %d minutos" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "há cerca de uma hora" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "há cerca de %d horas" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "há cerca de um dia" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "há cerca de %d dias" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "há cerca de um mês" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "há cerca de %d meses" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "há cerca de um ano" diff --git a/locale/pt_BR/LC_MESSAGES/statusnet.po b/locale/pt_BR/LC_MESSAGES/statusnet.po index b9ffc361b4..0d3d92e18b 100644 --- a/locale/pt_BR/LC_MESSAGES/statusnet.po +++ b/locale/pt_BR/LC_MESSAGES/statusnet.po @@ -11,12 +11,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-14 20:05+0000\n" -"PO-Revision-Date: 2010-02-14 20:07:20+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:10+0000\n" "Language-Team: Brazilian Portuguese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62476); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -195,11 +195,11 @@ msgstr "Atualizações de %1$s e amigos no %2$s!" #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 #: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 -#: actions/apitimelinegroup.php:182 actions/apitimelinehome.php:184 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 #: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 #: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 -#: actions/apitimelineuser.php:194 actions/apiusershow.php:101 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "O método da API não foi encontrado!" @@ -567,7 +567,7 @@ msgstr "" "fornecer acesso à sua conta %4$s somente para terceiros nos quais você " "confia." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Conta" @@ -763,7 +763,7 @@ msgid "Preview" msgstr "Visualização" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Excluir" @@ -945,7 +945,7 @@ msgstr "Você não é o dono desta aplicação." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Ocorreu um problema com o seu token de sessão." @@ -1005,7 +1005,7 @@ msgstr "Tem certeza que deseja excluir esta mensagem?" msgid "Do not delete this notice" msgstr "Não excluir esta mensagem." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Excluir esta mensagem" @@ -1694,7 +1694,7 @@ msgstr "Membros do grupo %1$s, pág. %2$d" msgid "A list of the users in this group." msgstr "Uma lista dos usuários deste grupo." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2081,7 +2081,7 @@ msgid "Error setting user. You are probably not authorized." msgstr "" "Erro na configuração do usuário. Você provavelmente não tem autorização." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Entrar" @@ -2343,7 +2343,7 @@ msgid "Only " msgstr "Apenas " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Não é um formato de dados suportado." @@ -3053,7 +3053,7 @@ msgstr "Desculpe, mas o código do convite é inválido." msgid "Registration successful" msgstr "Registro realizado com sucesso" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrar-se" @@ -3202,7 +3202,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL do seu perfil em outro serviço de microblog compatível" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Assinar" @@ -3239,7 +3239,7 @@ msgstr "Você não pode repetir sua própria mensagem." msgid "You already repeated that notice." msgstr "Você já repetiu essa mensagem." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Repetida" @@ -3254,9 +3254,9 @@ msgid "Replies to %s" msgstr "Respostas para %s" #: actions/replies.php:127 -#, fuzzy, php-format +#, php-format msgid "Replies to %1$s, page %2$d" -msgstr "Respostas para %1$s no %2$s" +msgstr "Respostas para %1$s, pág. %2$d" #: actions/replies.php:144 #, php-format @@ -3324,9 +3324,8 @@ msgid "Sessions" msgstr "Sessões" #: actions/sessionsadminpanel.php:65 -#, fuzzy msgid "Session settings for this StatusNet site." -msgstr "Configurações da aparência deste site StatusNet." +msgstr "Configurações da sessão deste site StatusNet." #: actions/sessionsadminpanel.php:175 msgid "Handle sessions" @@ -4418,7 +4417,7 @@ msgstr "" msgid "Plugins" msgstr "Plugins" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Versão" @@ -4506,21 +4505,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Você está proibido de publicar mensagens neste site." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problema no salvamento da mensagem." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Problema no salvamento da mensagem." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Erro no banco de dados na inserção da reposta: %s" -#: classes/Notice.php:1271 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4575,124 +4574,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Página sem título" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Navegação primária no site" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Início" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Perfil pessoal e fluxo de mensagens dos amigos" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Mude seu e-mail, avatar, senha, perfil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Conectar" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Conecte-se a outros serviços" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Mude as configurações do site" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Convidar" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Convide seus amigos e colegas para unir-se a você no %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Sair" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Sai do site" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Cria uma conta" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Autentique-se no site" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Ajuda" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Ajudem-me!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Procurar" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Procura por pessoas ou textos" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Mensagem do site" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Visualizações locais" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Notícia da página" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Navegação secundária no site" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Sobre" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "Termos de uso" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Privacidade" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Fonte" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Contato" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Mini-aplicativo" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Licença do software StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4701,12 +4700,12 @@ msgstr "" "**%%site.name%%** é um serviço de microblog disponibilizado por [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** é um serviço de microblog. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4717,43 +4716,43 @@ msgstr "" "versão %s, disponível sob a [GNU Affero General Public License] (http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licença do conteúdo do site" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "O conteúdo e os dados de %1$s são privados e confidenciais." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Conteúdo e dados licenciados sob %1$s. Todos os direitos reservados." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Conteúdo e dados licenciados pelos colaboradores. Todos os direitos " "reservados." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Todas " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licença." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Paginação" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Próximo" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Anterior" @@ -5717,7 +5716,7 @@ msgstr "" "privadas para envolver outras pessoas em uma conversa. Você também pode " "receber mensagens privadas." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "de" @@ -5845,48 +5844,48 @@ msgstr "" "Desculpe, mas recuperar a sua geolocalização está demorando mais que o " "esperado. Por favor, tente novamente mais tarde." -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "S" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "L" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "O" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "em" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "no contexto" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Repetida por" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Responder a esta mensagem" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Responder" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Mensagem repetida" @@ -6176,23 +6175,23 @@ msgstr "Editar o avatar" msgid "User actions" msgstr "Ações do usuário" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Editar as configurações do perfil" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Editar" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Enviar uma mensagem para este usuário." -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Mensagem" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Moderar" diff --git a/locale/ru/LC_MESSAGES/statusnet.po b/locale/ru/LC_MESSAGES/statusnet.po index da1345a0d6..e1dd38e99f 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-02-14 20:05+0000\n" -"PO-Revision-Date: 2010-02-14 20:07:23+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:13+0000\n" "Language-Team: Russian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62476); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -196,11 +196,11 @@ msgstr "Обновлено от %1$s и его друзей на %2$s!" #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 #: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 -#: actions/apitimelinegroup.php:182 actions/apitimelinehome.php:184 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 #: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 #: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 -#: actions/apitimelineuser.php:194 actions/apiusershow.php:101 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "Метод API не найден." @@ -565,7 +565,7 @@ msgstr "" "предоставлять разрешение на доступ к вашей учётной записи %4$s только тем " "сторонним приложениям, которым вы доверяете." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Настройки" @@ -761,7 +761,7 @@ msgid "Preview" msgstr "Просмотр" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Удалить" @@ -942,7 +942,7 @@ msgstr "Вы не являетесь владельцем этого прило #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Проблема с Вашей сессией. Попробуйте ещё раз, пожалуйста." @@ -1002,7 +1002,7 @@ msgstr "Вы уверены, что хотите удалить эту запи msgid "Do not delete this notice" msgstr "Не удалять эту запись" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Удалить эту запись" @@ -1695,7 +1695,7 @@ msgstr "Участники группы %1$s, страница %2$d" msgid "A list of the users in this group." msgstr "Список пользователей, являющихся членами этой группы." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Настройки" @@ -2081,7 +2081,7 @@ msgstr "Некорректное имя или пароль." msgid "Error setting user. You are probably not authorized." msgstr "Ошибка установки пользователя. Вы, вероятно, не авторизованы." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Вход" @@ -2335,7 +2335,7 @@ msgid "Only " msgstr "Только " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Неподдерживаемый формат данных." @@ -3036,7 +3036,7 @@ msgstr "Извините, неверный пригласительный код msgid "Registration successful" msgstr "Регистрация успешна!" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Регистрация" @@ -3188,7 +3188,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "Адрес URL твоего профиля на другом подходящем сервисе микроблогинга" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Подписаться" @@ -3224,7 +3224,7 @@ msgstr "Вы не можете повторить собственную зап msgid "You already repeated that notice." msgstr "Вы уже повторили эту запись." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Повторено" @@ -4403,7 +4403,7 @@ msgstr "" msgid "Plugins" msgstr "Плагины" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Версия" @@ -4491,20 +4491,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Вам запрещено поститься на этом сайте (бан)" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Проблемы с сохранением записи." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Проблемы с сохранением входящих сообщений группы." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Ошибка баз данных при вставке ответа для %s" -#: classes/Notice.php:1271 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4559,124 +4559,124 @@ msgstr "%1$s — %2$s" msgid "Untitled page" msgstr "Страница без названия" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Главная навигация" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Моё" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Личный профиль и лента друзей" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Изменить ваш email, аватару, пароль, профиль" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Соединить" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Соединить с сервисами" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Изменить конфигурацию сайта" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Пригласить" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Пригласите друзей и коллег стать такими же как вы участниками %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Выход" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Выйти" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Создать новый аккаунт" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Войти" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Помощь" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Помощь" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Поиск" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Искать людей или текст" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Новая запись" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Локальные виды" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Новая запись" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Навигация по подпискам" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "О проекте" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "ЧаВо" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "TOS" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Пользовательское соглашение" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Исходный код" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Контактная информация" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Бедж" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNet лицензия" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4685,12 +4685,12 @@ msgstr "" "**%%site.name%%** — это сервис микроблогинга, созданный для вас при помощи [%" "%site.broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** — сервис микроблогинга. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4702,44 +4702,44 @@ msgstr "" "лицензией [GNU Affero General Public License](http://www.fsf.org/licensing/" "licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Лицензия содержимого сайта" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Содержание и данные %1$s являются личными и конфиденциальными." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Авторские права на содержание и данные принадлежат %1$s. Все права защищены." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Авторские права на содержание и данные принадлежат разработчикам. Все права " "защищены." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "All " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "license." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Разбиение на страницы" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Сюда" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Туда" @@ -5703,7 +5703,7 @@ msgstr "" "вовлечения других пользователей в разговор. Сообщения, получаемые от других " "людей, видите только вы." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "от " @@ -5828,48 +5828,48 @@ msgstr "" "К сожалению, получение информации о вашем местонахождении заняло больше " "времени, чем ожидалось; повторите попытку позже" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\" %4$s %5$u°%6$u'%7$u\" %8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "с. ш." -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "ю. ш." -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "в. д." -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "з. д." -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "на" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "в контексте" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Повторено" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Ответить на эту запись" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Ответить" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Запись повторена" @@ -6159,23 +6159,23 @@ msgstr "Изменить аватару" msgid "User actions" msgstr "Действия пользователя" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Изменение настроек профиля" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Редактировать" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Послать приватное сообщение этому пользователю." -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Сообщение" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Модерировать" diff --git a/locale/statusnet.po b/locale/statusnet.po index d1ee56f2ca..6fbf800659 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-02-14 20:05+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -181,11 +181,11 @@ msgstr "" #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 #: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 -#: actions/apitimelinegroup.php:182 actions/apitimelinehome.php:184 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 #: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 #: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 -#: actions/apitimelineuser.php:194 actions/apiusershow.php:101 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "" @@ -536,7 +536,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "" @@ -731,7 +731,7 @@ msgid "Preview" msgstr "" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "" @@ -909,7 +909,7 @@ msgstr "" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -964,7 +964,7 @@ msgstr "" msgid "Do not delete this notice" msgstr "" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "" @@ -1625,7 +1625,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -1955,7 +1955,7 @@ msgstr "" msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "" @@ -2196,7 +2196,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -2873,7 +2873,7 @@ msgstr "" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -2997,7 +2997,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "" @@ -3033,7 +3033,7 @@ msgstr "" msgid "You already repeated that notice." msgstr "" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "" @@ -4119,7 +4119,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "" @@ -4201,20 +4201,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1271 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4269,136 +4269,136 @@ msgstr "" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%). " msgstr "" -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4406,41 +4406,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "" @@ -5266,7 +5266,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "" @@ -5386,48 +5386,48 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "" @@ -5717,23 +5717,23 @@ msgstr "" msgid "User actions" msgstr "" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" diff --git a/locale/sv/LC_MESSAGES/statusnet.po b/locale/sv/LC_MESSAGES/statusnet.po index a0d407c5c8..cc959b8eaf 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:15:57+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:16+0000\n" "Language-Team: Swedish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -169,8 +169,8 @@ msgstr "" msgid "You and friends" msgstr "Du och vänner" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Uppdateringar från %1$s och vänner på %2$s!" @@ -191,12 +191,12 @@ msgstr "Uppdateringar från %1$s och vänner på %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "API-metod hittades inte." @@ -553,7 +553,7 @@ msgstr "" "möjligheten att %3$s din %4$s kontoinformation. Du bör bara " "ge tillgång till ditt %4$s-konto till tredje-parter du litar på." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Konto" @@ -635,7 +635,7 @@ msgstr "Format som inte stödjs." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Favoriter från %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s uppdateringar markerade som favorit av %2$s / %2$s." @@ -646,7 +646,7 @@ msgstr "%1$s uppdateringar markerade som favorit av %2$s / %2$s." msgid "%s timeline" msgstr "%s tidslinje" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -662,12 +662,12 @@ msgstr "%1$s / Uppdateringar som nämner %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s uppdateringar med svar på uppdatering från %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s publika tidslinje" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s uppdateringar från alla!" @@ -677,7 +677,7 @@ msgstr "%s uppdateringar från alla!" msgid "Repeated to %s" msgstr "Upprepat till %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Upprepningar av %s" @@ -687,7 +687,7 @@ msgstr "Upprepningar av %s" msgid "Notices tagged with %s" msgstr "Notiser taggade med %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Uppdateringar taggade med %1$s på %2$s!" @@ -749,7 +749,7 @@ msgid "Preview" msgstr "Förhandsgranska" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Ta bort" @@ -931,7 +931,7 @@ msgstr "Du är inte ägaren av denna applikation." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Det var ett problem med din sessions-token." @@ -991,7 +991,7 @@ msgstr "Är du säker på att du vill ta bort denna notis?" msgid "Do not delete this notice" msgstr "Ta inte bort denna notis" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Ta bort denna notis" @@ -1232,7 +1232,7 @@ msgstr "beskrivning är för lång (max %d tecken)." msgid "Could not update group." msgstr "Kunde inte uppdatera grupp." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Kunde inte skapa alias." @@ -1674,7 +1674,7 @@ msgstr "%1$s gruppmedlemmar, sida %2$d" msgid "A list of the users in this group." msgstr "En lista av användarna i denna grupp." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Administratör" @@ -2059,7 +2059,7 @@ msgstr "Felaktigt användarnamn eller lösenord." msgid "Error setting user. You are probably not authorized." msgstr "Fel vid inställning av användare. Du har sannolikt inte tillstånd." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Logga in" @@ -2315,7 +2315,7 @@ msgid "Only " msgstr "Bara " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Ett dataformat som inte stödjs" @@ -3019,7 +3019,7 @@ msgstr "Tyvärr, ogiltig inbjudningskod." msgid "Registration successful" msgstr "Registreringen genomförd" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrera" @@ -3171,7 +3171,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL till din profil på en annan kompatibel mikrobloggtjänst" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Prenumerera" @@ -3209,7 +3209,7 @@ msgstr "Du kan inte upprepa din egna notis." msgid "You already repeated that notice." msgstr "Du har redan upprepat denna notis." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Upprepad" @@ -4382,7 +4382,7 @@ msgstr "" msgid "Plugins" msgstr "Insticksmoduler" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Version" @@ -4470,20 +4470,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Du är utestängd från att posta notiser på denna webbplats." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Problem med att spara notis." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Problem med att spara gruppinkorg." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Databasfel vid infogning av svar: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4493,11 +4493,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Välkommen till %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Kunde inte skapa grupp." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Kunde inte ställa in gruppmedlemskap." @@ -4538,124 +4538,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Namnlös sida" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Primär webbplatsnavigation" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Hem" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Personlig profil och vänners tidslinje" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Ändra din e-post, avatar, lösenord, profil" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Anslut" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "Anslut till tjänster" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Ändra webbplatskonfiguration" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Bjud in" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Bjud in vänner och kollegor att gå med dig på %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Logga ut" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Logga ut från webbplatsen" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Skapa ett konto" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Logga in på webbplatsen" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Hjälp" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Hjälp mig!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Sök" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Sök efter personer eller text" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Webbplatsnotis" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Lokala vyer" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Sidnotis" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Sekundär webbplatsnavigation" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Om" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "Frågor & svar" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "Användarvillkor" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Sekretess" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Källa" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Emblem" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Programvarulicens för StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4664,12 +4664,12 @@ msgstr "" "**%%site.name%%** är en mikrobloggtjänst tillhandahållen av [%%site.broughtby" "%%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** är en mikrobloggtjänst. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4680,42 +4680,42 @@ msgstr "" "version %s, tillgänglig under [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Licens för webbplatsinnehåll" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Innehåll och data av %1$s är privat och konfidensiell." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Innehåll och data copyright av %1$s. Alla rättigheter reserverade." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Innehåll och data copyright av medarbetare. Alla rättigheter reserverade." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Alla " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "licens." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Numrering av sidor" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Senare" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Tidigare" @@ -5673,7 +5673,7 @@ msgstr "" "engagera andra användare i konversationen. Folk kan skicka meddelanden till " "dig som bara du ser." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "från" @@ -5799,48 +5799,48 @@ msgstr "" "Tyvärr, hämtning av din geografiska plats tar längre tid än förväntat, var " "god försök igen senare" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "N" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "S" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "Ö" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "V" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "på" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "i sammanhang" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Upprepad av" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Svara på denna notis" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Svara" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Notis upprepad" @@ -6130,67 +6130,67 @@ msgstr "Redigera avatar" msgid "User actions" msgstr "Åtgärder för användare" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Redigera profilinställningar" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Redigera" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Skicka ett direktmeddelande till denna användare" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Meddelande" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Moderera" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "ett par sekunder sedan" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "för nån minut sedan" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "för %d minuter sedan" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "för en timma sedan" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "för %d timmar sedan" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "för en dag sedan" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "för %d dagar sedan" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "för en månad sedan" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "för %d månader sedan" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "för ett år sedan" diff --git a/locale/te/LC_MESSAGES/statusnet.po b/locale/te/LC_MESSAGES/statusnet.po index 85719532b8..fce5e5d696 100644 --- a/locale/te/LC_MESSAGES/statusnet.po +++ b/locale/te/LC_MESSAGES/statusnet.po @@ -8,12 +8,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:16:03+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:19+0000\n" "Language-Team: Telugu\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -163,8 +163,8 @@ msgstr "" msgid "You and friends" msgstr "మీరు మరియు మీ స్నేహితులు" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -185,12 +185,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "నిర్ధారణ సంకేతం కనబడలేదు." @@ -551,7 +551,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "ఖాతా" @@ -633,7 +633,7 @@ msgstr "" msgid "%1$s / Favorites from %2$s" msgstr "" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s యొక్క మైక్రోబ్లాగు" @@ -644,7 +644,7 @@ msgstr "%s యొక్క మైక్రోబ్లాగు" msgid "%s timeline" msgstr "%s కాలరేఖ" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -660,12 +660,12 @@ msgstr "" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s బహిరంగ కాలరేఖ" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "అందరి నుండి %s తాజాకరణలు!" @@ -675,7 +675,7 @@ msgstr "అందరి నుండి %s తాజాకరణలు!" msgid "Repeated to %s" msgstr "%sకి స్పందనలు" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "%s యొక్క పునరావృతాలు" @@ -685,7 +685,7 @@ msgstr "%s యొక్క పునరావృతాలు" msgid "Notices tagged with %s" msgstr "" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "%s యొక్క మైక్రోబ్లాగు" @@ -747,7 +747,7 @@ msgid "Preview" msgstr "మునుజూపు" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "తొలగించు" @@ -927,7 +927,7 @@ msgstr "మీరు ఈ ఉపకరణం యొక్క యజమాని #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -984,7 +984,7 @@ msgstr "మీరు నిజంగానే ఈ నోటీసుని త msgid "Do not delete this notice" msgstr "ఈ నోటీసుని తొలగించకు" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "ఈ నోటీసుని తొలగించు" @@ -1227,7 +1227,7 @@ msgstr "వివరణ చాలా పెద్దదిగా ఉంది (1 msgid "Could not update group." msgstr "గుంపుని తాజాకరించలేకున్నాం." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "మారుపేర్లని సృష్టించలేకపోయాం." @@ -1657,7 +1657,7 @@ msgstr "%1$s గుంపు సభ్యులు, పేజీ %2$d" msgid "A list of the users in this group." msgstr "ఈ గుంపులో వాడుకరులు జాబితా." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -1996,7 +1996,7 @@ msgstr "వాడుకరిపేరు లేదా సంకేతపదం msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "ప్రవేశించండి" @@ -2247,7 +2247,7 @@ msgid "Only " msgstr "మాత్రమే " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -2947,7 +2947,7 @@ msgstr "క్షమించండి, తప్పు ఆహ్వాన స msgid "Registration successful" msgstr "నమోదు విజయవంతం" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "నమోదు" @@ -3084,7 +3084,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "చందాచేరు" @@ -3123,7 +3123,7 @@ msgstr "ఈ లైసెన్సుకి అంగీకరించకపో msgid "You already repeated that notice." msgstr "మీరు ఇప్పటికే ఆ వాడుకరిని నిరోధించారు." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "సృష్టితం" @@ -4232,7 +4232,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "సంచిక" @@ -4316,21 +4316,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "ఈ సైటులో నోటీసులు రాయడం నుండి మిమ్మల్ని నిషేధించారు." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "సందేశాన్ని భద్రపరచడంలో పొరపాటు." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "సందేశాన్ని భద్రపరచడంలో పొరపాటు." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4340,11 +4340,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "@%2$s, %1$sకి స్వాగతం!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "గుంపుని సృష్టించలేకపోయాం." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "గుంపు సభ్యత్వాన్ని అమర్చలేకపోయాం." @@ -4386,126 +4386,126 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "ముంగిలి" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "మీ ఈమెయిలు, అవతారం, సంకేతపదం మరియు ప్రౌఫైళ్ళను మార్చుకోండి" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "అనుసంధానించు" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "చందాలు" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "ఆహ్వానించు" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "నిష్క్రమించు" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "సైటు నుండి నిష్క్రమించు" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "కొత్త ఖాతా సృష్టించు" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "సైటులోని ప్రవేశించు" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "సహాయం" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "సహాయం కావాలి!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "వెతుకు" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "సైటు గమనిక" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "స్థానిక వీక్షణలు" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "పేజీ గమనిక" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "చందాలు" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "గురించి" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "ప్రశ్నలు" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "సేవా నియమాలు" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "అంతరంగికత" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "మూలము" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "సంప్రదించు" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "బాడ్జి" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "స్టేటస్‌నెట్ మృదూపకరణ లైసెన్సు" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4514,12 +4514,12 @@ msgstr "" "**%%site.name%%** అనేది [%%site.broughtby%%](%%site.broughtbyurl%%) వారు " "అందిస్తున్న మైక్రో బ్లాగింగు సదుపాయం. " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** అనేది మైక్రో బ్లాగింగు సదుపాయం." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4530,42 +4530,42 @@ msgstr "" "html) కింద లభ్యమయ్యే [స్టేటస్‌నెట్](http://status.net/) మైక్రోబ్లాగింగ్ ఉపకరణం సంచిక %s " "పై నడుస్తుంది." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "కొత్త సందేశం" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "అన్నీ " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "పేజీకరణ" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "తర్వాత" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "ఇంతక్రితం" @@ -5434,7 +5434,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "నుండి" @@ -5558,49 +5558,49 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "ఉ" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "ద" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "తూ" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "ప" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "సందర్భంలో" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "సృష్టితం" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "ఈ నోటీసుపై స్పందించండి" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "స్పందించండి" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "నోటీసుని తొలగించాం." @@ -5903,68 +5903,68 @@ msgstr "అవతారాన్ని మార్చు" msgid "User actions" msgstr "వాడుకరి చర్యలు" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "ఫ్రొఫైలు అమరికలు" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "మార్చు" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "ఈ వాడుకరికి ఒక నేరు సందేశాన్ని పంపించండి" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "సందేశం" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "కొన్ని క్షణాల క్రితం" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "ఓ నిమిషం క్రితం" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "%d నిమిషాల క్రితం" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "ఒక గంట క్రితం" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "%d గంటల క్రితం" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "ఓ రోజు క్రితం" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "%d రోజుల క్రితం" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "ఓ నెల క్రితం" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "%d నెలల క్రితం" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "ఒక సంవత్సరం క్రితం" diff --git a/locale/tr/LC_MESSAGES/statusnet.po b/locale/tr/LC_MESSAGES/statusnet.po index 5368680c6b..d65a14b408 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:16:08+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:22+0000\n" "Language-Team: Turkish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -169,8 +169,8 @@ msgstr "" msgid "You and friends" msgstr "%s ve arkadaşları" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -191,12 +191,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "Onay kodu bulunamadı." @@ -567,7 +567,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 #, fuzzy msgid "Account" msgstr "Hakkında" @@ -655,7 +655,7 @@ msgstr "Desteklenmeyen görüntü dosyası biçemi." msgid "%1$s / Favorites from %2$s" msgstr "%1$s'in %2$s'deki durum mesajları " -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s adli kullanicinin durum mesajlari" @@ -666,7 +666,7 @@ msgstr "%s adli kullanicinin durum mesajlari" msgid "%s timeline" msgstr "" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -682,12 +682,12 @@ msgstr "%1$s'in %2$s'deki durum mesajları " msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "" @@ -697,7 +697,7 @@ msgstr "" msgid "Repeated to %s" msgstr "%s için cevaplar" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "%s için cevaplar" @@ -707,7 +707,7 @@ msgstr "%s için cevaplar" msgid "Notices tagged with %s" msgstr "" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "%s adli kullanicinin durum mesajlari" @@ -771,7 +771,7 @@ msgid "Preview" msgstr "" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "" @@ -962,7 +962,7 @@ msgstr "Bize o profili yollamadınız" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -1021,7 +1021,7 @@ msgstr "" msgid "Do not delete this notice" msgstr "Böyle bir durum mesajı yok." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "" @@ -1280,7 +1280,7 @@ msgstr "Hakkında bölümü çok uzun (azm 140 karakter)." msgid "Could not update group." msgstr "Kullanıcı güncellenemedi." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "Avatar bilgisi kaydedilemedi" @@ -1728,7 +1728,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2080,7 +2080,7 @@ msgstr "Yanlış kullanıcı adı veya parola." msgid "Error setting user. You are probably not authorized." msgstr "Yetkilendirilmemiş." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Giriş" @@ -2334,7 +2334,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -3048,7 +3048,7 @@ msgstr "Onay kodu hatası." msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Kayıt" @@ -3177,7 +3177,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Abone ol" @@ -3217,7 +3217,7 @@ msgstr "Eğer lisansı kabul etmezseniz kayıt olamazsınız." msgid "You already repeated that notice." msgstr "Zaten giriş yapmış durumdasıznız!" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Yarat" @@ -4350,7 +4350,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Kişisel" @@ -4438,21 +4438,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Durum mesajını kaydederken hata oluştu." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Durum mesajını kaydederken hata oluştu." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Cevap eklenirken veritabanı hatası: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4462,12 +4462,12 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 #, fuzzy msgid "Could not create group." msgstr "Avatar bilgisi kaydedilemedi" -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "Abonelik oluşturulamadı." @@ -4511,131 +4511,131 @@ msgstr "%1$s'in %2$s'deki durum mesajları " msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Başlangıç" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Bağlan" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Sunucuya yönlendirme yapılamadı: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Abonelikler" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Çıkış" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "Yeni hesap oluştur" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Yardım" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "Yardım" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Ara" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "Yeni durum mesajı" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "Yeni durum mesajı" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "Abonelikler" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Hakkında" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "SSS" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Gizlilik" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Kaynak" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "İletişim" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4644,12 +4644,12 @@ msgstr "" "**%%site.name%%** [%%site.broughtby%%](%%site.broughtbyurl%%)\" tarafından " "hazırlanan anında mesajlaşma ağıdır. " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** bir aninda mesajlaşma sosyal ağıdır." -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4660,43 +4660,43 @@ msgstr "" "licenses/agpl-3.0.html) lisansı ile korunan [StatusNet](http://status.net/) " "microbloglama yazılımının %s. versiyonunu kullanmaktadır." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "Yeni durum mesajı" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 #, fuzzy msgid "After" msgstr "« Sonra" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "Önce »" @@ -5569,7 +5569,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "" @@ -5694,51 +5694,51 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "İçerik yok!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Yarat" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 #, fuzzy msgid "Reply" msgstr "cevapla" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Durum mesajları" @@ -6046,68 +6046,68 @@ msgstr "Avatar" msgid "User actions" msgstr "" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "Profil ayarları" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "birkaç saniye önce" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "yaklaşık bir dakika önce" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "yaklaşık %d dakika önce" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "yaklaşık bir saat önce" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "yaklaşık %d saat önce" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "yaklaşık bir gün önce" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "yaklaşık %d gün önce" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "yaklaşık bir ay önce" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "yaklaşık %d ay önce" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "yaklaşık bir yıl önce" diff --git a/locale/uk/LC_MESSAGES/statusnet.po b/locale/uk/LC_MESSAGES/statusnet.po index 5f5fa846e6..9899d51dbe 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:16:16+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:25+0000\n" "Language-Team: Ukrainian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -171,8 +171,8 @@ msgstr "" msgid "You and friends" msgstr "Ви з друзями" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "Оновлення від %1$s та друзів на %2$s!" @@ -193,12 +193,12 @@ msgstr "Оновлення від %1$s та друзів на %2$s!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 msgid "API method not found." msgstr "API метод не знайдено." @@ -562,7 +562,7 @@ msgstr "" "на доступ до Вашого акаунту %4$s лише тим стороннім додаткам, яким Ви " "довіряєте." -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "Акаунт" @@ -646,7 +646,7 @@ msgstr "Формат не підтримується." msgid "%1$s / Favorites from %2$s" msgstr "%1$s / Обрані від %2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%1$s оновлення обраних від %2$s / %2$s." @@ -657,7 +657,7 @@ msgstr "%1$s оновлення обраних від %2$s / %2$s." msgid "%s timeline" msgstr "%s стрічка" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -673,12 +673,12 @@ msgstr "%1$s / Оновленні відповіді %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "%1$s оновив цю відповідь на допис від %2$s / %3$s." -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s загальна стрічка" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s оновлення від усіх!" @@ -688,7 +688,7 @@ msgstr "%s оновлення від усіх!" msgid "Repeated to %s" msgstr "Вторування за %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "Вторування %s" @@ -698,7 +698,7 @@ msgstr "Вторування %s" msgid "Notices tagged with %s" msgstr "Дописи позначені з %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Оновлення позначені з %1$s на %2$s!" @@ -759,7 +759,7 @@ msgid "Preview" msgstr "Перегляд" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "Видалити" @@ -940,7 +940,7 @@ msgstr "Ви не є власником цього додатку." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "Виникли певні проблеми з токеном поточної сесії." @@ -998,7 +998,7 @@ msgstr "Ви впевненні, що бажаєте видалити цей д msgid "Do not delete this notice" msgstr "Не видаляти цей допис" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "Видалити допис" @@ -1239,7 +1239,7 @@ msgstr "опис надто довгий (%d знаків максимум)." msgid "Could not update group." msgstr "Не вдалося оновити групу." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 msgid "Could not create aliases." msgstr "Неможна призначити додаткові імена." @@ -1679,7 +1679,7 @@ msgstr "Учасники групи %1$s, сторінка %2$d" msgid "A list of the users in this group." msgstr "Список учасників цієї групи." -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "Адмін" @@ -2066,7 +2066,7 @@ msgstr "Неточне ім’я або пароль." msgid "Error setting user. You are probably not authorized." msgstr "Помилка. Можливо, Ви не авторизовані." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Увійти" @@ -2324,7 +2324,7 @@ msgid "Only " msgstr "Лише " #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Такий формат даних не підтримується." @@ -3030,7 +3030,7 @@ msgstr "Даруйте, помилка у коді запрошення." msgid "Registration successful" msgstr "Реєстрація успішна" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Реєстрація" @@ -3179,7 +3179,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL-адреса Вашого профілю на іншому сумісному сервісі" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Підписатись" @@ -3216,7 +3216,7 @@ msgstr "Ви не можете вторувати своїм власним до msgid "You already repeated that notice." msgstr "Ви вже вторували цьому допису." -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 msgid "Repeated" msgstr "Вторування" @@ -4389,7 +4389,7 @@ msgstr "" msgid "Plugins" msgstr "Додатки" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 msgid "Version" msgstr "Версія" @@ -4477,20 +4477,20 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "Вам заборонено надсилати дописи до цього сайту." -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Проблема при збереженні допису." -#: classes/Notice.php:788 +#: classes/Notice.php:790 msgid "Problem saving group inbox." msgstr "Проблема при збереженні вхідних дописів для групи." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Помилка бази даних при додаванні відповіді: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" @@ -4500,11 +4500,11 @@ msgstr "RT @%1$s %2$s" msgid "Welcome to %1$s, @%2$s!" msgstr "Вітаємо на %1$s, @%2$s!" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "Не вдалося створити нову групу." -#: classes/User_group.php:409 +#: classes/User_group.php:442 msgid "Could not set group membership." msgstr "Не вдалося встановити членство." @@ -4545,124 +4545,124 @@ msgstr "%1$s — %2$s" msgid "Untitled page" msgstr "Сторінка без заголовку" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "Відправна навігація по сайту" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Дім" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "Персональний профіль і стрічка друзів" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "Змінити електронну адресу, аватару, пароль, профіль" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "З’єднання" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect to services" msgstr "З’єднання з сервісами" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "Змінити конфігурацію сайту" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Запросити" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Запросіть друзів та колег приєднатись до Вас на %s" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Вийти" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "Вийти з сайту" -#: lib/action.php:463 +#: lib/action.php:464 msgid "Create an account" msgstr "Створити новий акаунт" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "Увійти на сайт" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Допомога" -#: lib/action.php:469 +#: lib/action.php:470 msgid "Help me!" msgstr "Допоможіть!" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Пошук" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "Пошук людей або текстів" -#: lib/action.php:493 +#: lib/action.php:494 msgid "Site notice" msgstr "Зауваження сайту" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "Огляд" -#: lib/action.php:625 +#: lib/action.php:626 msgid "Page notice" msgstr "Зауваження сторінки" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "Другорядна навігація по сайту" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Про" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "ЧаПи" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "Умови" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Конфіденційність" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Джерело" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Контакт" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "Бедж" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "Ліцензія програмного забезпечення StatusNet" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4671,12 +4671,12 @@ msgstr "" "**%%site.name%%** — це сервіс мікроблоґів наданий вам [%%site.broughtby%%](%%" "site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** — це сервіс мікроблоґів. " -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4687,42 +4687,42 @@ msgstr "" "для мікроблоґів, версія %s, доступному під [GNU Affero General Public " "License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 msgid "Site content license" msgstr "Ліцензія змісту сайту" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Зміст і дані %1$s є приватними і конфіденційними." -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Авторські права на зміст і дані належать %1$s. Всі права захищено." -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Авторські права на зміст і дані належать розробникам. Всі права захищено." -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "Всі " -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "ліцензія." -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "Нумерація сторінок" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "Вперед" -#: lib/action.php:1147 +#: lib/action.php:1150 msgid "Before" msgstr "Назад" @@ -5683,7 +5683,7 @@ msgstr "" "повідомлення аби долучити користувачів до розмови. Такі повідомлення бачите " "лише Ви." -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "від" @@ -5808,48 +5808,48 @@ msgstr "" "На жаль, отримання інформації щодо Вашого місцезнаходження займе більше " "часу, ніж очікувалось; будь ласка, спробуйте пізніше" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "Півн." -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "Півд." -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "Сх." -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "Зах." -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "в" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 msgid "in context" msgstr "в контексті" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 msgid "Repeated by" msgstr "Вторуванні" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "Відповісти на цей допис" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Відповісти" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 msgid "Notice repeated" msgstr "Допис вторували" @@ -6139,67 +6139,67 @@ msgstr "Аватара" msgid "User actions" msgstr "Діяльність користувача" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 msgid "Edit profile settings" msgstr "Налаштування профілю" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "Правка" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "Надіслати пряме повідомлення цьому користувачеві" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "Повідомлення" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "Модерувати" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "мить тому" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "хвилину тому" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "близько %d хвилин тому" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "годину тому" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "близько %d годин тому" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "день тому" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "близько %d днів тому" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "місяць тому" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "близько %d місяців тому" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "рік тому" diff --git a/locale/vi/LC_MESSAGES/statusnet.po b/locale/vi/LC_MESSAGES/statusnet.po index cf152eff5f..dcfb3d7675 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:16:19+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:29+0000\n" "Language-Team: Vietnamese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -168,8 +168,8 @@ msgstr "" msgid "You and friends" msgstr "%s và bạn bè" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -190,12 +190,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "Phương thức API không tìm thấy!" @@ -569,7 +569,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 #, fuzzy msgid "Account" msgstr "Giới thiệu" @@ -656,7 +656,7 @@ msgstr "Không hỗ trợ kiểu file ảnh này." msgid "%1$s / Favorites from %2$s" msgstr "Tìm kiếm các tin nhắn ưa thích của %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "Tất cả các cập nhật của %s" @@ -667,7 +667,7 @@ msgstr "Tất cả các cập nhật của %s" msgid "%s timeline" msgstr "Dòng tin nhắn của %s" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -683,12 +683,12 @@ msgstr "%1$s / Các cập nhật đang trả lời tới %2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, fuzzy, php-format msgid "%s public timeline" msgstr "Dòng tin công cộng" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "%s cập nhật từ tất cả mọi người!" @@ -698,7 +698,7 @@ msgstr "%s cập nhật từ tất cả mọi người!" msgid "Repeated to %s" msgstr "Trả lời cho %s" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "Trả lời cho %s" @@ -708,7 +708,7 @@ msgstr "Trả lời cho %s" msgid "Notices tagged with %s" msgstr "Thông báo được gắn thẻ %s" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "Dòng tin nhắn cho %s" @@ -774,7 +774,7 @@ msgid "Preview" msgstr "Xem trước" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 #, fuzzy msgid "Delete" msgstr "Xóa tin nhắn" @@ -966,7 +966,7 @@ msgstr "Bạn chưa cập nhật thông tin riêng" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 #, fuzzy msgid "There was a problem with your session token." msgstr "Có lỗi xảy ra khi thao tác. Hãy thử lại lần nữa." @@ -1027,7 +1027,7 @@ msgstr "Bạn có chắc chắn là muốn xóa tin nhắn này không?" msgid "Do not delete this notice" msgstr "Không thể xóa tin nhắn này." -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 #, fuzzy msgid "Delete this notice" msgstr "Xóa tin nhắn" @@ -1299,7 +1299,7 @@ msgstr "Lý lịch quá dài (không quá 140 ký tự)" msgid "Could not update group." msgstr "Không thể cập nhật thành viên." -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "Không thể tạo favorite." @@ -1771,7 +1771,7 @@ msgstr "Thành viên" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2161,7 +2161,7 @@ msgstr "Sai tên đăng nhập hoặc mật khẩu." msgid "Error setting user. You are probably not authorized." msgstr "Chưa được phép." -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Đăng nhập" @@ -2423,7 +2423,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "Không hỗ trợ định dạng dữ liệu này." @@ -3148,7 +3148,7 @@ msgstr "Lỗi xảy ra với mã xác nhận." msgid "Registration successful" msgstr "Đăng ký thành công" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Đăng ký" @@ -3295,7 +3295,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "URL trong hồ sơ cá nhân của bạn ở trên các trang microblogging khác" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "Theo bạn này" @@ -3336,7 +3336,7 @@ msgstr "Bạn không thể đăng ký nếu không đồng ý các điều kho msgid "You already repeated that notice." msgstr "Bạn đã theo những người này:" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "Tạo" @@ -4499,7 +4499,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "Cá nhân" @@ -4590,21 +4590,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "Có lỗi xảy ra khi lưu tin nhắn." -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "Có lỗi xảy ra khi lưu tin nhắn." -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "Lỗi cơ sở dữ liệu khi chèn trả lời: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%s (%s)" @@ -4614,12 +4614,12 @@ msgstr "%s (%s)" msgid "Welcome to %1$s, @%2$s!" msgstr "%s chào mừng bạn " -#: classes/User_group.php:380 +#: classes/User_group.php:413 #, fuzzy msgid "Could not create group." msgstr "Không thể tạo favorite." -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "Không thể tạo đăng nhận." @@ -4664,135 +4664,135 @@ msgstr "%s (%s)" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "Trang chủ" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 #, fuzzy msgid "Change your email, avatar, password, profile" msgstr "Thay đổi mật khẩu của bạn" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "Kết nối" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "Không thể chuyển đến máy chủ: %s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "Tôi theo" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "Thư mời" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, fuzzy, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" "Điền địa chỉ email và nội dung tin nhắn để gửi thư mời bạn bè và đồng nghiệp " "của bạn tham gia vào dịch vụ này." -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "Thoát" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "Tạo tài khoản mới" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "Hướng dẫn" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "Hướng dẫn" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "Tìm kiếm" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "Thông báo mới" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "Thông báo mới" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "Tôi theo" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "Giới thiệu" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "Riêng tư" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "Nguồn" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "Liên hệ" -#: lib/action.php:751 +#: lib/action.php:752 #, fuzzy msgid "Badge" msgstr "Tin đã gửi" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4801,12 +4801,12 @@ msgstr "" "**%%site.name%%** là dịch vụ gửi tin nhắn được cung cấp từ [%%site.broughtby%" "%](%%site.broughtbyurl%%). " -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** là dịch vụ gửi tin nhắn. " -#: lib/action.php:786 +#: lib/action.php:787 #, fuzzy, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4817,43 +4817,43 @@ msgstr "" "quyền [GNU Affero General Public License](http://www.fsf.org/licensing/" "licenses/agpl-3.0.html)." -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "Tìm theo nội dung của tin nhắn" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 #, fuzzy msgid "After" msgstr "Sau" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "Trước" @@ -5791,7 +5791,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr " từ " @@ -5919,52 +5919,52 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "Không" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "Không có nội dung!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "Tạo" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 #, fuzzy msgid "Reply to this notice" msgstr "Trả lời tin nhắn này" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "Trả lời" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "Tin đã gửi" @@ -6286,70 +6286,70 @@ msgstr "Hình đại diện" msgid "User actions" msgstr "Không tìm thấy action" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "Các thiết lập cho Hồ sơ cá nhân" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 #, fuzzy msgid "Send a direct message to this user" msgstr "Bạn đã theo những người này:" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 #, fuzzy msgid "Message" msgstr "Tin mới nhất" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "vài giây trước" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "1 phút trước" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "%d phút trước" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "1 giờ trước" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "%d giờ trước" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "1 ngày trước" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "%d ngày trước" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "1 tháng trước" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "%d tháng trước" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "1 năm trước" diff --git a/locale/zh_CN/LC_MESSAGES/statusnet.po b/locale/zh_CN/LC_MESSAGES/statusnet.po index a7aeec7ca5..038dd64982 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:16:22+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:32+0000\n" "Language-Team: Simplified Chinese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -170,8 +170,8 @@ msgstr "" msgid "You and friends" msgstr "%s 及好友" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "来自%2$s 上 %1$s 和好友的更新!" @@ -192,12 +192,12 @@ msgstr "来自%2$s 上 %1$s 和好友的更新!" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "API 方法未实现!" @@ -567,7 +567,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 msgid "Account" msgstr "帐号" @@ -654,7 +654,7 @@ msgstr "不支持这种图像格式。" msgid "%1$s / Favorites from %2$s" msgstr "%s 的收藏 / %s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "%s 收藏了 %s 的 %s 通告。" @@ -665,7 +665,7 @@ msgstr "%s 收藏了 %s 的 %s 通告。" msgid "%s timeline" msgstr "%s 时间表" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -681,12 +681,12 @@ msgstr "%1$s / 回复 %2$s 的消息" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "回复 %2$s / %3$s 的 %1$s 更新。" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "%s 公众时间表" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "来自所有人的 %s 消息!" @@ -696,7 +696,7 @@ msgstr "来自所有人的 %s 消息!" msgid "Repeated to %s" msgstr "%s 的回复" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, fuzzy, php-format msgid "Repeats of %s" msgstr "%s 的回复" @@ -706,7 +706,7 @@ msgstr "%s 的回复" msgid "Notices tagged with %s" msgstr "带 %s 标签的通告" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "%2$s 上 %1$s 的更新!" @@ -769,7 +769,7 @@ msgid "Preview" msgstr "预览" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 #, fuzzy msgid "Delete" msgstr "删除" @@ -962,7 +962,7 @@ msgstr "您未告知此个人信息" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 #, fuzzy msgid "There was a problem with your session token." msgstr "会话标识有问题,请重试。" @@ -1023,7 +1023,7 @@ msgstr "确定要删除这条消息吗?" msgid "Do not delete this notice" msgstr "无法删除通告。" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 #, fuzzy msgid "Delete this notice" msgstr "删除通告" @@ -1287,7 +1287,7 @@ msgstr "描述过长(不能超过140字符)。" msgid "Could not update group." msgstr "无法更新组" -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "无法创建收藏。" @@ -1748,7 +1748,7 @@ msgstr "%s 组成员, 第 %d 页" msgid "A list of the users in this group." msgstr "该组成员列表。" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "admin管理员" @@ -2119,7 +2119,7 @@ msgstr "用户名或密码不正确。" msgid "Error setting user. You are probably not authorized." msgstr "未认证。" -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "登录" @@ -2373,7 +2373,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "不支持的数据格式。" @@ -3086,7 +3086,7 @@ msgstr "验证码出错。" msgid "Registration successful" msgstr "注册成功。" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "注册" @@ -3227,7 +3227,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "您在其他兼容的微博客服务的个人信息URL" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "订阅" @@ -3270,7 +3270,7 @@ msgstr "您必须同意此授权方可注册。" msgid "You already repeated that notice." msgstr "您已成功阻止该用户:" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "创建" @@ -4426,7 +4426,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "个人" @@ -4516,21 +4516,21 @@ msgstr "你在短时间里发布了过多的消息,请深呼吸,过几分钟 msgid "You are banned from posting notices on this site." msgstr "在这个网站你被禁止发布消息。" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "保存通告时出错。" -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "保存通告时出错。" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "添加回复时数据库出错:%s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" @@ -4540,11 +4540,11 @@ msgstr "%1$s (%2$s)" msgid "Welcome to %1$s, @%2$s!" msgstr "发送给 %1$s 的 %2$s 消息" -#: classes/User_group.php:380 +#: classes/User_group.php:413 msgid "Could not create group." msgstr "无法创建组。" -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "无法删除订阅。" @@ -4587,133 +4587,133 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "无标题页" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "主站导航" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "主页" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "个人资料及朋友年表" -#: lib/action.php:441 +#: lib/action.php:442 #, fuzzy msgid "Change your email, avatar, password, profile" msgstr "修改资料" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "连接" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "无法重定向到服务器:%s" -#: lib/action.php:448 +#: lib/action.php:449 #, fuzzy msgid "Change site configuration" msgstr "主站导航" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "邀请" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, fuzzy, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "使用这个表单来邀请好友和同事加入。" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "登出" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "登出本站" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "创建新帐号" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "登入本站" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "帮助" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "帮助" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "搜索" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "检索人或文字" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "新通告" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "本地显示" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "新通告" -#: lib/action.php:727 +#: lib/action.php:728 #, fuzzy msgid "Secondary site navigation" msgstr "次项站导航" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "关于" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "常见问题FAQ" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "隐私" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "来源" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "联系人" -#: lib/action.php:751 +#: lib/action.php:752 #, fuzzy msgid "Badge" msgstr "呼叫" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "StatusNet软件注册证" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4722,12 +4722,12 @@ msgstr "" "**%%site.name%%** 是一个微博客服务,提供者为 [%%site.broughtby%%](%%site." "broughtbyurl%%)。" -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** 是一个微博客服务。" -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4738,43 +4738,43 @@ msgstr "" "General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)" "授权。" -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "StatusNet软件注册证" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "全部" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "注册证" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "分页" -#: lib/action.php:1139 +#: lib/action.php:1142 #, fuzzy msgid "After" msgstr "« 之后" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "之前 »" @@ -5659,7 +5659,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 #, fuzzy msgid "from" msgstr " 从 " @@ -5786,53 +5786,53 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 #, fuzzy msgid "N" msgstr "否" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "没有内容!" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "创建" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 #, fuzzy msgid "Reply to this notice" msgstr "无法删除通告。" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 #, fuzzy msgid "Reply" msgstr "回复" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "消息已发布。" @@ -6151,70 +6151,70 @@ msgstr "头像" msgid "User actions" msgstr "未知动作" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "个人设置" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 #, fuzzy msgid "Send a direct message to this user" msgstr "无法向此用户发送消息。" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 #, fuzzy msgid "Message" msgstr "新消息" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "几秒前" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "一分钟前" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "%d 分钟前" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "一小时前" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "%d 小时前" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "一天前" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "%d 天前" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "一个月前" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "%d 个月前" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "一年前" diff --git a/locale/zh_TW/LC_MESSAGES/statusnet.po b/locale/zh_TW/LC_MESSAGES/statusnet.po index 815f95eacd..e6996e1524 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-02-11 08:14+0000\n" -"PO-Revision-Date: 2010-02-11 08:16:25+0000\n" +"POT-Creation-Date: 2010-02-18 22:55+0000\n" +"PO-Revision-Date: 2010-02-18 22:57:35+0000\n" "Language-Team: Traditional Chinese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62295); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62678); 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" @@ -166,8 +166,8 @@ msgstr "" msgid "You and friends" msgstr "%s與好友" -#: actions/allrss.php:119 actions/apitimelinefriends.php:121 -#: actions/apitimelinehome.php:122 +#: actions/allrss.php:119 actions/apitimelinefriends.php:119 +#: actions/apitimelinehome.php:120 #, php-format msgid "Updates from %1$s and friends on %2$s!" msgstr "" @@ -188,12 +188,12 @@ msgstr "" #: actions/apistatusesdestroy.php:102 actions/apistatusesretweets.php:112 #: actions/apistatusesshow.php:108 actions/apistatusnetconfig.php:137 #: actions/apistatusnetversion.php:93 actions/apisubscriptions.php:111 -#: actions/apitimelinefavorites.php:146 actions/apitimelinefriends.php:155 -#: actions/apitimelinegroup.php:150 actions/apitimelinehome.php:156 -#: actions/apitimelinementions.php:151 actions/apitimelinepublic.php:131 +#: actions/apitimelinefavorites.php:183 actions/apitimelinefriends.php:187 +#: actions/apitimelinegroup.php:194 actions/apitimelinehome.php:184 +#: actions/apitimelinementions.php:175 actions/apitimelinepublic.php:152 #: actions/apitimelineretweetedtome.php:121 -#: actions/apitimelineretweetsofme.php:122 actions/apitimelinetag.php:141 -#: actions/apitimelineuser.php:166 actions/apiusershow.php:101 +#: actions/apitimelineretweetsofme.php:152 actions/apitimelinetag.php:166 +#: actions/apitimelineuser.php:207 actions/apiusershow.php:101 #, fuzzy msgid "API method not found." msgstr "確認碼遺失" @@ -559,7 +559,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:441 +#: actions/apioauthauthorize.php:310 lib/action.php:442 #, fuzzy msgid "Account" msgstr "關於" @@ -645,7 +645,7 @@ msgstr "" msgid "%1$s / Favorites from %2$s" msgstr "%1$s的狀態是%2$s" -#: actions/apitimelinefavorites.php:120 +#: actions/apitimelinefavorites.php:117 #, fuzzy, php-format msgid "%1$s updates favorited by %2$s / %2$s." msgstr "&s的微型部落格" @@ -656,7 +656,7 @@ msgstr "&s的微型部落格" msgid "%s timeline" msgstr "" -#: actions/apitimelinegroup.php:117 actions/apitimelineuser.php:126 +#: actions/apitimelinegroup.php:114 actions/apitimelineuser.php:126 #: actions/userrss.php:92 #, php-format msgid "Updates from %1$s on %2$s!" @@ -672,12 +672,12 @@ msgstr "%1$s的狀態是%2$s" msgid "%1$s updates that reply to updates from %2$s / %3$s." msgstr "" -#: actions/apitimelinepublic.php:107 actions/publicrss.php:103 +#: actions/apitimelinepublic.php:111 actions/publicrss.php:103 #, php-format msgid "%s public timeline" msgstr "" -#: actions/apitimelinepublic.php:111 actions/publicrss.php:105 +#: actions/apitimelinepublic.php:115 actions/publicrss.php:105 #, php-format msgid "%s updates from everyone!" msgstr "" @@ -687,7 +687,7 @@ msgstr "" msgid "Repeated to %s" msgstr "" -#: actions/apitimelineretweetsofme.php:112 +#: actions/apitimelineretweetsofme.php:114 #, php-format msgid "Repeats of %s" msgstr "" @@ -697,7 +697,7 @@ msgstr "" msgid "Notices tagged with %s" msgstr "" -#: actions/apitimelinetag.php:108 actions/tagrss.php:64 +#: actions/apitimelinetag.php:104 actions/tagrss.php:64 #, fuzzy, php-format msgid "Updates tagged with %1$s on %2$s!" msgstr "&s的微型部落格" @@ -761,7 +761,7 @@ msgid "Preview" msgstr "" #: actions/avatarsettings.php:149 actions/showapplication.php:252 -#: lib/deleteuserform.php:66 lib/noticelist.php:624 +#: lib/deleteuserform.php:66 lib/noticelist.php:636 msgid "Delete" msgstr "" @@ -952,7 +952,7 @@ msgstr "無法連結到伺服器:%s" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1195 +#: lib/action.php:1198 msgid "There was a problem with your session token." msgstr "" @@ -1011,7 +1011,7 @@ msgstr "" msgid "Do not delete this notice" msgstr "無此通知" -#: actions/deletenotice.php:146 lib/noticelist.php:624 +#: actions/deletenotice.php:146 lib/noticelist.php:636 msgid "Delete this notice" msgstr "" @@ -1268,7 +1268,7 @@ msgstr "自我介紹過長(共140個字元)" msgid "Could not update group." msgstr "無法更新使用者" -#: actions/editgroup.php:259 classes/User_group.php:390 +#: actions/editgroup.php:259 classes/User_group.php:423 #, fuzzy msgid "Could not create aliases." msgstr "無法存取個人圖像資料" @@ -1710,7 +1710,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2048,7 +2048,7 @@ msgstr "使用者名稱或密碼錯誤" msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:466 +#: actions/login.php:188 actions/login.php:241 lib/action.php:467 #: lib/logingroupnav.php:79 msgid "Login" msgstr "登入" @@ -2293,7 +2293,7 @@ msgid "Only " msgstr "" #: actions/oembed.php:181 actions/oembed.php:200 lib/api.php:1040 -#: lib/api.php:1068 lib/api.php:1178 +#: lib/api.php:1068 lib/api.php:1177 msgid "Not a supported data format." msgstr "" @@ -2989,7 +2989,7 @@ msgstr "確認碼發生錯誤" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:463 +#: actions/register.php:114 actions/register.php:503 lib/action.php:464 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -3114,7 +3114,7 @@ msgid "URL of your profile on another compatible microblogging service" msgstr "" #: actions/remotesubscribe.php:137 lib/subscribeform.php:139 -#: lib/userprofile.php:365 +#: lib/userprofile.php:368 msgid "Subscribe" msgstr "" @@ -3153,7 +3153,7 @@ msgstr "" msgid "You already repeated that notice." msgstr "無此使用者" -#: actions/repeat.php:114 lib/noticelist.php:642 +#: actions/repeat.php:114 lib/noticelist.php:655 #, fuzzy msgid "Repeated" msgstr "新增" @@ -4272,7 +4272,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:747 +#: actions/version.php:196 lib/action.php:748 #, fuzzy msgid "Version" msgstr "地點" @@ -4360,21 +4360,21 @@ msgstr "" msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:319 +#: classes/Notice.php:294 classes/Notice.php:320 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:788 +#: classes/Notice.php:790 #, fuzzy msgid "Problem saving group inbox." msgstr "儲存使用者發生錯誤" -#: classes/Notice.php:848 +#: classes/Notice.php:850 #, php-format msgid "DB error inserting reply: %s" msgstr "增加回覆時,資料庫發生錯誤: %s" -#: classes/Notice.php:1235 +#: classes/Notice.php:1274 #, php-format msgid "RT @%1$s %2$s" msgstr "" @@ -4384,12 +4384,12 @@ msgstr "" msgid "Welcome to %1$s, @%2$s!" msgstr "" -#: classes/User_group.php:380 +#: classes/User_group.php:413 #, fuzzy msgid "Could not create group." msgstr "無法存取個人圖像資料" -#: classes/User_group.php:409 +#: classes/User_group.php:442 #, fuzzy msgid "Could not set group membership." msgstr "註冊失敗" @@ -4433,129 +4433,129 @@ msgstr "%1$s的狀態是%2$s" msgid "Untitled page" msgstr "" -#: lib/action.php:433 +#: lib/action.php:434 msgid "Primary site navigation" msgstr "" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Home" msgstr "主頁" -#: lib/action.php:439 +#: lib/action.php:440 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:441 +#: lib/action.php:442 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:444 +#: lib/action.php:445 msgid "Connect" msgstr "連結" -#: lib/action.php:444 +#: lib/action.php:445 #, fuzzy msgid "Connect to services" msgstr "無法連結到伺服器:%s" -#: lib/action.php:448 +#: lib/action.php:449 msgid "Change site configuration" msgstr "" -#: lib/action.php:452 lib/subgroupnav.php:105 +#: lib/action.php:453 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:106 +#: lib/action.php:454 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout" msgstr "登出" -#: lib/action.php:458 +#: lib/action.php:459 msgid "Logout from the site" msgstr "" -#: lib/action.php:463 +#: lib/action.php:464 #, fuzzy msgid "Create an account" msgstr "新增帳號" -#: lib/action.php:466 +#: lib/action.php:467 msgid "Login to the site" msgstr "" -#: lib/action.php:469 lib/action.php:732 +#: lib/action.php:470 lib/action.php:733 msgid "Help" msgstr "求救" -#: lib/action.php:469 +#: lib/action.php:470 #, fuzzy msgid "Help me!" msgstr "求救" -#: lib/action.php:472 lib/searchaction.php:127 +#: lib/action.php:473 lib/searchaction.php:127 msgid "Search" msgstr "" -#: lib/action.php:472 +#: lib/action.php:473 msgid "Search for people or text" msgstr "" -#: lib/action.php:493 +#: lib/action.php:494 #, fuzzy msgid "Site notice" msgstr "新訊息" -#: lib/action.php:559 +#: lib/action.php:560 msgid "Local views" msgstr "" -#: lib/action.php:625 +#: lib/action.php:626 #, fuzzy msgid "Page notice" msgstr "新訊息" -#: lib/action.php:727 +#: lib/action.php:728 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:734 +#: lib/action.php:735 msgid "About" msgstr "關於" -#: lib/action.php:736 +#: lib/action.php:737 msgid "FAQ" msgstr "常見問題" -#: lib/action.php:740 +#: lib/action.php:741 msgid "TOS" msgstr "" -#: lib/action.php:743 +#: lib/action.php:744 msgid "Privacy" msgstr "" -#: lib/action.php:745 +#: lib/action.php:746 msgid "Source" msgstr "" -#: lib/action.php:749 +#: lib/action.php:750 msgid "Contact" msgstr "好友名單" -#: lib/action.php:751 +#: lib/action.php:752 msgid "Badge" msgstr "" -#: lib/action.php:779 +#: lib/action.php:780 msgid "StatusNet software license" msgstr "" -#: lib/action.php:782 +#: lib/action.php:783 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4564,12 +4564,12 @@ msgstr "" "**%%site.name%%**是由[%%site.broughtby%%](%%site.broughtbyurl%%)所提供的微型" "部落格服務" -#: lib/action.php:784 +#: lib/action.php:785 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%**是個微型部落格" -#: lib/action.php:786 +#: lib/action.php:787 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4577,42 +4577,42 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:801 +#: lib/action.php:802 #, fuzzy msgid "Site content license" msgstr "新訊息" -#: lib/action.php:806 +#: lib/action.php:807 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:811 +#: lib/action.php:812 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:814 +#: lib/action.php:815 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:826 +#: lib/action.php:828 msgid "All " msgstr "" -#: lib/action.php:831 +#: lib/action.php:834 msgid "license." msgstr "" -#: lib/action.php:1130 +#: lib/action.php:1133 msgid "Pagination" msgstr "" -#: lib/action.php:1139 +#: lib/action.php:1142 msgid "After" msgstr "" -#: lib/action.php:1147 +#: lib/action.php:1150 #, fuzzy msgid "Before" msgstr "之前的內容»" @@ -5469,7 +5469,7 @@ msgid "" "users in conversation. People can send you messages for your eyes only." msgstr "" -#: lib/mailbox.php:227 lib/noticelist.php:477 +#: lib/mailbox.php:227 lib/noticelist.php:481 msgid "from" msgstr "" @@ -5594,50 +5594,50 @@ msgid "" "try again later" msgstr "" -#: lib/noticelist.php:428 +#: lib/noticelist.php:429 #, php-format msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "N" msgstr "" -#: lib/noticelist.php:429 +#: lib/noticelist.php:430 msgid "S" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "E" msgstr "" -#: lib/noticelist.php:430 +#: lib/noticelist.php:431 msgid "W" msgstr "" -#: lib/noticelist.php:436 +#: lib/noticelist.php:438 msgid "at" msgstr "" -#: lib/noticelist.php:547 +#: lib/noticelist.php:557 #, fuzzy msgid "in context" msgstr "無內容" -#: lib/noticelist.php:572 +#: lib/noticelist.php:582 #, fuzzy msgid "Repeated by" msgstr "新增" -#: lib/noticelist.php:598 +#: lib/noticelist.php:609 msgid "Reply to this notice" msgstr "" -#: lib/noticelist.php:599 +#: lib/noticelist.php:610 msgid "Reply" msgstr "" -#: lib/noticelist.php:641 +#: lib/noticelist.php:654 #, fuzzy msgid "Notice repeated" msgstr "更新個人圖像" @@ -5941,68 +5941,68 @@ msgstr "個人圖像" msgid "User actions" msgstr "" -#: lib/userprofile.php:248 +#: lib/userprofile.php:251 #, fuzzy msgid "Edit profile settings" msgstr "線上即時通設定" -#: lib/userprofile.php:249 +#: lib/userprofile.php:252 msgid "Edit" msgstr "" -#: lib/userprofile.php:272 +#: lib/userprofile.php:275 msgid "Send a direct message to this user" msgstr "" -#: lib/userprofile.php:273 +#: lib/userprofile.php:276 msgid "Message" msgstr "" -#: lib/userprofile.php:311 +#: lib/userprofile.php:314 msgid "Moderate" msgstr "" -#: lib/util.php:870 +#: lib/util.php:871 msgid "a few seconds ago" msgstr "" -#: lib/util.php:872 +#: lib/util.php:873 msgid "about a minute ago" msgstr "" -#: lib/util.php:874 +#: lib/util.php:875 #, php-format msgid "about %d minutes ago" msgstr "" -#: lib/util.php:876 +#: lib/util.php:877 msgid "about an hour ago" msgstr "" -#: lib/util.php:878 +#: lib/util.php:879 #, php-format msgid "about %d hours ago" msgstr "" -#: lib/util.php:880 +#: lib/util.php:881 msgid "about a day ago" msgstr "" -#: lib/util.php:882 +#: lib/util.php:883 #, php-format msgid "about %d days ago" msgstr "" -#: lib/util.php:884 +#: lib/util.php:885 msgid "about a month ago" msgstr "" -#: lib/util.php:886 +#: lib/util.php:887 #, php-format msgid "about %d months ago" msgstr "" -#: lib/util.php:888 +#: lib/util.php:889 msgid "about a year ago" msgstr "" From 0dac13d197248bf24ea51cb7911d32286764c0c8 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 18 Feb 2010 21:22:21 +0000 Subject: [PATCH 038/190] OStatus refactoring to clean up profile vs feed and fix up subscription issues. PuSH subscription maintenance broken back out to FeedSub, letting Ostatus_profile deal with the profile level (user or group, with unique id URI) --- plugins/OStatus/OStatusPlugin.php | 53 +- plugins/OStatus/actions/feedsubsettings.php | 99 ++-- plugins/OStatus/actions/pushcallback.php | 22 +- plugins/OStatus/actions/salmon.php | 32 +- plugins/OStatus/classes/FeedSub.php | 443 ++++++++++++++++ plugins/OStatus/classes/Ostatus_profile.php | 558 +++++++------------- plugins/OStatus/lib/feeddiscovery.php | 52 +- plugins/OStatus/lib/feedmunger.php | 350 ------------ 8 files changed, 749 insertions(+), 860 deletions(-) create mode 100644 plugins/OStatus/classes/FeedSub.php delete mode 100644 plugins/OStatus/lib/feedmunger.php diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index e548a151c7..4ebe4551ec 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -1,17 +1,7 @@ -Author URI: http://status.net/ -*/ - /* * StatusNet - the distributed open-source microblogging tool - * Copyright (C) 2009, StatusNet, Inc. + * Copyright (C) 2009-2010, StatusNet, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -28,17 +18,12 @@ Author URI: http://status.net/ */ /** - * @package FeedSubPlugin + * @package OStatusPlugin * @maintainer Brion Vibber */ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -define('FEEDSUB_SERVICE', 100); // fixme -- avoid hardcoding these? - -// We bundle the XML_Parse_Feed library... -set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib'); - class FeedSubException extends Exception { } @@ -258,24 +243,6 @@ class OStatusPlugin extends Plugin } } - /** - * Notify remote server when one of our users subscribes. - * @fixme Check and restart the PuSH subscription if needed - * - * @param User $user - * @param Profile $other - * @return hook return value - */ - function onEndSubscribe($user, $other) - { - $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); - if ($oprofile) { - // Notify the remote server of the unsub, if supported. - $oprofile->notify($user->getProfile(), ActivityVerb::FOLLOW, $oprofile); - } - return true; - } - /** * Notify remote server and garbage collect unused feeds on unsubscribe. * @fixme send these operations to background queues @@ -309,6 +276,7 @@ class OStatusPlugin extends Plugin function onCheckSchema() { $schema = Schema::get(); $schema->ensureTable('ostatus_profile', Ostatus_profile::schemaDef()); + $schema->ensureTable('feedsub', FeedSub::schemaDef()); $schema->ensureTable('hubsub', HubSub::schemaDef()); return true; } @@ -345,4 +313,19 @@ class OStatusPlugin extends Plugin return false; } } + + /** + * Send incoming PuSH feeds for OStatus endpoints in for processing. + * + * @param FeedSub $feedsub + * @param DOMDocument $feed + * @return mixed hook return code + */ + function onStartFeedSubReceive($feedsub, $feed) + { + $oprofile = Ostatus_profile::staticGet('feeduri', $feedsub->uri); + if ($oprofile) { + $oprofile->processFeed($feed); + } + } } diff --git a/plugins/OStatus/actions/feedsubsettings.php b/plugins/OStatus/actions/feedsubsettings.php index 6933c9bf21..3e1d0aa823 100644 --- a/plugins/OStatus/actions/feedsubsettings.php +++ b/plugins/OStatus/actions/feedsubsettings.php @@ -26,7 +26,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } class FeedSubSettingsAction extends ConnectSettingsAction { - protected $feedurl; + protected $profile_uri; protected $preview; protected $munger; @@ -88,7 +88,10 @@ class FeedSubSettingsAction extends ConnectSettingsAction $this->elementStart('ul', 'form_data'); $this->elementStart('li', array('id' => 'settings_twitter_login_button')); - $this->input('feedurl', _('Feed URL'), $this->feedurl, _('Enter the URL of a PubSubHubbub-enabled feed')); + $this->input('profile_uri', + _m('Feed URL'), + $this->profile_uri, + _m('Enter the profile URL of a PubSubHubbub-enabled feed')); $this->elementEnd('li'); $this->elementEnd('ul'); @@ -145,79 +148,55 @@ class FeedSubSettingsAction extends ConnectSettingsAction */ function validateFeed() { - $feedurl = trim($this->arg('feedurl')); + $profile_uri = trim($this->arg('profile_uri')); - if ($feedurl == '') { - $this->showForm(_m('Empty feed URL!')); + if ($profile_uri == '') { + $this->showForm(_m('Empty remote profile URL!')); return; } - $this->feedurl = $feedurl; + $this->profile_uri = $profile_uri; - // Get the canonical feed URI and check it + // @fixme validate, normalize bla bla try { - $discover = new FeedDiscovery(); - $uri = $discover->discoverFromURL($feedurl); + $oprofile = Ostatus_profile::ensureProfile($this->profile_uri); + $this->oprofile = $oprofile; + return true; } catch (FeedSubBadURLException $e) { - $this->showForm(_m('Invalid URL or could not reach server.')); - return false; + $err = _m('Invalid URL or could not reach server.'); } catch (FeedSubBadResponseException $e) { - $this->showForm(_m('Cannot read feed; server returned error.')); - return false; + $err = _m('Cannot read feed; server returned error.'); } catch (FeedSubEmptyException $e) { - $this->showForm(_m('Cannot read feed; server returned an empty page.')); - return false; + $err = _m('Cannot read feed; server returned an empty page.'); } catch (FeedSubBadHTMLException $e) { - $this->showForm(_m('Bad HTML, could not find feed link.')); - return false; + $err = _m('Bad HTML, could not find feed link.'); } catch (FeedSubNoFeedException $e) { - $this->showForm(_m('Could not find a feed linked from this URL.')); - return false; + $err = _m('Could not find a feed linked from this URL.'); } catch (FeedSubUnrecognizedTypeException $e) { - $this->showForm(_m('Not a recognized feed type.')); - return false; + $err = _m('Not a recognized feed type.'); } catch (FeedSubException $e) { // Any new ones we forgot about - $this->showForm(_m('Bad feed URL.')); - return false; + $err = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage()); } - - $this->munger = $discover->feedMunger(); - $this->profile = $this->munger->ostatusProfile(); - if ($this->profile->huburi == '' && !common_config('feedsub', 'nohub')) { - $this->showForm(_m('Feed is not PuSH-enabled; cannot subscribe.')); - return false; - } - - return true; + $this->showForm($err); + return false; } function saveFeed() { if ($this->validateFeed()) { $this->preview = true; - $this->profile = Ostatus_profile::ensureProfile($this->munger); - if (!$this->profile) { - throw new ServerException("Feed profile was not saved properly."); - } - - // If not already in use, subscribe to updates via the hub - if ($this->profile->sub_start) { - common_log(LOG_INFO, __METHOD__ . ": double the fun! new sub for {$this->profile->feeduri} last subbed {$this->profile->sub_start}"); - } else { - $ok = $this->profile->subscribe(); - common_log(LOG_INFO, __METHOD__ . ": sub was $ok"); - if (!$ok) { - $this->showForm(_m('Feed subscription failed! Bad response from hub.')); - return; - } - } // And subscribe the current user to the local profile $user = common_current_user(); - if ($this->profile->isGroup()) { - $group = $this->profile->localGroup(); + if (!$this->oprofile->subscribe()) { + $this->showForm(_m("Failed to set up server-to-server subscription.")); + return; + } + + if ($this->oprofile->isGroup()) { + $group = $this->oprofile->localGroup(); if ($user->isMember($group)) { $this->showForm(_m('Already a member!')); } elseif (Group_member::join($this->profile->group_id, $user->id)) { @@ -226,13 +205,13 @@ class FeedSubSettingsAction extends ConnectSettingsAction $this->showForm(_m('Remote group join failed!')); } } else { - $local = $this->profile->localProfile(); + $local = $this->oprofile->localProfile(); if ($user->isSubscribed($local)) { $this->showForm(_m('Already subscribed!')); - } elseif ($user->subscribeTo($local)) { - $this->showForm(_m('Feed subscribed!')); + } elseif ($this->oprofile->subscribeLocalToRemote($user)) { + $this->showForm(_m('Remote user subscribed!')); } else { - $this->showForm(_m('Feed subscription failed!')); + $this->showForm(_m('Remote subscription failed!')); } } } @@ -248,17 +227,7 @@ class FeedSubSettingsAction extends ConnectSettingsAction function previewFeed() { - $profile = $this->munger->ostatusProfile(); - $notice = $this->munger->notice(0, true); // preview - - if ($notice) { - $this->element('b', null, 'Preview of latest post from this feed:'); - - $item = new NoticeList($notice, $this); - $item->show(); - } else { - $this->element('b', null, 'No posts in this feed yet.'); - } + $this->text('Profile preview should go here'); } function showScripts() diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index ed859a32f8..7e1227a66a 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -48,9 +48,9 @@ class PushCallbackAction extends Action throw new ServerException('Empty or invalid feed id', 400); } - $profile = Ostatus_profile::staticGet('id', $feedid); - if (!$profile) { - throw new ServerException('Unknown OStatus/PuSH feed id ' . $feedid, 400); + $feedsub = FeedSub::staticGet('id', $feedid); + if (!$feedsub) { + throw new ServerException('Unknown PuSH feed id ' . $feedid, 400); } $hmac = ''; @@ -62,7 +62,7 @@ class PushCallbackAction extends Action // @fixme Queue this to a background process; we should return // as quickly as possible from a distribution POST. - $profile->postUpdates($post, $hmac); + $feedsub->receive($post, $hmac); } /** @@ -81,29 +81,29 @@ class PushCallbackAction extends Action throw new ServerException("Bogus hub callback: bad mode", 404); } - $profile = Ostatus_profile::staticGet('feeduri', $topic); - if (!$profile) { + $feedsub = FeedSub::staticGet('uri', $topic); + if (!$feedsub) { common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback for unknown feed $topic"); throw new ServerException("Bogus hub callback: unknown feed", 404); } - if ($profile->verify_token !== $verify_token) { + if ($feedsub->verify_token !== $verify_token) { common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad token \"$verify_token\" for feed $topic"); throw new ServerException("Bogus hub callback: bad token", 404); } - if ($mode != $profile->sub_state) { - common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad mode \"$mode\" for feed $topic in state \"{$profile->sub_state}\""); + if ($mode != $feedsub->sub_state) { + common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad mode \"$mode\" for feed $topic in state \"{$feedsub->sub_state}\""); throw new ServerException("Bogus hub callback: mode doesn't match subscription state.", 404); } // OK! if ($mode == 'subscribe') { common_log(LOG_INFO, __METHOD__ . ': sub confirmed'); - $profile->confirmSubscribe($lease_seconds); + $feedsub->confirmSubscribe($lease_seconds); } else { common_log(LOG_INFO, __METHOD__ . ": unsub confirmed; deleting sub record for $topic"); - $profile->confirmUnsubscribe(); + $feedsub->confirmUnsubscribe(); } print $challenge; } diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index 224134cd7c..ea5b8e4ea8 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -68,6 +68,9 @@ class SalmonAction extends Action return true; } + /** + * @fixme probably call Ostatus_profile::processFeed + */ function handle($args) { common_log(LOG_INFO, 'Salmon: incoming post for user '. $this->user->id); @@ -95,6 +98,9 @@ class SalmonAction extends Action } } + /** + * @fixme probably call Ostatus_profile::processFeed + */ function handlePost() { switch ($this->act->object->type) { @@ -111,14 +117,23 @@ class SalmonAction extends Action $profile = $this->ensureProfile(); } + /** + * @fixme probably call Ostatus_profile::processFeed + */ function handleFollow() { } + /** + * @fixme probably call Ostatus_profile::processFeed + */ function handleFavorite() { } + /** + * @fixme probably call Ostatus_profile::processFeed + */ function handleShare() { } @@ -131,17 +146,13 @@ class SalmonAction extends Action throw new Exception("Received a salmon slap from unidentified actor."); } - $ostatusProfile = Ostatus_profile::staticGet('homeuri', $actor->id); - - if (empty($ostatusProfile)) { - return $this->createProfile(); - } else { - // XXX: can we receive a salmon slap from a group...? - assert(!empty($ostatusProfile->profile_id)); - return Profile::staticGet($ostatusProfile->profile_id); - } + $ostatusProfile = Ostatus_profile::ensureActorProfile($this->act); + return $oprofile->localProfile(); } + /** + * @fixme anything new in here probably should be merged into Ostatus_profile::ensureActorProfile and friends + */ function createProfile() { $actor = $this->act->actor; @@ -186,6 +197,9 @@ class SalmonAction extends Action return $profile; } + /** + * @fixme should be merged into Ostatus_profile + */ function nicknameFromURI($uri) { preg_match('/(\w+):/', $uri, $matches); diff --git a/plugins/OStatus/classes/FeedSub.php b/plugins/OStatus/classes/FeedSub.php new file mode 100644 index 0000000000..dc2c0b710b --- /dev/null +++ b/plugins/OStatus/classes/FeedSub.php @@ -0,0 +1,443 @@ +. + */ + +/** + * @package OStatusPlugin + * @maintainer Brion Vibber + */ + +/* +PuSH subscription flow: + + $profile->subscribe() + generate random verification token + save to verify_token + sends a sub request to the hub... + + main/push/callback + hub sends confirmation back to us via GET + We verify the request, then echo back the challenge. + On our end, we save the time we subscribed and the lease expiration + + main/push/callback + hub sends us updates via POST + +*/ + +class FeedDBException extends FeedSubException +{ + public $obj; + + function __construct($obj) + { + parent::__construct('Database insert failure'); + $this->obj = $obj; + } +} + +/** + * FeedSub handles low-level PubHubSubbub (PuSH) subscriptions. + * Higher-level behavior building OStatus stuff on top is handled + * under Ostatus_profile. + */ +class FeedSub extends Memcached_DataObject +{ + public $__table = 'feedsub'; + + public $id; + public $feeduri; + + // PuSH subscription data + public $huburi; + public $secret; + public $verify_token; + public $sub_state; // subscribe, active, unsubscribe, inactive + public $sub_start; + public $sub_end; + public $last_update; + + public $created; + public $modified; + + public /*static*/ function staticGet($k, $v=null) + { + return parent::staticGet(__CLASS__, $k, $v); + } + + /** + * return table definition for DB_DataObject + * + * DB_DataObject needs to know something about the table to manipulate + * instances. This method provides all the DB_DataObject needs to know. + * + * @return array array of column definitions + */ + + function table() + { + return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'huburi' => DB_DATAOBJECT_STR, + 'secret' => DB_DATAOBJECT_STR, + 'verify_token' => DB_DATAOBJECT_STR, + 'sub_state' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'sub_start' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, + 'sub_end' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, + 'last_update' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, + 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, + 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); + } + + static function schemaDef() + { + return array(new ColumnDef('id', 'integer', + /*size*/ null, + /*nullable*/ false, + /*key*/ 'PRI', + /*default*/ '0', + /*extra*/ null, + /*auto_increment*/ true), + new ColumnDef('uri', 'varchar', + 255, false, 'UNI'), + new ColumnDef('huburi', 'text', + null, true), + new ColumnDef('verify_token', 'text', + null, true), + new ColumnDef('secret', 'text', + null, true), + new ColumnDef('sub_state', "enum('subscribe','active','unsubscribe','inactive')", + null, false), + new ColumnDef('sub_start', 'datetime', + null, true), + new ColumnDef('sub_end', 'datetime', + null, true), + new ColumnDef('last_update', 'datetime', + null, false), + new ColumnDef('created', 'datetime', + null, false), + new ColumnDef('modified', 'datetime', + null, false)); + } + + /** + * return key definitions for DB_DataObject + * + * DB_DataObject needs to know about keys that the table has; this function + * defines them. + * + * @return array key definitions + */ + + function keys() + { + return array_keys($this->keyTypes()); + } + + /** + * return key definitions for Memcached_DataObject + * + * Our caching system uses the same key definitions, but uses a different + * method to get them. + * + * @return array key definitions + */ + + function keyTypes() + { + return array('id' => 'K', 'uri' => 'U'); + } + + function sequenceKey() + { + return array('id', true, false); + } + + /** + * Fetch the StatusNet-side profile for this feed + * @return Profile + */ + public function localProfile() + { + if ($this->profile_id) { + return Profile::staticGet('id', $this->profile_id); + } + return null; + } + + /** + * Fetch the StatusNet-side profile for this feed + * @return Profile + */ + public function localGroup() + { + if ($this->group_id) { + return User_group::staticGet('id', $this->group_id); + } + return null; + } + + /** + * @param string $feeduri + * @return FeedSub + * @throws FeedSubException if feed is invalid or lacks PuSH setup + */ + public static function ensureFeed($feeduri) + { + $current = self::staticGet('uri', $feeduri); + if ($current) { + return $current; + } + + $discover = new FeedDiscovery(); + $discover->discoverFromFeedURL($feeduri); + + $huburi = $discover->getAtomLink('hub'); + if (!$huburi) { + throw new FeedSubNoHubException(); + } + + $feedsub = new FeedSub(); + $feedsub->uri = $feeduri; + $feedsub->huburi = $huburi; + $feedsub->sub_state = 'inactive'; + + $feedsub->created = common_sql_now(); + $feedsub->modified = common_sql_now(); + + $result = $feedsub->insert(); + if (empty($result)) { + throw new FeedDBException($feedsub); + } + + return $feedsub; + } + + /** + * Send a subscription request to the hub for this feed. + * The hub will later send us a confirmation POST to /main/push/callback. + * + * @return bool true on success, false on failure + * @throws ServerException if feed state is not valid + */ + public function subscribe($mode='subscribe') + { + if ($this->sub_state && $this->sub_state != 'inactive') { + throw new ServerException("Attempting to start PuSH subscription to feed in state $this->sub_state"); + } + if (empty($this->huburi)) { + if (common_config('feedsub', 'nohub')) { + // Fake it! We're just testing remote feeds w/o hubs. + return true; + } else { + throw new ServerException("Attempting to start PuSH subscription for feed with no hub"); + } + } + + return $this->doSubscribe('subscribe'); + } + + /** + * Send a PuSH unsubscription request to the hub for this feed. + * The hub will later send us a confirmation POST to /main/push/callback. + * + * @return bool true on success, false on failure + * @throws ServerException if feed state is not valid + */ + public function unsubscribe() { + if ($this->sub_state != 'active') { + throw new ServerException("Attempting to end PuSH subscription to feed in state $this->sub_state"); + } + if (empty($this->huburi)) { + if (common_config('feedsub', 'nohub')) { + // Fake it! We're just testing remote feeds w/o hubs. + return true; + } else { + throw new ServerException("Attempting to end PuSH subscription for feed with no hub"); + } + } + + return $this->doSubscribe('unsubscribe'); + } + + protected function doSubscribe($mode) + { + $orig = clone($this); + $this->verify_token = common_good_rand(16); + if ($mode == 'subscribe') { + $this->secret = common_good_rand(32); + } + $this->sub_state = $mode; + $this->update($orig); + unset($orig); + + try { + $callback = common_local_url('pushcallback', array('feed' => $this->id)); + $headers = array('Content-Type: application/x-www-form-urlencoded'); + $post = array('hub.mode' => $mode, + 'hub.callback' => $callback, + 'hub.verify' => 'async', + 'hub.verify_token' => $this->verify_token, + 'hub.secret' => $this->secret, + //'hub.lease_seconds' => 0, + 'hub.topic' => $this->uri); + $client = new HTTPClient(); + $response = $client->post($this->huburi, $headers, $post); + $status = $response->getStatus(); + if ($status == 202) { + common_log(LOG_INFO, __METHOD__ . ': sub req ok, awaiting verification callback'); + return true; + } else if ($status == 204) { + common_log(LOG_INFO, __METHOD__ . ': sub req ok and verified'); + return true; + } else if ($status >= 200 && $status < 300) { + common_log(LOG_ERR, __METHOD__ . ": sub req returned unexpected HTTP $status: " . $response->getBody()); + return false; + } else { + common_log(LOG_ERR, __METHOD__ . ": sub req failed with HTTP $status: " . $response->getBody()); + return false; + } + } catch (Exception $e) { + // wtf! + common_log(LOG_ERR, __METHOD__ . ": error \"{$e->getMessage()}\" hitting hub $this->huburi subscribing to $this->uri"); + + $orig = clone($this); + $this->verify_token = null; + $this->sub_state = null; + $this->update($orig); + unset($orig); + + return false; + } + } + + /** + * Save PuSH subscription confirmation. + * Sets approximate lease start and end times and finalizes state. + * + * @param int $lease_seconds provided hub.lease_seconds parameter, if given + */ + public function confirmSubscribe($lease_seconds=0) + { + $original = clone($this); + + $this->sub_state = 'active'; + $this->sub_start = common_sql_date(time()); + if ($lease_seconds > 0) { + $this->sub_end = common_sql_date(time() + $lease_seconds); + } else { + $this->sub_end = null; + } + $this->lastupdate = common_sql_now(); + + return $this->update($original); + } + + /** + * Save PuSH unsubscription confirmation. + * Wipes active PuSH sub info and resets state. + */ + public function confirmUnsubscribe() + { + $original = clone($this); + + // @fixme these should all be null, but DB_DataObject doesn't save null values...????? + $this->verify_token = ''; + $this->secret = ''; + $this->sub_state = ''; + $this->sub_start = ''; + $this->sub_end = ''; + $this->lastupdate = common_sql_now(); + + return $this->update($original); + } + + /** + * Accept updates from a PuSH feed. If validated, this object and the + * feed (as a DOMDocument) will be passed to the StartFeedSubHandleFeed + * and EndFeedSubHandleFeed events for processing. + * + * @param string $post source of Atom or RSS feed + * @param string $hmac X-Hub-Signature header, if present + */ + public function receive($post, $hmac) + { + common_log(LOG_INFO, __METHOD__ . ": packet for \"$this->uri\"! $hmac $post"); + + if ($this->sub_state != 'active') { + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH for inactive feed $this->uri (in state '$this->sub_state')"); + return; + } + + if ($post === '') { + common_log(LOG_ERR, __METHOD__ . ": ignoring empty post"); + return; + } + + if (!$this->validatePushSig($post, $hmac)) { + // Per spec we silently drop input with a bad sig, + // while reporting receipt to the server. + return; + } + + $feed = new DOMDocument(); + if (!$feed->loadXML($post)) { + // @fixme might help to include the err message + common_log(LOG_ERR, __METHOD__ . ": ignoring invalid XML"); + return; + } + + Event::handle('StartFeedSubReceive', array($this, $feed)); + Event::handle('EndFeedSubReceive', array($this, $feed)); + } + + /** + * Validate the given Atom chunk and HMAC signature against our + * shared secret that was set up at subscription time. + * + * If we don't have a shared secret, there should be no signature. + * If we we do, our the calculated HMAC should match theirs. + * + * @param string $post raw XML source as POSTed to us + * @param string $hmac X-Hub-Signature HTTP header value, or empty + * @return boolean true for a match + */ + protected function validatePushSig($post, $hmac) + { + if ($this->secret) { + if (preg_match('/^sha1=([0-9a-fA-F]{40})$/', $hmac, $matches)) { + $their_hmac = strtolower($matches[1]); + $our_hmac = hash_hmac('sha1', $post, $this->secret); + if ($their_hmac === $our_hmac) { + return true; + } + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bad SHA-1 HMAC: got $their_hmac, expected $our_hmac"); + } else { + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bogus HMAC '$hmac'"); + } + } else { + if (empty($hmac)) { + return true; + } else { + common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with unexpected HMAC '$hmac'"); + } + } + return false; + } + +} diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 486417617c..1ce8ac4917 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -18,62 +18,24 @@ */ /** - * @package FeedSubPlugin + * @package OStatusPlugin * @maintainer Brion Vibber */ -/* -PuSH subscription flow: - - $profile->subscribe() - generate random verification token - save to verify_token - sends a sub request to the hub... - - main/push/callback - hub sends confirmation back to us via GET - We verify the request, then echo back the challenge. - On our end, we save the time we subscribed and the lease expiration - - main/push/callback - hub sends us updates via POST - -*/ - -class FeedDBException extends FeedSubException -{ - public $obj; - - function __construct($obj) - { - parent::__construct('Database insert failure'); - $this->obj = $obj; - } -} - class Ostatus_profile extends Memcached_DataObject { public $__table = 'ostatus_profile'; - public $id; + public $uri; + public $profile_id; public $group_id; public $feeduri; - public $homeuri; - - // PuSH subscription data - public $huburi; - public $secret; - public $verify_token; - public $sub_state; // subscribe, active, unsubscribe - public $sub_start; - public $sub_end; - public $salmonuri; public $created; - public $lastupdate; + public $modified; public /*static*/ function staticGet($k, $v=null) { @@ -91,56 +53,30 @@ class Ostatus_profile extends Memcached_DataObject function table() { - return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + return array('uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'profile_id' => DB_DATAOBJECT_INT, 'group_id' => DB_DATAOBJECT_INT, 'feeduri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, - 'homeuri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, - 'huburi' => DB_DATAOBJECT_STR, - 'secret' => DB_DATAOBJECT_STR, - 'verify_token' => DB_DATAOBJECT_STR, - 'sub_state' => DB_DATAOBJECT_STR, - 'sub_start' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, - 'sub_end' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, 'salmonuri' => DB_DATAOBJECT_STR, 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, - 'lastupdate' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); + 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); } static function schemaDef() { - return array(new ColumnDef('id', 'integer', - /*size*/ null, - /*nullable*/ false, - /*key*/ 'PRI', - /*default*/ '0', - /*extra*/ null, - /*auto_increment*/ true), + return array(new ColumnDef('uri', 'varchar', + 255, false, 'PRI'), new ColumnDef('profile_id', 'integer', null, true, 'UNI'), new ColumnDef('group_id', 'integer', null, true, 'UNI'), new ColumnDef('feeduri', 'varchar', 255, false, 'UNI'), - new ColumnDef('homeuri', 'varchar', - 255, false), - new ColumnDef('huburi', 'text', - null, true), - new ColumnDef('verify_token', 'varchar', - 32, true), - new ColumnDef('secret', 'varchar', - 64, true), - new ColumnDef('sub_state', "enum('subscribe','active','unsubscribe')", - null, true), - new ColumnDef('sub_start', 'datetime', - null, true), - new ColumnDef('sub_end', 'datetime', - null, true), new ColumnDef('salmonuri', 'text', null, true), new ColumnDef('created', 'datetime', null, false), - new ColumnDef('lastupdate', 'datetime', + new ColumnDef('modified', 'datetime', null, false)); } @@ -169,12 +105,12 @@ class Ostatus_profile extends Memcached_DataObject function keyTypes() { - return array('id' => 'K', 'profile_id' => 'U', 'group_id' => 'U', 'feeduri' => 'U'); + return array('uri' => 'K', 'profile_id' => 'U', 'group_id' => 'U', 'feeduri' => 'U'); } function sequenceKey() { - return array('id', true, false); + return array(false, false, false); } /** @@ -201,101 +137,6 @@ class Ostatus_profile extends Memcached_DataObject return null; } - /** - * @param FeedMunger $munger - * @param boolean $isGroup is this a group record? - * @return Ostatus_profile - */ - public static function ensureProfile($munger) - { - $profile = $munger->ostatusProfile(); - - $current = self::staticGet('feeduri', $profile->feeduri); - if ($current) { - // @fixme we should probably update info as necessary - return $current; - } - - $profile->query('BEGIN'); - - try { - $local = $munger->profile(); - - if ($profile->isGroup()) { - $group = new User_group(); - $group->nickname = $local->nickname . '@remote'; // @fixme - $group->fullname = $local->fullname; - $group->homepage = $local->homepage; - $group->location = $local->location; - $group->created = $local->created; - $group->insert(); - if (empty($result)) { - throw new FeedDBException($group); - } - $profile->group_id = $group->id; - } else { - $result = $local->insert(); - if (empty($result)) { - throw new FeedDBException($local); - } - $profile->profile_id = $local->id; - } - - $profile->created = common_sql_now(); - $profile->lastupdate = common_sql_now(); - $result = $profile->insert(); - if (empty($result)) { - throw new FeedDBException($profile); - } - - $profile->query('COMMIT'); - } catch (FeedDBException $e) { - common_log_db_error($e->obj, 'INSERT', __FILE__); - $profile->query('ROLLBACK'); - return false; - } - - $avatar = $munger->getAvatar(); - if ($avatar) { - try { - $profile->updateAvatar($avatar); - } catch (Exception $e) { - common_log(LOG_ERR, "Exception setting OStatus avatar: " . - $e->getMessage()); - } - } - - return $profile; - } - - /** - * Download and update given avatar image - * @param string $url - * @throws Exception in various failure cases - */ - public function updateAvatar($url) - { - // @fixme this should be better encapsulated - // ripped from oauthstore.php (for old OMB client) - $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); - copy($url, $temp_filename); - - // @fixme should we be using different ids? - $imagefile = new ImageFile($this->id, $temp_filename); - $filename = Avatar::filename($this->id, - image_type_to_extension($imagefile->type), - null, - common_timestamp()); - rename($temp_filename, Avatar::path($filename)); - if ($this->isGroup()) { - $group = $this->localGroup(); - $group->setOriginal($filename); - } else { - $profile = $this->localProfile(); - $profile->setOriginal($filename); - } - } - /** * Returns an XML string fragment with profile information as an * Activity Streams noun object with the given element type. @@ -345,7 +186,7 @@ class Ostatus_profile extends Memcached_DataObject $xs->element( 'id', null, - $this->homeuri); // ? + $this->uri); // ? $xs->element('title', null, $self->getBestName()); $xs->element( @@ -369,6 +210,61 @@ class Ostatus_profile extends Memcached_DataObject return (strpos($this->feeduri, '/groups/') !== false); } + /** + * Subscribe a local user to this remote user. + * PuSH subscription will be started if necessary, and we'll + * send a Salmon notification to the remote server if available + * notifying them of the sub. + * + * @param User $user + * @return boolean success + * @throws FeedException + */ + public function subscribeLocalToRemote(User $user) + { + if ($this->isGroup()) { + throw new ServerException("Can't subscribe to a remote group"); + } + + if ($this->subscribe()) { + if ($user->subscribeTo($this->localProfile())) { + $this->notify($user->getProfile(), ActivityVerb::FOLLOW, $this); + return true; + } + } + return false; + } + + /** + * Mark this remote profile as subscribing to the given local user, + * and send appropriate notifications to the user. + * + * This will generally be in response to a subscription notification + * from a foreign site to our local Salmon response channel. + * + * @param User $user + * @return boolean success + */ + public function subscribeRemoteToLocal(User $user) + { + if ($this->isGroup()) { + throw new ServerException("Remote groups can't subscribe to local users"); + } + + // @fixme use regular channels for subbing, once they accept remote profiles + $sub = new Subscription(); + $sub->subscriber = $this->profile_id; + $sub->subscribed = $user->id; + $sub->created = common_sql_now(); // current time + + if ($sub->insert()) { + // @fixme use subs_notify() if refactored to take profiles? + mail_subscribe_notify_profile($user, $this->localProfile()); + return true; + } + return false; + } + /** * Send a subscription request to the hub for this feed. * The hub will later send us a confirmation POST to /main/push/callback. @@ -378,19 +274,14 @@ class Ostatus_profile extends Memcached_DataObject */ public function subscribe($mode='subscribe') { - if ($this->sub_state != '') { - throw new ServerException("Attempting to start PuSH subscription to feed in state $this->sub_state"); + $feedsub = FeedSub::ensureFeed($this->feeduri); + if ($feedsub->sub_state == 'active' || $feedsub->sub_state == 'subscribe') { + return true; + } else if ($feedsub->sub_state == '' || $feedsub->sub_state == 'inactive') { + return $feedsub->subscribe(); + } else if ('unsubscribe') { + throw new FeedSubException("Unsub is pending, can't subscribe..."); } - if (empty($this->huburi)) { - if (common_config('feedsub', 'nohub')) { - // Fake it! We're just testing remote feeds w/o hubs. - return true; - } else { - throw new ServerException("Attempting to start PuSH subscription for feed with no hub"); - } - } - - return $this->doSubscribe('subscribe'); } /** @@ -401,111 +292,14 @@ class Ostatus_profile extends Memcached_DataObject * @throws ServerException if feed state is not valid */ public function unsubscribe() { - if ($this->sub_state != 'active') { - throw new ServerException("Attempting to end PuSH subscription to feed in state $this->sub_state"); + $feedsub = FeedSub::staticGet('uri', $this->feeduri); + if ($feedsub->sub_state == 'active') { + return $feedsub->unsubscribe(); + } else if ($feedsub->sub_state == '' || $feedsub->sub_state == 'inactive' || $feedsub->sub_state == 'unsubscribe') { + return true; + } else if ($feedsub->sub_state == 'subscribe') { + throw new FeedSubException("Feed is awaiting subscription, can't unsub..."); } - if (empty($this->huburi)) { - if (common_config('feedsub', 'nohub')) { - // Fake it! We're just testing remote feeds w/o hubs. - return true; - } else { - throw new ServerException("Attempting to end PuSH subscription for feed with no hub"); - } - } - - return $this->doSubscribe('unsubscribe'); - } - - protected function doSubscribe($mode) - { - $orig = clone($this); - $this->verify_token = common_good_rand(16); - if ($mode == 'subscribe') { - $this->secret = common_good_rand(32); - } - $this->sub_state = $mode; - $this->update($orig); - unset($orig); - - try { - $callback = common_local_url('pushcallback', array('feed' => $this->id)); - $headers = array('Content-Type: application/x-www-form-urlencoded'); - $post = array('hub.mode' => $mode, - 'hub.callback' => $callback, - 'hub.verify' => 'async', - 'hub.verify_token' => $this->verify_token, - 'hub.secret' => $this->secret, - //'hub.lease_seconds' => 0, - 'hub.topic' => $this->feeduri); - $client = new HTTPClient(); - $response = $client->post($this->huburi, $headers, $post); - $status = $response->getStatus(); - if ($status == 202) { - common_log(LOG_INFO, __METHOD__ . ': sub req ok, awaiting verification callback'); - return true; - } else if ($status == 204) { - common_log(LOG_INFO, __METHOD__ . ': sub req ok and verified'); - return true; - } else if ($status >= 200 && $status < 300) { - common_log(LOG_ERR, __METHOD__ . ": sub req returned unexpected HTTP $status: " . $response->getBody()); - return false; - } else { - common_log(LOG_ERR, __METHOD__ . ": sub req failed with HTTP $status: " . $response->getBody()); - return false; - } - } catch (Exception $e) { - // wtf! - common_log(LOG_ERR, __METHOD__ . ": error \"{$e->getMessage()}\" hitting hub $this->huburi subscribing to $this->feeduri"); - - $orig = clone($this); - $this->verify_token = null; - $this->sub_state = null; - $this->update($orig); - unset($orig); - - return false; - } - } - - /** - * Save PuSH subscription confirmation. - * Sets approximate lease start and end times and finalizes state. - * - * @param int $lease_seconds provided hub.lease_seconds parameter, if given - */ - public function confirmSubscribe($lease_seconds=0) - { - $original = clone($this); - - $this->sub_state = 'active'; - $this->sub_start = common_sql_date(time()); - if ($lease_seconds > 0) { - $this->sub_end = common_sql_date(time() + $lease_seconds); - } else { - $this->sub_end = null; - } - $this->lastupdate = common_sql_now(); - - return $this->update($original); - } - - /** - * Save PuSH unsubscription confirmation. - * Wipes active PuSH sub info and resets state. - */ - public function confirmUnsubscribe() - { - $original = clone($this); - - // @fixme these should all be null, but DB_DataObject doesn't save null values...????? - $this->verify_token = ''; - $this->secret = ''; - $this->sub_state = ''; - $this->sub_start = ''; - $this->sub_end = ''; - $this->lastupdate = common_sql_now(); - - return $this->update($original); } /** @@ -543,10 +337,7 @@ class Ostatus_profile extends Memcached_DataObject $entry->elementEnd('entry'); $feed = $this->atomFeed($actor); - #$feed->initFeed(); $feed->addEntry($entry); - #$feed->renderEntries(); - #$feed->endFeed(); $xml = $feed->getString(); common_log(LOG_INFO, "Posting to Salmon endpoint $salmon: $xml"); @@ -600,36 +391,10 @@ class Ostatus_profile extends Memcached_DataObject * Currently assumes that all items in the feed are new, * coming from a PuSH hub. * - * @param string $post source of Atom or RSS feed - * @param string $hmac X-Hub-Signature header, if present + * @param DOMDocument $feed */ - public function postUpdates($post, $hmac) + public function processFeed($feed) { - common_log(LOG_INFO, __METHOD__ . ": packet for \"$this->feeduri\"! $hmac $post"); - - if ($this->sub_state != 'active') { - common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH for inactive feed $this->feeduri (in state '$this->sub_state')"); - return; - } - - if ($post === '') { - common_log(LOG_ERR, __METHOD__ . ": ignoring empty post"); - return; - } - - if (!$this->validatePushSig($post, $hmac)) { - // Per spec we silently drop input with a bad sig, - // while reporting receipt to the server. - return; - } - - $feed = new DOMDocument(); - if (!$feed->loadXML($post)) { - // @fixme might help to include the err message - common_log(LOG_ERR, __METHOD__ . ": ignoring invalid XML"); - return; - } - $entries = $feed->getElementsByTagNameNS(Activity::ATOM, 'entry'); if ($entries->length == 0) { common_log(LOG_ERR, __METHOD__ . ": no entries in feed update, ignoring"); @@ -642,40 +407,6 @@ class Ostatus_profile extends Memcached_DataObject } } - /** - * Validate the given Atom chunk and HMAC signature against our - * shared secret that was set up at subscription time. - * - * If we don't have a shared secret, there should be no signature. - * If we we do, our the calculated HMAC should match theirs. - * - * @param string $post raw XML source as POSTed to us - * @param string $hmac X-Hub-Signature HTTP header value, or empty - * @return boolean true for a match - */ - protected function validatePushSig($post, $hmac) - { - if ($this->secret) { - if (preg_match('/^sha1=([0-9a-fA-F]{40})$/', $hmac, $matches)) { - $their_hmac = strtolower($matches[1]); - $our_hmac = hash_hmac('sha1', $post, $this->secret); - if ($their_hmac === $our_hmac) { - return true; - } - common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bad SHA-1 HMAC: got $their_hmac, expected $our_hmac"); - } else { - common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bogus HMAC '$hmac'"); - } - } else { - if (empty($hmac)) { - return true; - } else { - common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with unexpected HMAC '$hmac'"); - } - } - return false; - } - /** * Process a posted entry from this feed source. * @@ -704,14 +435,14 @@ class Ostatus_profile extends Memcached_DataObject { if ($this->isGroup()) { // @fixme validate these profiles in some way! - $oprofile = $this->ensureActorProfile($activity); + $oprofile = self::ensureActorProfile($activity); } else { - $actorUri = $this->getActorProfileURI($activity); - if ($actorUri == $this->homeuri) { + $actorUri = self::getActorProfileURI($activity); + if ($actorUri == $this->uri) { // @fixme check if profile info has changed and update it } else { // @fixme drop or reject the messages once we've got the canonical profile URI recorded sanely - common_log(LOG_INFO, "OStatus: Warning: non-group post with unexpected author: $actorUri expected $this->homeuri"); + common_log(LOG_INFO, "OStatus: Warning: non-group post with unexpected author: $actorUri expected $this->uri"); //return; } $oprofile = $this; @@ -787,6 +518,65 @@ class Ostatus_profile extends Memcached_DataObject return false; } + /** + * @param string $profile_url + * @return Ostatus_profile + * @throws FeedSubException + */ + public static function ensureProfile($profile_uri) + { + // Get the canonical feed URI and check it + $discover = new FeedDiscovery(); + $feeduri = $discover->discoverFromURL($profile_uri); + + $feedsub = FeedSub::ensureFeed($feeduri, $discover->feed); + $huburi = $discover->getAtomLink('hub'); + $salmonuri = $discover->getAtomLink('salmon'); + + if (!$huburi) { + // We can only deal with folks with a PuSH hub + throw new FeedSubNoHubException(); + } + + // Ok this is going to be a terrible hack! + // Won't be suitable for groups, empty feeds, or getting + // info that's only available on the profile page. + $entries = $discover->feed->getElementsByTagNameNS(Activity::ATOM, 'entry'); + if (!$entries || $entries->length == 0) { + throw new FeedSubException('empty feed'); + } + $first = new Activity($entries->item(0), $discover->feed); + return self::ensureActorProfile($first, $feeduri); + } + + /** + * Download and update given avatar image + * @param string $url + * @throws Exception in various failure cases + */ + protected function updateAvatar($url) + { + // @fixme this should be better encapsulated + // ripped from oauthstore.php (for old OMB client) + $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); + copy($url, $temp_filename); + + // @fixme should we be using different ids? + $imagefile = new ImageFile($this->id, $temp_filename); + $filename = Avatar::filename($this->id, + image_type_to_extension($imagefile->type), + null, + common_timestamp()); + rename($temp_filename, Avatar::path($filename)); + if ($this->isGroup()) { + $group = $this->localGroup(); + $group->setOriginal($filename); + } else { + $profile = $this->localProfile(); + $profile->setOriginal($filename); + } + } + /** * Get an appropriate avatar image source URL, if available. * @@ -794,7 +584,7 @@ class Ostatus_profile extends Memcached_DataObject * @param DOMElement $feed * @return string */ - function getAvatar($actor, $feed) + protected static function getAvatar($actor, $feed) { $url = ''; $icon = ''; @@ -833,13 +623,18 @@ class Ostatus_profile extends Memcached_DataObject } /** - * @fixme move off of ostatus_profile or static? + * Fetch, or build if necessary, an Ostatus_profile for the actor + * in a given Activity Streams activity. + * + * @param Activity $activity + * @param string $feeduri if we already know the canonical feed URI! + * @return Ostatus_profile */ - function ensureActorProfile($activity) + public static function ensureActorProfile($activity, $feeduri=null) { - $profile = $this->getActorProfile($activity); + $profile = self::getActorProfile($activity); if (!$profile) { - $profile = $this->createActorProfile($activity); + $profile = self::createActorProfile($activity, $feeduri); } return $profile; } @@ -848,10 +643,10 @@ class Ostatus_profile extends Memcached_DataObject * @param Activity $activity * @return mixed matching Ostatus_profile or false if none known */ - function getActorProfile($activity) + protected static function getActorProfile($activity) { - $homeuri = $this->getActorProfileURI($activity); - return Ostatus_profile::staticGet('homeuri', $homeuri); + $homeuri = self::getActorProfileURI($activity); + return self::staticGet('uri', $homeuri); } /** @@ -859,7 +654,7 @@ class Ostatus_profile extends Memcached_DataObject * @return string * @throws ServerException */ - function getActorProfileURI($activity) + protected static function getActorProfileURI($activity) { $opts = array('allowed_schemes' => array('http', 'https')); $actor = $activity->actor; @@ -873,14 +668,19 @@ class Ostatus_profile extends Memcached_DataObject } /** - * + * @fixme validate stuff somewhere */ - function createActorProfile($activity) + protected static function createActorProfile($activity, $feeduri=null) { - $actor = $activity->actor(); - $homeuri = $this->getActivityProfileURI($activity); - $nickname = $this->getAuthorNick($activity); - $avatar = $this->getAvatar($actor, $feed); + $actor = $activity->actor; + $homeuri = self::getActorProfileURI($activity); + $nickname = self::getAuthorNick($activity); + $avatar = self::getAvatar($actor, $feed); + + if (!$homeuri) { + common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true)); + throw new ServerException("No profile URI"); + } $profile = new Profile(); $profile->nickname = $nickname; @@ -894,9 +694,7 @@ class Ostatus_profile extends Memcached_DataObject // @todo lat/lon/location? $ok = $profile->insert(); - if ($ok) { - $this->updateAvatar($profile, $avatar); - } else { + if (!$ok) { throw new ServerException("Can't save local profile"); } @@ -904,11 +702,15 @@ class Ostatus_profile extends Memcached_DataObject // or need to split out some of the feed stuff // so we can leave it empty until later. $oprofile = new Ostatus_profile(); - $oprofile->homeuri = $homeuri; + $oprofile->uri = $homeuri; + if ($feeduri) { + $oprofile->feeduri = $feeduri; + } $oprofile->profile_id = $profile->id; $ok = $oprofile->insert(); if ($ok) { + $oprofile->updateAvatar($avatar); return $oprofile; } else { throw new ServerException("Can't save OStatus profile"); @@ -920,13 +722,13 @@ class Ostatus_profile extends Memcached_DataObject * @param Activity $activity * @return string */ - function getAuthorNick($activity) + protected static function getAuthorNick($activity) { // @fixme not technically part of the actor? foreach (array($activity->entry, $activity->feed) as $source) { - $author = ActivityUtil::child($source, 'author', Activity::ATOM); + $author = ActivityUtils::child($source, 'author', Activity::ATOM); if ($author) { - $name = ActivityUtil::child($author, 'name', Activity::ATOM); + $name = ActivityUtils::child($author, 'name', Activity::ATOM); if ($name) { return trim($name->textContent); } diff --git a/plugins/OStatus/lib/feeddiscovery.php b/plugins/OStatus/lib/feeddiscovery.php index 39985fc902..7afb71bdc1 100644 --- a/plugins/OStatus/lib/feeddiscovery.php +++ b/plugins/OStatus/lib/feeddiscovery.php @@ -48,6 +48,14 @@ class FeedSubNoFeedException extends FeedSubException { } +class FeedSubBadXmlException extends FeedSubException +{ +} + +class FeedSubNoHubException extends FeedSubException +{ +} + /** * Given a web page or feed URL, discover the final location of the feed * and return its current contents. @@ -57,21 +65,25 @@ class FeedSubNoFeedException extends FeedSubException * if ($feed->discoverFromURL($url)) { * print $feed->uri; * print $feed->type; - * processFeed($feed->body); + * processFeed($feed->feed); // DOMDocument * } */ class FeedDiscovery { public $uri; public $type; - public $body; + public $feed; - - public function feedMunger() + /** Post-initialize query helper... */ + public function getLink($rel, $type=null) { - require_once 'XML/Feed/Parser.php'; - $feed = new XML_Feed_Parser($this->body, false, false, true); // @fixme - return new FeedMunger($feed, $this->uri); + // @fixme check for non-Atom links in RSS2 feeds as well + return self::getAtomLink($rel, $type); + } + + public function getAtomLink($rel, $type=null) + { + return ActivityUtils::getLink($this->feed->documentElement, $rel, $type); } /** @@ -90,6 +102,7 @@ class FeedDiscovery $client = new HTTPClient(); $response = $client->get($url); } catch (HTTP_Request2_Exception $e) { + common_log(LOG_ERR, __METHOD__ . " Failure for $url - " . $e->getMessage()); throw new FeedSubBadURLException($e); } @@ -107,7 +120,12 @@ class FeedDiscovery return $this->initFromResponse($response); } - + + function discoverFromFeedURL($url) + { + return $this->discoverFromURL($url, false); + } + function initFromResponse($response) { if (!$response->isOk()) { @@ -122,16 +140,26 @@ class FeedDiscovery $type = $response->getHeader('Content-Type'); if (preg_match('!^(text/xml|application/xml|application/(rss|atom)\+xml)!i', $type)) { - $this->uri = $sourceurl; - $this->type = $type; - $this->body = $body; - return true; + return $this->init($sourceurl, $type, $body); } else { common_log(LOG_WARNING, "Unrecognized feed type $type for $sourceurl"); throw new FeedSubUnrecognizedTypeException($type); } } + function init($sourceurl, $type, $body) + { + $feed = new DOMDocument(); + if ($feed->loadXML($body)) { + $this->uri = $sourceurl; + $this->type = $type; + $this->feed = $feed; + return $this->uri; + } else { + throw new FeedSubBadXmlException($url); + } + } + /** * @param string $url source URL, used to resolve relative links * @param string $body HTML body text diff --git a/plugins/OStatus/lib/feedmunger.php b/plugins/OStatus/lib/feedmunger.php deleted file mode 100644 index e8c46de90e..0000000000 --- a/plugins/OStatus/lib/feedmunger.php +++ /dev/null @@ -1,350 +0,0 @@ -. - */ - -/** - * @package FeedSubPlugin - * @maintainer Brion Vibber - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -class FeedSubPreviewNotice extends Notice -{ - protected $fetched = true; - - function __construct($profile) - { - $this->profile = $profile; - $this->profile_id = 0; - } - - function getProfile() - { - return $this->profile; - } - - function find() - { - return true; - } - - function fetch() - { - $got = $this->fetched; - $this->fetched = false; - return $got; - } -} - -class FeedSubPreviewProfile extends Profile -{ - function getAvatar($width, $height=null) - { - return new FeedSubPreviewAvatar($width, $height, $this->avatar); - } -} - -class FeedSubPreviewAvatar extends Avatar -{ - function __construct($width, $height, $remote) - { - $this->remoteImage = $remote; - } - - function displayUrl() { - return $this->remoteImage; - } -} - -class FeedMunger -{ - /** - * @param XML_Feed_Parser $feed - */ - function __construct($feed, $url=null) - { - $this->feed = $feed; - $this->url = $url; - } - - function ostatusProfile() - { - $profile = new Ostatus_profile(); - $profile->feeduri = $this->url; - $profile->homeuri = $this->feed->link; - $profile->huburi = $this->getHubLink(); - $salmon = $this->getSalmonLink(); - if ($salmon) { - $profile->salmonuri = $salmon; - } - return $profile; - } - - function getAtomLink($item, $attribs=array()) - { - // XML_Feed_Parser gets confused by multiple elements. - $dom = $item->model; - - // Note that RSS feeds would embed an so this should work for both. - /// http://code.google.com/p/pubsubhubbub/wiki/RssFeeds - // - $links = $dom->getElementsByTagNameNS('http://www.w3.org/2005/Atom', 'link'); - for ($i = 0; $i < $links->length; $i++) { - $node = $links->item($i); - if ($node->hasAttributes()) { - $href = $node->attributes->getNamedItem('href'); - if ($href) { - $matches = 0; - foreach ($attribs as $name => $val) { - $attrib = $node->attributes->getNamedItem($name); - if ($attrib && $attrib->value == $val) { - $matches++; - } - } - if ($matches == count($attribs)) { - return $href->value; - } - } - } - } - return false; - } - - function getRssLink($item) - { - // XML_Feed_Parser gets confused by multiple elements. - $dom = $item->model; - - // Note that RSS feeds would embed an so this should work for both. - /// http://code.google.com/p/pubsubhubbub/wiki/RssFeeds - // - $links = $dom->getElementsByTagName('link'); - for ($i = 0; $i < $links->length; $i++) { - $node = $links->item($i); - if (!$node->hasAttributes()) { - return $node->textContent; - } - } - return false; - } - - function getAltLink($item) - { - // Check for an atom link... - $link = $this->getAtomLink($item, array('rel' => 'alternate', 'type' => 'text/html')); - if (!$link) { - $link = $this->getRssLink($item); - } - return $link; - } - - function getHubLink() - { - return $this->getAtomLink($this->feed, array('rel' => 'hub')); - } - - function getSalmonLink() - { - return $this->getAtomLink($this->feed, array('rel' => 'salmon')); - } - - function getSelfLink() - { - return $this->getAtomLink($this->feed, array('rel' => 'self')); - } - - /** - * Get an appropriate avatar image source URL, if available. - * @return mixed string or false - */ - function getAvatar() - { - $logo = $this->feed->logo; - if ($logo) { - return $logo; - } - $icon = $this->feed->icon; - if ($icon) { - return $icon; - } - return common_path('plugins/OStatus/images/48px-Feed-icon.svg.png'); - } - - function profile($preview=false) - { - if ($preview) { - $profile = new FeedSubPreviewProfile(); - } else { - $profile = new Profile(); - } - - // @todo validate/normalize nick? - $profile->nickname = $this->feed->title; - $profile->fullname = $this->feed->title; - $profile->homepage = $this->getAltLink($this->feed); - $profile->bio = $this->feed->description; - $profile->profileurl = $this->getAltLink($this->feed); - - if ($preview) { - $profile->avatar = $this->getAvatar(); - } - - // @todo tags from categories - // @todo lat/lon/location? - - return $profile; - } - - function notice($index=1, $preview=false) - { - $entry = $this->feed->getEntryByOffset($index); - if (!$entry) { - return null; - } - - if ($preview) { - $notice = new FeedSubPreviewNotice($this->profile(true)); - $notice->id = -1; - } else { - $notice = new Notice(); - $notice->profile_id = $this->profileIdForEntry($index); - } - - $link = $this->getAltLink($entry); - if (empty($link)) { - if (preg_match('!^https?://!', $entry->id)) { - $link = $entry->id; - common_log(LOG_DEBUG, "No link on entry, using URL from id: $link"); - } - } - $notice->uri = $link; - $notice->url = $link; - $notice->content = $this->noticeFromEntry($entry); - $notice->rendered = common_render_content($notice->content, $notice); // @fixme this is failing on group posts - $notice->created = common_sql_date($entry->updated); // @fixme - $notice->is_local = Notice::GATEWAY; - $notice->source = 'feed'; - - $location = $this->getLocation($entry); - if ($location) { - if ($location->location_id) { - $notice->location_ns = $location->location_ns; - $notice->location_id = $location->location_id; - } - $notice->lat = $location->lat; - $notice->lon = $location->lon; - } - - return $notice; - } - - function profileIdForEntry($index=1) - { - // hack hack hack - // should get profile for this entry's author... - $feeduri = $this->getSelfLink(); - $remote = Ostatus_profile::staticGet('feeduri', $feeduri); - if ($remote) { - return $remote->profile_id; - } else { - throw new Exception("Can't find feed profile for $feeduri"); - } - } - - /** - * Parse location given as a GeoRSS-simple point, if provided. - * http://www.georss.org/simple - * - * @param feed item $entry - * @return mixed Location or false - */ - function getLocation($entry) - { - $dom = $entry->model; - $points = $dom->getElementsByTagNameNS('http://www.georss.org/georss', 'point'); - - for ($i = 0; $i < $points->length; $i++) { - $point = $points->item(0)->textContent; - $point = str_replace(',', ' ', $point); // per spec "treat commas as whitespace" - $point = preg_replace('/\s+/', ' ', $point); - $point = trim($point); - $coords = explode(' ', $point); - if (count($coords) == 2) { - list($lat, $lon) = $coords; - if (is_numeric($lat) && is_numeric($lon)) { - common_log(LOG_INFO, "Looking up location for $lat $lon from georss"); - return Location::fromLatLon($lat, $lon); - } - } - common_log(LOG_ERR, "Ignoring bogus georss:point value $point"); - } - - return false; - } - - /** - * @param XML_Feed_Type $entry - * @return string notice text, within post size limit - */ - function noticeFromEntry($entry) - { - $max = Notice::maxContent(); - $ellipsis = "\xe2\x80\xa6"; // U+2026 HORIZONTAL ELLIPSIS - $title = $entry->title; - $link = $entry->link; - - // @todo We can get entries like this: - // $cats = $entry->getCategory('category', array(0, true)); - // but it feels like an awful hack. If it's accessible cleanly, - // try adding #hashtags from the categories/tags on a post. - - $title = $entry->title; - $link = $this->getAltLink($entry); - if ($link) { - // Blog post or such... - // @todo Should we force a language here? - $format = _m('New post: "%1$s" %2$s'); - $out = sprintf($format, $title, $link); - - // Trim link if needed... - if (mb_strlen($out) > $max) { - $link = common_shorten_url($link); - $out = sprintf($format, $title, $link); - } - - // Trim title if needed... - if (mb_strlen($out) > $max) { - $used = mb_strlen($out) - mb_strlen($title); - $available = $max - $used - mb_strlen($ellipsis); - $title = mb_substr($title, 0, $available) . $ellipsis; - $out = sprintf($format, $title, $link); - } - } else { - // No link? Consider a bare status update. - if (mb_strlen($title) > $max) { - $available = $max - mb_strlen($ellipsis); - $out = mb_substr($title, 0, $available) . $ellipsis; - } else { - $out = $title; - } - } - - return $out; - } -} From 3d665f82d17d36c11bf4f36e84fdeedd911d62c8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Feb 2010 22:13:47 -0500 Subject: [PATCH 039/190] add type='text/html' to alternate link in Notice Atom --- classes/Notice.php | 1 + 1 file changed, 1 insertion(+) diff --git a/classes/Notice.php b/classes/Notice.php index 7e2b8b4a69..a52cfed70c 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1012,6 +1012,7 @@ class Notice extends Memcached_DataObject $xs->raw($profile->asActivityActor()); $xs->element('link', array('rel' => 'alternate', + 'type' => 'text/html', 'href' => $this->bestUrl())); $xs->element('id', null, $this->uri); From 48edade751cca3ac7363808264a76c470a520528 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Feb 2010 22:18:14 -0500 Subject: [PATCH 040/190] add ActivityContext class and test it --- plugins/OStatus/actions/salmon.php | 1 + plugins/OStatus/classes/Ostatus_profile.php | 32 +------- plugins/OStatus/lib/activity.php | 85 +++++++++++++++++++- plugins/OStatus/tests/ActivityParseTests.php | 53 +++++++++++- 4 files changed, 138 insertions(+), 33 deletions(-) diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index ea5b8e4ea8..e9d6015f43 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -71,6 +71,7 @@ class SalmonAction extends Action /** * @fixme probably call Ostatus_profile::processFeed */ + function handle($args) { common_log(LOG_INFO, 'Salmon: incoming post for user '. $this->user->id); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 1ce8ac4917..e0cb467e5e 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -488,36 +488,6 @@ class Ostatus_profile extends Memcached_DataObject $params); } - /** - * Parse location given as a GeoRSS-simple point, if provided. - * http://www.georss.org/simple - * - * @param feed item $entry - * @return mixed Location or false - */ - function getLocation($dom) - { - $points = $dom->getElementsByTagNameNS('http://www.georss.org/georss', 'point'); - - for ($i = 0; $i < $points->length; $i++) { - $point = $points->item(0)->textContent; - $point = str_replace(',', ' ', $point); // per spec "treat commas as whitespace" - $point = preg_replace('/\s+/', ' ', $point); - $point = trim($point); - $coords = explode(' ', $point); - if (count($coords) == 2) { - list($lat, $lon) = $coords; - if (is_numeric($lat) && is_numeric($lon)) { - common_log(LOG_INFO, "Looking up location for $lat $lon from georss"); - return Location::fromLatLon($lat, $lon); - } - } - common_log(LOG_ERR, "Ignoring bogus georss:point value $point"); - } - - return false; - } - /** * @param string $profile_url * @return Ostatus_profile @@ -560,7 +530,7 @@ class Ostatus_profile extends Memcached_DataObject // ripped from oauthstore.php (for old OMB client) $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); copy($url, $temp_filename); - + // @fixme should we be using different ids? $imagefile = new ImageFile($this->id, $temp_filename); $filename = Avatar::filename($this->id, diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 3ed613dc7f..5bc8f78e52 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -311,6 +311,87 @@ class ActivityVerb const LEAVE = 'http://ostatus.org/schema/1.0/leave'; } +class ActivityContext +{ + public $replyToID; + public $replyToUrl; + public $location; + public $attention = array(); + public $conversation; + + const THR = 'http://purl.org/syndication/thread/1.0'; + const GEORSS = 'http://www.georss.org/georss'; + const OSTATUS = 'http://ostatus.org/schema/1.0'; + + const INREPLYTO = 'in-reply-to'; + const REF = 'ref'; + const HREF = 'href'; + + const POINT = 'point'; + + const ATTENTION = 'ostatus:attention'; + const CONVERSATION = 'ostatus:conversation'; + + function __construct($element) + { + $replyToEl = ActivityUtils::child($element, self::INREPLYTO, self::THR); + + if (!empty($replyToEl)) { + $this->replyToID = $replyToEl->getAttribute(self::REF); + $this->replyToUrl = $replyToEl->getAttribute(self::HREF); + } + + $this->location = $this->getLocation($element); + + $this->conversation = ActivityUtils::getLink($element, self::CONVERSATION); + + // Multiple attention links allowed + + $links = $element->getElementsByTagNameNS(ActivityUtils::ATOM, ActivityUtils::LINK); + + for ($i = 0; $i < $links->length; $i++) { + + $link = $links->item($i); + + $linkRel = $link->getAttribute(ActivityUtils::REL); + + if ($linkRel == self::ATTENTION) { + $this->attention[] = $link->getAttribute(self::HREF); + } + } + } + + /** + * Parse location given as a GeoRSS-simple point, if provided. + * http://www.georss.org/simple + * + * @param feed item $entry + * @return mixed Location or false + */ + function getLocation($dom) + { + $points = $dom->getElementsByTagNameNS(self::GEORSS, self::POINT); + + for ($i = 0; $i < $points->length; $i++) { + $point = $points->item($i)->textContent; + $point = str_replace(',', ' ', $point); // per spec "treat commas as whitespace" + $point = preg_replace('/\s+/', ' ', $point); + $point = trim($point); + $coords = explode(' ', $point); + if (count($coords) == 2) { + list($lat, $lon) = $coords; + if (is_numeric($lat) && is_numeric($lon)) { + common_log(LOG_INFO, "Looking up location for $lat $lon from georss"); + return Location::fromLatLon($lat, $lon); + } + } + common_log(LOG_ERR, "Ignoring bogus georss:point value $point"); + } + + return null; + } +} + /** * An activity in the ActivityStrea.ms world * @@ -426,7 +507,9 @@ class Activity $contextEl = $this->_child($entry, self::CONTEXT); if (!empty($contextEl)) { - $this->context = new ActivityObject($contextEl); + $this->context = new ActivityContext($contextEl); + } else { + $this->context = new ActivityContext($entry); } $targetEl = $this->_child($entry, self::TARGET); diff --git a/plugins/OStatus/tests/ActivityParseTests.php b/plugins/OStatus/tests/ActivityParseTests.php index fa8bcdda23..35b4b0f9d7 100644 --- a/plugins/OStatus/tests/ActivityParseTests.php +++ b/plugins/OStatus/tests/ActivityParseTests.php @@ -57,12 +57,35 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertEquals($act->object->summary, 'Some text.'); $this->assertEquals($act->object->link, 'http://example.org/2003/12/13/atom03.html'); - $this->assertTrue(empty($act->context)); + $this->assertFalse(empty($act->context)); + $this->assertTrue(empty($act->target)); $this->assertEquals($act->entry, $entry); $this->assertEquals($act->feed, $feed); } + + public function testExample4() + { + global $_example4; + $dom = DOMDocument::loadXML($_example4); + + $entry = $dom->documentElement; + + $act = new Activity($entry); + + $this->assertFalse(empty($act)); + $this->assertEquals(1266547958, $act->time); + $this->assertEquals('http://example.net/notice/14', $act->link); + + $this->assertFalse(empty($act->context)); + $this->assertEquals('http://example.net/notice/12', $act->context->replyToID); + $this->assertEquals('http://example.net/notice/12', $act->context->replyToUrl); + $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->actor)); + } } $_example1 = << EXAMPLE3; + +$_example4 = << + + @evan now is the time for all good men to come to the aid of their country. #thetime + @evan now is the time for all good men to come to the aid of their country. #thetime + + spock + http://example.net/user/2 + + + http://activitystrea.ms/schema/1.0/person + http://example.net/user/2 + spock + + + + http://example.net/notice/14 + 2010-02-19T02:52:38+00:00 + 2010-02-19T02:52:38+00:00 + + + + + @<span class="vcard"><a href="http://example.net/user/1" class="url"><span class="fn nickname">evan</span></a></span> now is the time for all good men to come to the aid of their country. #<span class="tag"><a href="http://example.net/tag/thetime" rel="tag">thetime</a></span> + + +EXAMPLE4; From b03c7a383f00a97b08a270c6c472b46e11314b84 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 19 Feb 2010 13:03:26 +0100 Subject: [PATCH 041/190] Only load json2.js if native JSON is not supported --- lib/action.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action.php b/lib/action.php index b85f353a3d..cd84662c96 100644 --- a/lib/action.php +++ b/lib/action.php @@ -249,7 +249,7 @@ class Action extends HTMLOutputter // lawsuit $this->script('jquery.min.js'); $this->script('jquery.form.js'); $this->script('jquery.cookie.js'); - $this->script('json2.js'); + $this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.js').'"); }'); $this->script('jquery.joverlay.min.js'); Event::handle('EndShowJQueryScripts', array($this)); } From 8d59f7cc9d7f9f12d46530db2d9efe0b7aaac1a5 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 19 Feb 2010 13:13:05 +0100 Subject: [PATCH 042/190] Using inlineScript instead for clickjacking check --- lib/action.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/action.php b/lib/action.php index cd84662c96..fa9ddb9110 100644 --- a/lib/action.php +++ b/lib/action.php @@ -259,8 +259,7 @@ class Action extends HTMLOutputter // lawsuit $this->script('util.js'); $this->script('geometa.js'); // Frame-busting code to avoid clickjacking attacks. - $this->element('script', array('type' => 'text/javascript'), - 'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }'); + $this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }'); Event::handle('EndShowStatusNetScripts', array($this)); Event::handle('EndShowLaconicaScripts', array($this)); } From 52e8aa798a23b2832a748189b42c3bc77d65c9c7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 19 Feb 2010 08:16:45 -0500 Subject: [PATCH 043/190] Refactor subs_* functions for remote use The subs_* functions in subs.php have made a lot of assumptions about users versus profiles. I've refactored the functions to be methods of the Subscription class instead, and to use Profile objects throughout. Some of the checks for blocks or existing subscriptions depended on users or profiles, so I've moved those methods around a bit. I've left stubs for the subs_* functions until we get time to replace them. --- classes/Profile.php | 12 +++ classes/Subscription.php | 154 ++++++++++++++++++++++++++++++++++++++- classes/User.php | 19 +---- lib/subs.php | 112 ++-------------------------- 4 files changed, 170 insertions(+), 127 deletions(-) diff --git a/classes/Profile.php b/classes/Profile.php index 494c697e42..6b396c8c34 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -868,4 +868,16 @@ class Profile extends Memcached_DataObject return $uri; } + function hasBlocked($other) + { + $block = Profile_block::get($this->id, $other->id); + + if (empty($block)) { + $result = false; + } else { + $result = true; + } + + return $result; + } } diff --git a/classes/Subscription.php b/classes/Subscription.php index faf1331cda..d6fb3fcbdd 100644 --- a/classes/Subscription.php +++ b/classes/Subscription.php @@ -24,7 +24,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Subscription extends Memcached_DataObject +class Subscription extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -34,8 +34,8 @@ class Subscription extends Memcached_DataObject public $subscribed; // int(4) primary_key not_null public $jabber; // tinyint(1) default_1 public $sms; // tinyint(1) default_1 - public $token; // varchar(255) - public $secret; // varchar(255) + public $token; // varchar(255) + public $secret; // varchar(255) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP @@ -45,9 +45,155 @@ class Subscription extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Subscription', $kv); } + + /** + * Make a new subscription + * + * @param Profile $subscriber party to receive new notices + * @param Profile $other party sending notices; publisher + * + * @return Subscription new subscription + */ + + static function start($subscriber, $other) + { + if (!$subscriber->hasRight(Right::SUBSCRIBE)) { + throw new Exception(_('You have been banned from subscribing.')); + } + + if (self::exists($subscriber, $other)) { + throw new Exception(_('Already subscribed!')); + } + + if ($other->hasBlocked($subscriber)) { + throw new Exception(_('User has blocked you.')); + } + + if (Event::handle('StartSubscribe', array($subscriber, $other))) { + + $sub = new Subscription(); + + $sub->subscriber = $subscriber->id; + $sub->subscribed = $other->id; + $sub->created = common_sql_now(); + + $result = $sub->insert(); + + if (!$result) { + common_log_db_error($sub, 'INSERT', __FILE__); + throw new Exception(_('Could not save subscription.')); + } + + $sub->notify(); + + self::blow('user:notices_with_friends:%d', $subscriber->id); + + $subscriber->blowSubscriptionsCount(); + $other->blowSubscribersCount(); + + $otherUser = User::staticGet('id', $other->id); + + if (!empty($otherUser) && + $otherUser->autosubscribe && + !self::exists($other, $subscriber) && + !$subscriber->hasBlocked($other)) { + + $auto = new Subscription(); + + $auto->subscriber = $subscriber->id; + $auto->subscribed = $other->id; + $auto->created = common_sql_now(); + + $result = $auto->insert(); + + if (!$result) { + common_log_db_error($auto, 'INSERT', __FILE__); + throw new Exception(_('Could not save subscription.')); + } + + $auto->notify(); + } + + Event::handle('EndSubscribe', array($subscriber, $other)); + } + + return true; + } + + function notify() + { + # XXX: add other notifications (Jabber, SMS) here + # XXX: queue this and handle it offline + # XXX: Whatever happens, do it in Twitter-like API, too + + $this->notifyEmail(); + } + + function notifyEmail() + { + $subscribedUser = User::staticGet('id', $this->subscribed); + + if (!empty($subscribedUser)) { + + $subscriber = Profile::staticGet('id', $this->subscriber); + + mail_subscribe_notify_profile($subscribedUser, $subscriber); + } + } + + /** + * Cancel a subscription + * + */ + + function cancel($subscriber, $other) + { + if (!self::exists($subscriber, $other)) { + throw new Exception(_('Not subscribed!')); + } + + // Don't allow deleting self subs + + if ($subscriber->id == $other->id) { + throw new Exception(_('Couldn\'t delete self-subscription.')); + } + + if (Event::handle('StartUnsubscribe', array($subscriber, $other))) { + + $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id, + 'subscribed' => $other->id)); + + // note we checked for existence above + + assert(!empty($sub)); + + $result = $sub->delete(); + + if (!$result) { + common_log_db_error($sub, 'DELETE', __FILE__); + throw new Exception(_('Couldn\'t delete subscription.')); + } + + self::blow('user:notices_with_friends:%d', $subscriber->id); + + $subscriber->blowSubscriptionsCount(); + $other->blowSubscribersCount(); + + Event::handle('EndUnsubscribe', array($subscriber, $other)); + } + + return; + } + + function exists($subscriber, $other) + { + $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id, + 'subscribed' => $other->id)); + return (empty($sub)) ? false : true; + } } diff --git a/classes/User.php b/classes/User.php index 72c3f39e94..10b1f48651 100644 --- a/classes/User.php +++ b/classes/User.php @@ -80,11 +80,7 @@ class User extends Memcached_DataObject function isSubscribed($other) { - assert(!is_null($other)); - // XXX: cache results of this query - $sub = Subscription::pkeyGet(array('subscriber' => $this->id, - 'subscribed' => $other->id)); - return (is_null($sub)) ? false : true; + return Subscription::exists($this->getProfile(), $other); } // 'update' won't write key columns, so we have to do it ourselves. @@ -167,17 +163,8 @@ class User extends Memcached_DataObject function hasBlocked($other) { - - $block = Profile_block::get($this->id, $other->id); - - if (is_null($block)) { - $result = false; - } else { - $result = true; - $block->free(); - } - - return $result; + $profile = $this->getProfile(); + return $profile->hasBlocked($other); } /** diff --git a/lib/subs.php b/lib/subs.php index 5ac1a75a5c..5376e21bda 100644 --- a/lib/subs.php +++ b/lib/subs.php @@ -19,8 +19,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once('XMPPHP/XMPP.php'); - /* Subscribe $user to nickname $other_nickname Returns true or an error message. */ @@ -44,72 +42,12 @@ function subs_subscribe_user($user, $other_nickname) function subs_subscribe_to($user, $other) { - if (!$user->hasRight(Right::SUBSCRIBE)) { - return _('You have been banned from subscribing.'); - } - - if ($user->isSubscribed($other)) { - return _('Already subscribed!'); - } - - if ($other->hasBlocked($user)) { - return _('User has blocked you.'); - } - try { - if (Event::handle('StartSubscribe', array($user, $other))) { - - if (!$user->subscribeTo($other)) { - return _('Could not subscribe.'); - return; - } - - subs_notify($other, $user); - - $cache = common_memcache(); - - if ($cache) { - $cache->delete(common_cache_key('user:notices_with_friends:' . $user->id)); - } - - $profile = $user->getProfile(); - - $profile->blowSubscriptionsCount(); - $other->blowSubscribersCount(); - - if ($other->autosubscribe && !$other->isSubscribed($user) && !$user->hasBlocked($other)) { - if (!$other->subscribeTo($user)) { - return _('Could not subscribe other to you.'); - } - $cache = common_memcache(); - - if ($cache) { - $cache->delete(common_cache_key('user:notices_with_friends:' . $other->id)); - } - - subs_notify($user, $other); - } - - Event::handle('EndSubscribe', array($user, $other)); - } + Subscription::start($user->getProfile(), $other); + return true; } catch (Exception $e) { return $e->getMessage(); } - - return true; -} - -function subs_notify($listenee, $listener) -{ - # XXX: add other notifications (Jabber, SMS) here - # XXX: queue this and handle it offline - # XXX: Whatever happens, do it in Twitter-like API, too - subs_notify_email($listenee, $listener); -} - -function subs_notify_email($listenee, $listener) -{ - mail_subscribe_notify($listenee, $listener); } /* Unsubscribe $user from nickname $other_nickname @@ -128,52 +66,12 @@ function subs_unsubscribe_user($user, $other_nickname) return subs_unsubscribe_to($user, $other->getProfile()); } -/* Unsubscribe user $user from profile $other - * NB: other can be a remote user. */ - function subs_unsubscribe_to($user, $other) { - if (!$user->isSubscribed($other)) - return _('Not subscribed!'); - - // Don't allow deleting self subs - - if ($user->id == $other->id) { - return _('Couldn\'t delete self-subscription.'); - } - try { - if (Event::handle('StartUnsubscribe', array($user, $other))) { - - $sub = DB_DataObject::factory('subscription'); - - $sub->subscriber = $user->id; - $sub->subscribed = $other->id; - - $sub->find(true); - - // note we checked for existence above - - if (!$sub->delete()) - return _('Couldn\'t delete subscription.'); - - $cache = common_memcache(); - - if ($cache) { - $cache->delete(common_cache_key('user:notices_with_friends:' . $user->id)); - } - - $profile = $user->getProfile(); - - $profile->blowSubscriptionsCount(); - $other->blowSubscribersCount(); - - Event::handle('EndUnsubscribe', array($user, $other)); - } + Subscription::cancel($user->getProfile(), $other); + return true; } catch (Exception $e) { return $e->getMessage(); } - - return true; -} - +} \ No newline at end of file From b0a75a2ab24673452674a8f296ca4dbb110bed6b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 19 Feb 2010 08:31:20 -0500 Subject: [PATCH 044/190] replace calls to subs_(un)subscribe_user with Subscription methods --- actions/apifriendshipsdestroy.php | 9 +++------ lib/command.php | 29 +++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/actions/apifriendshipsdestroy.php b/actions/apifriendshipsdestroy.php index 91c6fd0324..d48a577562 100644 --- a/actions/apifriendshipsdestroy.php +++ b/actions/apifriendshipsdestroy.php @@ -124,12 +124,9 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction return; } - $result = subs_unsubscribe_user($this->user, $this->other->nickname); - - if (is_string($result)) { - $this->clientError($result, 403, $this->format); - return; - } + // throws an exception on error + Subscription::cancel($this->user->getProfile(), + $this->other->getProfile()); $this->initDocument($this->format); $this->showProfile($this->other, $this->format); diff --git a/lib/command.php b/lib/command.php index 2a51fd6872..ea7b60372d 100644 --- a/lib/command.php +++ b/lib/command.php @@ -548,12 +548,19 @@ class SubCommand extends Command return; } - $result = subs_subscribe_user($this->user, $this->other); + $otherUser = User::staticGet('nickname', $this->other); - if ($result == 'true') { + if (empty($otherUser)) { + $channel->error($this->user, _('No such user')); + return; + } + + try { + Subscription::start($this->user->getProfile(), + $otherUser->getProfile()); $channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other)); - } else { - $channel->error($this->user, $result); + } catch (Exception $e) { + $channel->error($this->user, $e->getMessage()); } } } @@ -576,12 +583,18 @@ class UnsubCommand extends Command return; } - $result=subs_unsubscribe_user($this->user, $this->other); + $otherUser = User::staticGet('nickname', $this->other); - if ($result) { + if (empty($otherUser)) { + $channel->error($this->user, _('No such user')); + } + + try { + Subscription::cancel($this->user->getProfile(), + $otherUser->getProfile()); $channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other)); - } else { - $channel->error($this->user, $result); + } catch (Exception $e) { + $channel->error($this->user, $e->getMessage()); } } } From 512e8b69f1e6020e97835f1c5c492c2be3eff4c1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 19 Feb 2010 08:31:46 -0500 Subject: [PATCH 045/190] remove unused subs_(un)subscribe_user functions --- lib/subs.php | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/lib/subs.php b/lib/subs.php index 5376e21bda..1c240c475d 100644 --- a/lib/subs.php +++ b/lib/subs.php @@ -19,22 +19,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -/* Subscribe $user to nickname $other_nickname - Returns true or an error message. -*/ - -function subs_subscribe_user($user, $other_nickname) -{ - - $other = User::staticGet('nickname', $other_nickname); - - if (!$other) { - return _('No such user.'); - } - - return subs_subscribe_to($user, $other); -} - /* Subscribe user $user to other user $other. * Note: $other must be a local user, not a remote profile. * Because the other way is quite a bit more complicated. @@ -50,22 +34,6 @@ function subs_subscribe_to($user, $other) } } -/* Unsubscribe $user from nickname $other_nickname - Returns true or an error message. -*/ - -function subs_unsubscribe_user($user, $other_nickname) -{ - - $other = User::staticGet('nickname', $other_nickname); - - if (!$other) { - return _('No such user.'); - } - - return subs_unsubscribe_to($user, $other->getProfile()); -} - function subs_unsubscribe_to($user, $other) { try { From 114eb310ca4f53e09c98f2337850829a9036c133 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 19 Feb 2010 10:29:06 -0800 Subject: [PATCH 046/190] OStatus: fix up Salmon endpoint detection/saving, timestamp fixes. --- plugins/OStatus/actions/salmon.php | 2 +- plugins/OStatus/classes/FeedSub.php | 2 +- plugins/OStatus/classes/Ostatus_profile.php | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index e9d6015f43..2da9db9eb7 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -142,7 +142,7 @@ class SalmonAction extends Action function ensureProfile() { $actor = $this->act->actor; - + common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); if (empty($actor->id)) { throw new Exception("Received a salmon slap from unidentified actor."); } diff --git a/plugins/OStatus/classes/FeedSub.php b/plugins/OStatus/classes/FeedSub.php index dc2c0b710b..bf9d063fa1 100644 --- a/plugins/OStatus/classes/FeedSub.php +++ b/plugins/OStatus/classes/FeedSub.php @@ -99,7 +99,7 @@ class FeedSub extends Memcached_DataObject 'sub_state' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'sub_start' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, 'sub_end' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, - 'last_update' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, + 'last_update' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index e0cb467e5e..319b76a661 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -328,7 +328,7 @@ class Ostatus_profile extends Memcached_DataObject $entry->element('id', null, $id); $entry->element('title', null, $text); $entry->element('summary', null, $text); - $entry->element('published', null, common_date_w3dtf(time())); + $entry->element('published', null, common_date_w3dtf(common_sql_now())); $entry->element('activity:verb', null, $verb); $entry->raw($actor->asAtomAuthor()); @@ -516,7 +516,7 @@ class Ostatus_profile extends Memcached_DataObject throw new FeedSubException('empty feed'); } $first = new Activity($entries->item(0), $discover->feed); - return self::ensureActorProfile($first, $feeduri); + return self::ensureActorProfile($first, $feeduri, $salmonuri); } /** @@ -598,13 +598,14 @@ class Ostatus_profile extends Memcached_DataObject * * @param Activity $activity * @param string $feeduri if we already know the canonical feed URI! + * @param string $salmonuri if we already know the salmon return channel URI * @return Ostatus_profile */ - public static function ensureActorProfile($activity, $feeduri=null) + public static function ensureActorProfile($activity, $feeduri=null, $salmonuri=null) { $profile = self::getActorProfile($activity); if (!$profile) { - $profile = self::createActorProfile($activity, $feeduri); + $profile = self::createActorProfile($activity, $feeduri, $salmonuri); } return $profile; } @@ -640,7 +641,7 @@ class Ostatus_profile extends Memcached_DataObject /** * @fixme validate stuff somewhere */ - protected static function createActorProfile($activity, $feeduri=null) + protected static function createActorProfile($activity, $feeduri=null, $salmonuri=null) { $actor = $activity->actor; $homeuri = self::getActorProfileURI($activity); @@ -674,10 +675,17 @@ class Ostatus_profile extends Memcached_DataObject $oprofile = new Ostatus_profile(); $oprofile->uri = $homeuri; if ($feeduri) { + // If we don't have these, we can look them up later. $oprofile->feeduri = $feeduri; + if ($salmonuri) { + $oprofile->salmonuri = $salmonuri; + } } $oprofile->profile_id = $profile->id; + $oprofile->created = common_sql_now(); + $oprofile->modified = common_sql_now(); + $ok = $oprofile->insert(); if ($ok) { $oprofile->updateAvatar($avatar); From a1a3ab1c58cf8636c4e9ac6b9d44bdc18946a547 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 19 Feb 2010 12:08:07 -0800 Subject: [PATCH 047/190] OStatus: hooked up follow/unfollow events on Salmon endpoint to create/destroy remote subscriber relationships --- plugins/OStatus/OStatusPlugin.php | 9 ++- plugins/OStatus/actions/feedsubsettings.php | 8 --- plugins/OStatus/actions/salmon.php | 66 ++++++++++++++++++--- plugins/OStatus/classes/Ostatus_profile.php | 22 +++++-- 4 files changed, 81 insertions(+), 24 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 4ebe4551ec..4c43d8a303 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -253,17 +253,22 @@ class OStatusPlugin extends Plugin */ function onEndUnsubscribe($user, $other) { + if ($user instanceof Profile) { + $profile = $user; + } else if ($user instanceof Profile) { + $profile = $user->getProfile(); + } $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); if ($oprofile) { // Notify the remote server of the unsub, if supported. - $oprofile->notify($user->getProfile(), ActivityVerb::UNFOLLOW, $oprofile); + $oprofile->notify($profile, ActivityVerb::UNFOLLOW, $oprofile); // Drop the PuSH subscription if there are no other subscribers. $sub = new Subscription(); $sub->subscribed = $other->id; $sub->limit(1); if (!$sub->find(true)) { - common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri on hub $oprofile->huburi"); + common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri"); $oprofile->unsubscribe(); } } diff --git a/plugins/OStatus/actions/feedsubsettings.php b/plugins/OStatus/actions/feedsubsettings.php index 3e1d0aa823..aee4cee9af 100644 --- a/plugins/OStatus/actions/feedsubsettings.php +++ b/plugins/OStatus/actions/feedsubsettings.php @@ -68,14 +68,6 @@ class FeedSubSettingsAction extends ConnectSettingsAction $profile = $user->getProfile(); - $fuser = null; - - $flink = Foreign_link::getByUserID($user->id, FEEDSUB_SERVICE); - - if (!empty($flink)) { - $fuser = $flink->getForeignUser(); - } - $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_feedsub', 'class' => 'form_settings', diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index 2da9db9eb7..1ed322ed28 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -63,13 +63,17 @@ class SalmonAction extends Action // XXX: check that document element is Atom entry // XXX: check the signature - $this->act = new Activity($dom->documentElement); + $entries = $dom->getElementsByTagNameNS(Activity::ATOM, 'entry'); + if ($entries && $entries->length) { + // @fixme is it legit to have multiple entries? + $this->act = new Activity($entries->item(0), $dom->documentElement); + } return true; } /** - * @fixme probably call Ostatus_profile::processFeed + * Check the posted activity type and break out to appropriate processing. */ function handle($args) @@ -94,13 +98,19 @@ class SalmonAction extends Action case ActivityVerb::FRIEND: $this->handleFollow(); break; + case ActivityVerb::UNFOLLOW: + $this->handleUnfollow(); + break; } Event::handle('EndHandleSalmon', array($this->user, $this->activity)); } } /** - * @fixme probably call Ostatus_profile::processFeed + * We've gotten a post event on the Salmon backchannel, probably a reply. + * + * @todo validate if we need to handle this post, then call into + * ostatus_profile's general incoming-post handling. */ function handlePost() { @@ -116,43 +126,81 @@ class SalmonAction extends Action } $profile = $this->ensureProfile(); + // @fixme do something with the post } /** - * @fixme probably call Ostatus_profile::processFeed + * We've gotten a follow/subscribe notification from a remote user. + * Save a subscription relationship for them. */ function handleFollow() { + $oprofile = $this->ensureProfile(); + if ($oprofile) { + common_log(LOG_INFO, "Setting up subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); + $oprofile->subscribeRemoteToLocal($this->user); + } else { + common_log(LOG_INFO, "Can't set up subscription from remote; missing profile."); + } } /** - * @fixme probably call Ostatus_profile::processFeed + * We've gotten an unfollow/unsubscribe notification from a remote user. + * Check if we have a subscription relationship for them and kill it. + * + * @fixme probably catch exceptions on fail? + */ + function handleUnfollow() + { + $oprofile = $this->ensureProfile(); + if ($oprofile) { + common_log(LOG_INFO, "Canceling subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); + Subscription::cancel($oprofile->localProfile(), $this->user->getProfile()); + } else { + common_log(LOG_ERR, "Can't cancel subscription from remote, didn't find the profile"); + } + } + + /** + * Remote user likes one of our posts. + * Confirm the post is ours, and save a local favorite event. */ function handleFavorite() { } /** - * @fixme probably call Ostatus_profile::processFeed + * Remote user doesn't like one of our posts after all! + * Confirm the post is ours, and save a local favorite event. + */ + function handleUnfavorite() + { + } + + /** + * Hmmmm */ function handleShare() { } + /** + * @return Ostatus_profile + */ function ensureProfile() { $actor = $this->act->actor; common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); if (empty($actor->id)) { + common_log(LOG_ERR, "broken actor: " . var_export($actor, true)); throw new Exception("Received a salmon slap from unidentified actor."); } - $ostatusProfile = Ostatus_profile::ensureActorProfile($this->act); - return $oprofile->localProfile(); + return Ostatus_profile::ensureActorProfile($this->act); } /** - * @fixme anything new in here probably should be merged into Ostatus_profile::ensureActorProfile and friends + * @fixme merge into Ostatus_profile::ensureActorProfile and friends */ function createProfile() { diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 319b76a661..97d8eec101 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -310,8 +310,15 @@ class Ostatus_profile extends Memcached_DataObject * @param $verb eg Activity::SUBSCRIBE or Activity::JOIN * @param $object object of the action; if null, the remote entity itself is assumed */ - public function notify(Profile $actor, $verb, $object=null) + public function notify($actor, $verb, $object=null) { + if (!($actor instanceof Profile)) { + $type = gettype($actor); + if ($type == 'object') { + $type = get_class($actor); + } + throw new ServerException("Invalid actor passed to " . __METHOD__ . ": " . $type); + } if ($object == null) { $object = $this; } @@ -340,7 +347,7 @@ class Ostatus_profile extends Memcached_DataObject $feed->addEntry($entry); $xml = $feed->getString(); - common_log(LOG_INFO, "Posting to Salmon endpoint $salmon: $xml"); + common_log(LOG_INFO, "Posting to Salmon endpoint $this->salmonuri: $xml"); $salmon = new Salmon(); // ? $salmon->post($this->salmonuri, $xml); @@ -531,9 +538,14 @@ class Ostatus_profile extends Memcached_DataObject $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); copy($url, $temp_filename); + if ($this->isGroup()) { + $id = $this->group_id; + } else { + $id = $this->profile_id; + } // @fixme should we be using different ids? - $imagefile = new ImageFile($this->id, $temp_filename); - $filename = Avatar::filename($this->id, + $imagefile = new ImageFile($id, $temp_filename); + $filename = Avatar::filename($id, image_type_to_extension($imagefile->type), null, common_timestamp()); @@ -646,7 +658,7 @@ class Ostatus_profile extends Memcached_DataObject $actor = $activity->actor; $homeuri = self::getActorProfileURI($activity); $nickname = self::getAuthorNick($activity); - $avatar = self::getAvatar($actor, $feed); + $avatar = self::getAvatar($actor, $activity->feed); if (!$homeuri) { common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true)); From b0327506a491f029b239ae703e1acb1d42ae299c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 19 Feb 2010 16:37:07 -0500 Subject: [PATCH 048/190] some more salmon stuff --- plugins/OStatus/actions/salmon.php | 90 +++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index e9d6015f43..7356c489a6 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -112,24 +112,112 @@ class SalmonAction extends Action case ActivityObject::COMMENT: break; default: - throw new Exception("Can't handle that kind of post."); + throw new ClientException("Can't handle that kind of post."); + } + + // Notice must either be a) in reply to a notice by this user + // or b) to the attention of this user + + $context = $this->act->context; + + if (!empty($context->replyToID)) { + $notice = Notice::staticGet('uri', $context->replyToID); + if (empty($notice)) { + throw new ClientException("In reply to unknown notice"); + } + if ($notice->profile_id != $this->user->id) { + throw new ClientException("In reply to a notice not by this user"); + } + } else if (!empty($context->attention)) { + if (!in_array($context->attention, $this->user->uri)) { + throw new ClientException("To the attention of user(s) not including this one!"); + } + } else { + throw new ClientException("Not to anyone in reply to anything!"); } $profile = $this->ensureProfile(); + } /** * @fixme probably call Ostatus_profile::processFeed */ + function handleFollow() { + $object = $this->act->object; + + if ($object->id != $this->user->uri) { + throw new ClientException("Subscription notice not for this user."); + } + + $profile = $this->ensureProfile(); + + $sub = Subscription::pkeyGet(array('subscriber' => $profile->id, + 'subscribed' => $this->user->id)); + + if (!empty($sub)) { + throw new ClientException("Already subscribed."); + } + + if ($this->user->hasBlocked($profile)) { + throw new ClientException("Already subscribed."); + } + } /** * @fixme probably call Ostatus_profile::processFeed */ + function handleFavorite() { + // WORST VARIABLE NAME EVER + $object = $this->act->object; + + switch ($this->act->object->type) { + case ActivityObject::ARTICLE: + case ActivityObject::BLOGENTRY: + case ActivityObject::NOTE: + case ActivityObject::STATUS: + case ActivityObject::COMMENT: + break; + default: + throw new ClientException("Can't handle that kind of object for liking/faving."); + } + + $notice = Notice::staticGet('uri', $object->id); + + if (empty($notice)) { + throw new ClientException("Notice with ID $object->id unknown."); + } + + if ($notice->profile_id != $this->user->id) { + throw new ClientException("Notice with ID $object->id not posted by $this->user->id."); + } + + $profile = $this->ensureProfile(); + + $old = Fave::pkeyGet(array('user_id' => $profile->id, + 'notice_id' => $notice->id)); + + if (!empty($old)) { + throw new ClientException("We already know that's a fave!"); + } + + $fave = new Fave(); + + // @fixme need to change this attribute name, maybe references + $fave->user_id = $profile->id; + $fave->notice_id = $notice->id; + + $result = $fave->insert(); + + if (!$result) { + common_log_db_error($fave, 'INSERT', __FILE__); + throw new ServerException('Could not save new favorite.'); + } } /** From 557df3d3f78dbfce656c4c8e3ddf82ee0e34da0a Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 19 Feb 2010 16:21:17 -0800 Subject: [PATCH 049/190] OStatus: sub/unsub notifications working again. Fixed up autodetection of feed info at profile setup time --- plugins/OStatus/OStatusPlugin.php | 2 ++ plugins/OStatus/actions/salmon.php | 13 +++++++-- plugins/OStatus/classes/Ostatus_profile.php | 31 +++++++++++++-------- plugins/OStatus/lib/salmon.php | 3 ++ 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 4c43d8a303..1b58d3c356 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -331,6 +331,8 @@ class OStatusPlugin extends Plugin $oprofile = Ostatus_profile::staticGet('feeduri', $feedsub->uri); if ($oprofile) { $oprofile->processFeed($feed); + } else { + common_log(LOG_DEBUG, "No ostatus profile for incoming feed $feedsub->uri"); } } } diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index 7a4474ff61..43d79cf4ad 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -34,6 +34,8 @@ class SalmonAction extends Action function prepare($args) { + StatusNet::setApi(true); // Send smaller error pages + parent::prepare($args); if ($_SERVER['REQUEST_METHOD'] != 'POST') { @@ -63,8 +65,12 @@ class SalmonAction extends Action // XXX: check that document element is Atom entry // XXX: check the signature - $this->act = new Activity($dom->documentElement); - + // We need to run an entry into Activity, so get the first one + $entries = $dom->getElementsByTagNameNS(Activity::ATOM, 'entry'); + if ($entries && $entries->length) { + // @fixme is it legit to have multiple entries? + $this->act = new Activity($entries->item(0), $dom->documentElement); + } return true; } @@ -74,7 +80,9 @@ class SalmonAction extends Action function handle($args) { + StatusNet::setApi(true); // Send smaller error pages common_log(LOG_INFO, 'Salmon: incoming post for user '. $this->user->id); + common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); // TODO : Insert new $xml -> notice code @@ -254,7 +262,6 @@ class SalmonAction extends Action function ensureProfile() { $actor = $this->act->actor; - common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); if (empty($actor->id)) { common_log(LOG_ERR, "broken actor: " . var_export($actor, true)); throw new Exception("Received a salmon slap from unidentified actor."); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 97d8eec101..5fe135f962 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -56,7 +56,7 @@ class Ostatus_profile extends Memcached_DataObject return array('uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'profile_id' => DB_DATAOBJECT_INT, 'group_id' => DB_DATAOBJECT_INT, - 'feeduri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'feeduri' => DB_DATAOBJECT_STR, 'salmonuri' => DB_DATAOBJECT_STR, 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); @@ -71,7 +71,7 @@ class Ostatus_profile extends Memcached_DataObject new ColumnDef('group_id', 'integer', null, true, 'UNI'), new ColumnDef('feeduri', 'varchar', - 255, false, 'UNI'), + 255, true, 'UNI'), new ColumnDef('salmonuri', 'text', null, true), new ColumnDef('created', 'datetime', @@ -272,7 +272,7 @@ class Ostatus_profile extends Memcached_DataObject * @return bool true on success, false on failure * @throws ServerException if feed state is not valid */ - public function subscribe($mode='subscribe') + public function subscribe() { $feedsub = FeedSub::ensureFeed($this->feeduri); if ($feedsub->sub_state == 'active' || $feedsub->sub_state == 'subscribe') { @@ -506,7 +506,7 @@ class Ostatus_profile extends Memcached_DataObject $discover = new FeedDiscovery(); $feeduri = $discover->discoverFromURL($profile_uri); - $feedsub = FeedSub::ensureFeed($feeduri, $discover->feed); + //$feedsub = FeedSub::ensureFeed($feeduri, $discover->feed); $huburi = $discover->getAtomLink('hub'); $salmonuri = $discover->getAtomLink('salmon'); @@ -665,6 +665,20 @@ class Ostatus_profile extends Memcached_DataObject throw new ServerException("No profile URI"); } + if (!$feeduri || !$salmonuri) { + // Get the canonical feed URI and check it + $discover = new FeedDiscovery(); + $feeduri = $discover->discoverFromURL($homeuri); + + $huburi = $discover->getAtomLink('hub'); + $salmonuri = $discover->getAtomLink('salmon'); + + if (!$huburi) { + // We can only deal with folks with a PuSH hub + throw new FeedSubNoHubException(); + } + } + $profile = new Profile(); $profile->nickname = $nickname; $profile->fullname = $actor->displayName; @@ -686,13 +700,8 @@ class Ostatus_profile extends Memcached_DataObject // so we can leave it empty until later. $oprofile = new Ostatus_profile(); $oprofile->uri = $homeuri; - if ($feeduri) { - // If we don't have these, we can look them up later. - $oprofile->feeduri = $feeduri; - if ($salmonuri) { - $oprofile->salmonuri = $salmonuri; - } - } + $oprofile->feeduri = $feeduri; + $oprofile->salmonuri = $salmonuri; $oprofile->profile_id = $profile->id; $oprofile->created = common_sql_now(); diff --git a/plugins/OStatus/lib/salmon.php b/plugins/OStatus/lib/salmon.php index 8c77222a62..df17a70068 100644 --- a/plugins/OStatus/lib/salmon.php +++ b/plugins/OStatus/lib/salmon.php @@ -41,9 +41,12 @@ class Salmon $client->setBody($xml); $response = $client->post($endpoint_uri, $headers); } catch (HTTP_Request2_Exception $e) { + common_log(LOG_ERR, "Salmon post to $endpoint_uri failed: " . $e->getMessage()); return false; } if ($response->getStatus() != 200) { + common_log(LOG_ERR, "Salmon at $endpoint_uri returned status " . + $response->getStatus() . ': ' . $response->getBody()); return false; } From 50db2d5d69a8769dc2ddcc937afb130bcce0971d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 19 Feb 2010 17:01:38 -0800 Subject: [PATCH 050/190] OStatus: Salmon notifications now being generated moderately correctly. :) Needs to be an not a . --- plugins/OStatus/actions/salmon.php | 12 +++++------- plugins/OStatus/classes/Ostatus_profile.php | 15 +++++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index 43d79cf4ad..f7c86dc0ce 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -62,15 +62,13 @@ class SalmonAction extends Action $dom = DOMDocument::loadXML($xml); - // XXX: check that document element is Atom entry + if ($dom->documentElement->namespaceURI != Activity::ATOM || + $dom->documentElement->localName != 'entry') { + $this->clientError(_m('Salmon post must be an Atom entry.')); + } // XXX: check the signature - // We need to run an entry into Activity, so get the first one - $entries = $dom->getElementsByTagNameNS(Activity::ATOM, 'entry'); - if ($entries && $entries->length) { - // @fixme is it legit to have multiple entries? - $this->act = new Activity($entries->item(0), $dom->documentElement); - } + $this->act = new Activity($dom->documentElement); return true; } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 5fe135f962..b14b4c9a37 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -329,9 +329,15 @@ class Ostatus_profile extends Memcached_DataObject ':' . $actor->id . ':' . time(); // @fixme - //$entry = new Atom10Entry(); + // @fixme consolidate all these NS settings somewhere + $attributes = array('xmlns' => Activity::ATOM, + 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', + 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', + 'xmlns:georss' => 'http://www.georss.org/georss', + 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); + $entry = new XMLStringer(); - $entry->elementStart('entry'); + $entry->elementStart('entry', $attributes); $entry->element('id', null, $id); $entry->element('title', null, $text); $entry->element('summary', null, $text); @@ -343,10 +349,7 @@ class Ostatus_profile extends Memcached_DataObject $entry->raw($object->asActivityNoun('object')); $entry->elementEnd('entry'); - $feed = $this->atomFeed($actor); - $feed->addEntry($entry); - - $xml = $feed->getString(); + $xml = $entry->getString(); common_log(LOG_INFO, "Posting to Salmon endpoint $this->salmonuri: $xml"); $salmon = new Salmon(); // ? From 2df3bbc80b6c9dd44134bcf3b5b4a09ea1a803d1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 11:12:43 -0500 Subject: [PATCH 051/190] Move some salmon processing to a superclass Moved some salmon processing to a superclass so we could handle group salmon posts, too. --- plugins/OStatus/OStatusPlugin.php | 4 +- plugins/OStatus/actions/groupsalmon.php | 108 ++++++++++++ plugins/OStatus/actions/usersalmon.php | 0 .../salmon.php => lib/salmonaction.php} | 156 +++--------------- 4 files changed, 133 insertions(+), 135 deletions(-) create mode 100644 plugins/OStatus/actions/groupsalmon.php create mode 100644 plugins/OStatus/actions/usersalmon.php rename plugins/OStatus/{actions/salmon.php => lib/salmonaction.php} (52%) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 1b58d3c356..e1f3fd9d37 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -63,10 +63,10 @@ class OStatusPlugin extends Plugin // Salmon endpoint $m->connect('main/salmon/user/:id', - array('action' => 'salmon'), + array('action' => 'usersalmon'), array('id' => '[0-9]+')); $m->connect('main/salmon/group/:id', - array('action' => 'salmongroup'), + array('action' => 'groupsalmon'), array('id' => '[0-9]+')); return true; } diff --git a/plugins/OStatus/actions/groupsalmon.php b/plugins/OStatus/actions/groupsalmon.php new file mode 100644 index 0000000000..64ae9f3cc0 --- /dev/null +++ b/plugins/OStatus/actions/groupsalmon.php @@ -0,0 +1,108 @@ +. + */ + +/** + * @package OStatusPlugin + * @author James Walker + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class GroupsalmonAction extends SalmonAction +{ + var $group = null; + + function prepare($args) + { + parent::prepare($args); + + $id = $this->trimmed('id'); + + if (!$id) { + $this->clientError(_('No ID.')); + } + + $this->group = User_group::staticGet('id', $id); + + if (empty($this->group)) { + $this->clientError(_('No such group.')); + } + + return true; + } + + /** + * We've gotten a post event on the Salmon backchannel, probably a reply. + */ + + function handlePost() + { + switch ($this->act->object->type) { + case ActivityObject::ARTICLE: + case ActivityObject::BLOGENTRY: + case ActivityObject::NOTE: + case ActivityObject::STATUS: + case ActivityObject::COMMENT: + break; + default: + throw new ClientException("Can't handle that kind of post."); + } + + // Notice must be to the attention of this group + + $context = $this->act->context; + + if (empty($context->attention)) { + throw new ClientException("Not to the attention of anyone."); + } else { + $uri = common_local_url('groupbyid', array('id' => $this->group->id)); + if (!in_array($context->attention, $uri)) { + throw new ClientException("Not to the attention of this group."); + } + } + + $profile = $this->ensureProfile(); + // @fixme save the post + } + + /** + * We've gotten a follow/subscribe notification from a remote user. + * Save a subscription relationship for them. + */ + + function handleFollow() + { + $this->handleJoin(); // ??? + } + + function handleUnfollow() + { + } + + /** + * A remote user joined our group. + */ + + function handleJoin() + { + } + +} diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/lib/salmonaction.php similarity index 52% rename from plugins/OStatus/actions/salmon.php rename to plugins/OStatus/lib/salmonaction.php index f7c86dc0ce..7085e4583e 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -28,7 +28,6 @@ if (!defined('STATUSNET')) { class SalmonAction extends Action { - var $user = null; var $xml = null; var $activity = null; @@ -46,18 +45,6 @@ class SalmonAction extends Action $this->clientError(_('Salmon requires application/atom+xml')); } - $id = $this->trimmed('id'); - - if (!$id) { - $this->clientError(_('No ID.')); - } - - $this->user = User::staticGet($id); - - if (empty($this->user)) { - $this->clientError(_('No such user.')); - } - $xml = file_get_contents('php://input'); $dom = DOMDocument::loadXML($xml); @@ -79,12 +66,10 @@ class SalmonAction extends Action function handle($args) { StatusNet::setApi(true); // Send smaller error pages - common_log(LOG_INFO, 'Salmon: incoming post for user '. $this->user->id); - common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); // TODO : Insert new $xml -> notice code - if (Event::handle('StartHandleSalmon', array($this->user, $this->activity))) { + if (Event::handle('StartHandleSalmon', array($this->activity))) { switch ($this->act->verb) { case ActivityVerb::POST: @@ -103,148 +88,44 @@ class SalmonAction extends Action case ActivityVerb::UNFOLLOW: $this->handleUnfollow(); break; + case ActivityVerb::JOIN: + $this->handleJoin(); + break; + default: + throw new ClientException(_("Unimplemented.")); } - Event::handle('EndHandleSalmon', array($this->user, $this->activity)); + Event::handle('EndHandleSalmon', array($this->activity)); } } - /** - * We've gotten a post event on the Salmon backchannel, probably a reply. - * - * @todo validate if we need to handle this post, then call into - * ostatus_profile's general incoming-post handling. - */ function handlePost() { - switch ($this->act->object->type) { - case ActivityObject::ARTICLE: - case ActivityObject::BLOGENTRY: - case ActivityObject::NOTE: - case ActivityObject::STATUS: - case ActivityObject::COMMENT: - break; - default: - throw new ClientException("Can't handle that kind of post."); - } - - // Notice must either be a) in reply to a notice by this user - // or b) to the attention of this user - - $context = $this->act->context; - - if (!empty($context->replyToID)) { - $notice = Notice::staticGet('uri', $context->replyToID); - if (empty($notice)) { - throw new ClientException("In reply to unknown notice"); - } - if ($notice->profile_id != $this->user->id) { - throw new ClientException("In reply to a notice not by this user"); - } - } else if (!empty($context->attention)) { - if (!in_array($context->attention, $this->user->uri)) { - throw new ClientException("To the attention of user(s) not including this one!"); - } - } else { - throw new ClientException("Not to anyone in reply to anything!"); - } - - $profile = $this->ensureProfile(); - // @fixme do something with the post + throw new ClientException(_("Unimplemented!")); } - /** - * We've gotten a follow/subscribe notification from a remote user. - * Save a subscription relationship for them. - */ - function handleFollow() { - $oprofile = $this->ensureProfile(); - if ($oprofile) { - common_log(LOG_INFO, "Setting up subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); - $oprofile->subscribeRemoteToLocal($this->user); - } else { - common_log(LOG_INFO, "Can't set up subscription from remote; missing profile."); - } + throw new ClientException(_("Unimplemented!")); } - /** - * We've gotten an unfollow/unsubscribe notification from a remote user. - * Check if we have a subscription relationship for them and kill it. - * - * @fixme probably catch exceptions on fail? - */ function handleUnfollow() { - $oprofile = $this->ensureProfile(); - if ($oprofile) { - common_log(LOG_INFO, "Canceling subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); - Subscription::cancel($oprofile->localProfile(), $this->user->getProfile()); - } else { - common_log(LOG_ERR, "Can't cancel subscription from remote, didn't find the profile"); - } + throw new ClientException(_("Unimplemented!")); } - /** - * Remote user likes one of our posts. - * Confirm the post is ours, and save a local favorite event. - */ - function handleFavorite() { - // WORST VARIABLE NAME EVER - $object = $this->act->object; - - switch ($this->act->object->type) { - case ActivityObject::ARTICLE: - case ActivityObject::BLOGENTRY: - case ActivityObject::NOTE: - case ActivityObject::STATUS: - case ActivityObject::COMMENT: - break; - default: - throw new ClientException("Can't handle that kind of object for liking/faving."); - } - - $notice = Notice::staticGet('uri', $object->id); - - if (empty($notice)) { - throw new ClientException("Notice with ID $object->id unknown."); - } - - if ($notice->profile_id != $this->user->id) { - throw new ClientException("Notice with ID $object->id not posted by $this->user->id."); - } - - $profile = $this->ensureProfile(); - - $old = Fave::pkeyGet(array('user_id' => $profile->id, - 'notice_id' => $notice->id)); - - if (!empty($old)) { - throw new ClientException("We already know that's a fave!"); - } - - $fave = new Fave(); - - // @fixme need to change this attribute name, maybe references - $fave->user_id = $profile->id; - $fave->notice_id = $notice->id; - - $result = $fave->insert(); - - if (!$result) { - common_log_db_error($fave, 'INSERT', __FILE__); - throw new ServerException('Could not save new favorite.'); - } + throw new ClientException(_("Unimplemented!")); } /** * Remote user doesn't like one of our posts after all! - * Confirm the post is ours, and save a local favorite event. + * Confirm the post is ours, and delete a local favorite event. */ + function handleUnfavorite() { + throw new ClientException(_("Unimplemented!")); } /** @@ -252,6 +133,15 @@ class SalmonAction extends Action */ function handleShare() { + throw new ClientException(_("Unimplemented!")); + } + + /** + * Hmmmm + */ + function handleJoin() + { + throw new ClientException(_("Unimplemented!")); } /** From ed45df045f661e9c3b85e0657986c99c320914f0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 11:17:54 -0500 Subject: [PATCH 052/190] Cool bug! Technically good PHP syntax --- plugins/OStatus/classes/Ostatus_profile.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index b14b4c9a37..9f5c605612 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -149,7 +149,6 @@ class Ostatus_profile extends Memcached_DataObject function asActivityNoun($element) { $xs = new XMLStringer(true); - $avatarHref = Avatar::defaultImage(AVATAR_PROFILE_SIZE); $avatarType = 'image/png'; if ($this->isGroup()) { @@ -173,8 +172,8 @@ class Ostatus_profile extends Memcached_DataObject $self = $this->localProfile(); $avatar = $self->getAvatar(AVATAR_PROFILE_SIZE); if ($avatar) { - $avatarHref = $avatar-> - $avatarType = $avatar->mediatype; + $avatarHref = $avatar->url; + $avatarType = $avatar->mediatype; } } $xs->elementStart('activity:' . $element); @@ -672,10 +671,10 @@ class Ostatus_profile extends Memcached_DataObject // Get the canonical feed URI and check it $discover = new FeedDiscovery(); $feeduri = $discover->discoverFromURL($homeuri); - + $huburi = $discover->getAtomLink('hub'); $salmonuri = $discover->getAtomLink('salmon'); - + if (!$huburi) { // We can only deal with folks with a PuSH hub throw new FeedSubNoHubException(); From 81ea0f81173030c73cfc8dd46946d126d3d41622 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 11:35:01 -0500 Subject: [PATCH 053/190] Add HTMLPurifier to extlib HTMLPurifier defangs arbitrary submitted HTML. We're using it in the OStatus plugin, but it may be valuable for other parts of the codebase (I think OEmbed might benefit, for example). --- extlib/HTMLPurifier/HTMLPurifier.auto.php | 11 + extlib/HTMLPurifier/HTMLPurifier.autoload.php | 21 + extlib/HTMLPurifier/HTMLPurifier.func.php | 23 + extlib/HTMLPurifier/HTMLPurifier.includes.php | 208 + extlib/HTMLPurifier/HTMLPurifier.kses.php | 30 + extlib/HTMLPurifier/HTMLPurifier.path.php | 11 + extlib/HTMLPurifier/HTMLPurifier.php | 237 + .../HTMLPurifier.safe-includes.php | 202 + .../HTMLPurifier/AttrCollections.php | 128 + extlib/HTMLPurifier/HTMLPurifier/AttrDef.php | 87 + .../HTMLPurifier/HTMLPurifier/AttrDef/CSS.php | 87 + .../HTMLPurifier/AttrDef/CSS/AlphaValue.php | 21 + .../HTMLPurifier/AttrDef/CSS/Background.php | 87 + .../AttrDef/CSS/BackgroundPosition.php | 126 + .../HTMLPurifier/AttrDef/CSS/Border.php | 43 + .../HTMLPurifier/AttrDef/CSS/Color.php | 78 + .../HTMLPurifier/AttrDef/CSS/Composite.php | 38 + .../AttrDef/CSS/DenyElementDecorator.php | 28 + .../HTMLPurifier/AttrDef/CSS/Filter.php | 54 + .../HTMLPurifier/AttrDef/CSS/Font.php | 149 + .../HTMLPurifier/AttrDef/CSS/FontFamily.php | 90 + .../AttrDef/CSS/ImportantDecorator.php | 40 + .../HTMLPurifier/AttrDef/CSS/Length.php | 47 + .../HTMLPurifier/AttrDef/CSS/ListStyle.php | 78 + .../HTMLPurifier/AttrDef/CSS/Multiple.php | 58 + .../HTMLPurifier/AttrDef/CSS/Number.php | 69 + .../HTMLPurifier/AttrDef/CSS/Percentage.php | 40 + .../AttrDef/CSS/TextDecoration.php | 38 + .../HTMLPurifier/AttrDef/CSS/URI.php | 56 + .../HTMLPurifier/AttrDef/Enum.php | 65 + .../HTMLPurifier/AttrDef/HTML/Bool.php | 28 + .../HTMLPurifier/AttrDef/HTML/Class.php | 34 + .../HTMLPurifier/AttrDef/HTML/Color.php | 32 + .../HTMLPurifier/AttrDef/HTML/FrameTarget.php | 21 + .../HTMLPurifier/AttrDef/HTML/ID.php | 70 + .../HTMLPurifier/AttrDef/HTML/Length.php | 41 + .../HTMLPurifier/AttrDef/HTML/LinkTypes.php | 53 + .../HTMLPurifier/AttrDef/HTML/MultiLength.php | 41 + .../HTMLPurifier/AttrDef/HTML/Nmtokens.php | 52 + .../HTMLPurifier/AttrDef/HTML/Pixels.php | 48 + .../HTMLPurifier/AttrDef/Integer.php | 73 + .../HTMLPurifier/AttrDef/Lang.php | 73 + .../HTMLPurifier/AttrDef/Switch.php | 34 + .../HTMLPurifier/AttrDef/Text.php | 15 + .../HTMLPurifier/HTMLPurifier/AttrDef/URI.php | 77 + .../HTMLPurifier/AttrDef/URI/Email.php | 17 + .../AttrDef/URI/Email/SimpleCheck.php | 21 + .../HTMLPurifier/AttrDef/URI/Host.php | 62 + .../HTMLPurifier/AttrDef/URI/IPv4.php | 39 + .../HTMLPurifier/AttrDef/URI/IPv6.php | 99 + .../HTMLPurifier/AttrTransform.php | 56 + .../HTMLPurifier/AttrTransform/Background.php | 23 + .../HTMLPurifier/AttrTransform/BdoDir.php | 19 + .../HTMLPurifier/AttrTransform/BgColor.php | 23 + .../HTMLPurifier/AttrTransform/BoolToCSS.php | 36 + .../HTMLPurifier/AttrTransform/Border.php | 18 + .../HTMLPurifier/AttrTransform/EnumToCSS.php | 58 + .../AttrTransform/ImgRequired.php | 42 + .../HTMLPurifier/AttrTransform/ImgSpace.php | 44 + .../HTMLPurifier/AttrTransform/Input.php | 40 + .../HTMLPurifier/AttrTransform/Lang.php | 28 + .../HTMLPurifier/AttrTransform/Length.php | 27 + .../HTMLPurifier/AttrTransform/Name.php | 21 + .../HTMLPurifier/AttrTransform/NameSync.php | 27 + .../HTMLPurifier/AttrTransform/SafeEmbed.php | 15 + .../HTMLPurifier/AttrTransform/SafeObject.php | 16 + .../HTMLPurifier/AttrTransform/SafeParam.php | 50 + .../AttrTransform/ScriptRequired.php | 16 + .../HTMLPurifier/AttrTransform/Textarea.php | 18 + .../HTMLPurifier/HTMLPurifier/AttrTypes.php | 77 + .../HTMLPurifier/AttrValidator.php | 162 + .../HTMLPurifier/HTMLPurifier/Bootstrap.php | 98 + .../HTMLPurifier/CSSDefinition.php | 292 ++ extlib/HTMLPurifier/HTMLPurifier/ChildDef.php | 48 + .../HTMLPurifier/ChildDef/Chameleon.php | 48 + .../HTMLPurifier/ChildDef/Custom.php | 90 + .../HTMLPurifier/ChildDef/Empty.php | 20 + .../HTMLPurifier/ChildDef/Optional.php | 26 + .../HTMLPurifier/ChildDef/Required.php | 117 + .../ChildDef/StrictBlockquote.php | 88 + .../HTMLPurifier/ChildDef/Table.php | 142 + extlib/HTMLPurifier/HTMLPurifier/Config.php | 580 +++ .../HTMLPurifier/ConfigSchema.php | 158 + .../ConfigSchema/Builder/ConfigSchema.php | 44 + .../HTMLPurifier/ConfigSchema/Builder/Xml.php | 106 + .../HTMLPurifier/ConfigSchema/Exception.php | 11 + .../HTMLPurifier/ConfigSchema/Interchange.php | 42 + .../ConfigSchema/Interchange/Directive.php | 77 + .../ConfigSchema/Interchange/Id.php | 37 + .../ConfigSchema/InterchangeBuilder.php | 180 + .../HTMLPurifier/ConfigSchema/Validator.php | 206 + .../ConfigSchema/ValidatorAtom.php | 66 + .../HTMLPurifier/ConfigSchema/schema.ser | Bin 0 -> 12999 bytes .../schema/Attr.AllowedClasses.txt | 8 + .../schema/Attr.AllowedFrameTargets.txt | 12 + .../ConfigSchema/schema/Attr.AllowedRel.txt | 9 + .../ConfigSchema/schema/Attr.AllowedRev.txt | 9 + .../schema/Attr.ClassUseCDATA.txt | 19 + .../schema/Attr.DefaultImageAlt.txt | 11 + .../schema/Attr.DefaultInvalidImage.txt | 9 + .../schema/Attr.DefaultInvalidImageAlt.txt | 8 + .../schema/Attr.DefaultTextDir.txt | 10 + .../ConfigSchema/schema/Attr.EnableID.txt | 16 + .../schema/Attr.ForbiddenClasses.txt | 8 + .../ConfigSchema/schema/Attr.IDBlacklist.txt | 5 + .../schema/Attr.IDBlacklistRegexp.txt | 9 + .../ConfigSchema/schema/Attr.IDPrefix.txt | 12 + .../schema/Attr.IDPrefixLocal.txt | 14 + .../schema/AutoFormat.AutoParagraph.txt | 31 + .../ConfigSchema/schema/AutoFormat.Custom.txt | 12 + .../schema/AutoFormat.DisplayLinkURI.txt | 11 + .../schema/AutoFormat.Linkify.txt | 12 + .../AutoFormat.PurifierLinkify.DocURL.txt | 12 + .../schema/AutoFormat.PurifierLinkify.txt | 12 + ...rmat.RemoveEmpty.RemoveNbsp.Exceptions.txt | 11 + .../AutoFormat.RemoveEmpty.RemoveNbsp.txt | 15 + .../schema/AutoFormat.RemoveEmpty.txt | 46 + .../schema/CSS.AllowImportant.txt | 8 + .../ConfigSchema/schema/CSS.AllowTricky.txt | 11 + .../schema/CSS.AllowedProperties.txt | 18 + .../ConfigSchema/schema/CSS.DefinitionRev.txt | 11 + .../ConfigSchema/schema/CSS.MaxImgLength.txt | 16 + .../ConfigSchema/schema/CSS.Proprietary.txt | 10 + .../schema/Cache.DefinitionImpl.txt | 14 + .../schema/Cache.SerializerPath.txt | 13 + .../schema/Core.AggressivelyFixLt.txt | 18 + .../schema/Core.CollectErrors.txt | 12 + .../schema/Core.ColorKeywords.txt | 28 + .../schema/Core.ConvertDocumentToFragment.txt | 14 + .../Core.DirectLexLineNumberSyncInterval.txt | 17 + .../ConfigSchema/schema/Core.Encoding.txt | 15 + .../schema/Core.EscapeInvalidChildren.txt | 10 + .../schema/Core.EscapeInvalidTags.txt | 7 + .../schema/Core.EscapeNonASCIICharacters.txt | 13 + .../schema/Core.HiddenElements.txt | 19 + .../ConfigSchema/schema/Core.Language.txt | 10 + .../ConfigSchema/schema/Core.LexerImpl.txt | 34 + .../schema/Core.MaintainLineNumbers.txt | 16 + .../schema/Core.RemoveInvalidImg.txt | 12 + .../schema/Core.RemoveScriptContents.txt | 12 + .../ConfigSchema/schema/Filter.Custom.txt | 11 + .../Filter.ExtractStyleBlocks.Escaping.txt | 14 + .../Filter.ExtractStyleBlocks.Scope.txt | 29 + .../Filter.ExtractStyleBlocks.TidyImpl.txt | 16 + .../schema/Filter.ExtractStyleBlocks.txt | 74 + .../ConfigSchema/schema/Filter.YouTube.txt | 11 + .../ConfigSchema/schema/HTML.Allowed.txt | 22 + .../schema/HTML.AllowedAttributes.txt | 19 + .../schema/HTML.AllowedElements.txt | 18 + .../schema/HTML.AllowedModules.txt | 20 + .../schema/HTML.Attr.Name.UseCDATA.txt | 11 + .../ConfigSchema/schema/HTML.BlockWrapper.txt | 18 + .../ConfigSchema/schema/HTML.CoreModules.txt | 23 + .../schema/HTML.CustomDoctype.txt | 9 + .../ConfigSchema/schema/HTML.DefinitionID.txt | 33 + .../schema/HTML.DefinitionRev.txt | 16 + .../ConfigSchema/schema/HTML.Doctype.txt | 11 + .../schema/HTML.ForbiddenAttributes.txt | 21 + .../schema/HTML.ForbiddenElements.txt | 20 + .../ConfigSchema/schema/HTML.MaxImgLength.txt | 14 + .../ConfigSchema/schema/HTML.Parent.txt | 12 + .../ConfigSchema/schema/HTML.Proprietary.txt | 12 + .../ConfigSchema/schema/HTML.SafeEmbed.txt | 14 + .../ConfigSchema/schema/HTML.SafeObject.txt | 14 + .../ConfigSchema/schema/HTML.Strict.txt | 9 + .../ConfigSchema/schema/HTML.TidyAdd.txt | 8 + .../ConfigSchema/schema/HTML.TidyLevel.txt | 24 + .../ConfigSchema/schema/HTML.TidyRemove.txt | 8 + .../ConfigSchema/schema/HTML.Trusted.txt | 8 + .../ConfigSchema/schema/HTML.XHTML.txt | 11 + .../schema/Output.CommentScriptContents.txt | 10 + .../ConfigSchema/schema/Output.Newline.txt | 13 + .../ConfigSchema/schema/Output.SortAttr.txt | 14 + .../ConfigSchema/schema/Output.TidyFormat.txt | 25 + .../ConfigSchema/schema/Test.ForceNoIconv.txt | 7 + .../schema/URI.AllowedSchemes.txt | 15 + .../ConfigSchema/schema/URI.Base.txt | 17 + .../ConfigSchema/schema/URI.DefaultScheme.txt | 10 + .../ConfigSchema/schema/URI.DefinitionID.txt | 11 + .../ConfigSchema/schema/URI.DefinitionRev.txt | 11 + .../ConfigSchema/schema/URI.Disable.txt | 14 + .../schema/URI.DisableExternal.txt | 11 + .../schema/URI.DisableExternalResources.txt | 13 + .../schema/URI.DisableResources.txt | 12 + .../ConfigSchema/schema/URI.Host.txt | 19 + .../ConfigSchema/schema/URI.HostBlacklist.txt | 9 + .../ConfigSchema/schema/URI.MakeAbsolute.txt | 13 + .../ConfigSchema/schema/URI.Munge.txt | 83 + .../schema/URI.MungeResources.txt | 17 + .../schema/URI.MungeSecretKey.txt | 30 + .../schema/URI.OverrideAllowedSchemes.txt | 9 + .../HTMLPurifier/ConfigSchema/schema/info.ini | 3 + .../HTMLPurifier/HTMLPurifier/ContentSets.php | 155 + extlib/HTMLPurifier/HTMLPurifier/Context.php | 82 + .../HTMLPurifier/HTMLPurifier/Definition.php | 39 + .../HTMLPurifier/DefinitionCache.php | 108 + .../DefinitionCache/Decorator.php | 62 + .../DefinitionCache/Decorator/Cleanup.php | 43 + .../DefinitionCache/Decorator/Memory.php | 46 + .../DefinitionCache/Decorator/Template.php.in | 47 + .../HTMLPurifier/DefinitionCache/Null.php | 39 + .../DefinitionCache/Serializer.php | 172 + .../DefinitionCache/Serializer/README | 3 + .../HTMLPurifier/DefinitionCacheFactory.php | 91 + extlib/HTMLPurifier/HTMLPurifier/Doctype.php | 60 + .../HTMLPurifier/DoctypeRegistry.php | 103 + .../HTMLPurifier/HTMLPurifier/ElementDef.php | 176 + extlib/HTMLPurifier/HTMLPurifier/Encoder.php | 426 ++ .../HTMLPurifier/EntityLookup.php | 44 + .../HTMLPurifier/EntityLookup/entities.ser | 1 + .../HTMLPurifier/EntityParser.php | 144 + .../HTMLPurifier/ErrorCollector.php | 209 + .../HTMLPurifier/HTMLPurifier/ErrorStruct.php | 60 + .../HTMLPurifier/HTMLPurifier/Exception.php | 12 + extlib/HTMLPurifier/HTMLPurifier/Filter.php | 46 + .../Filter/ExtractStyleBlocks.php | 135 + .../HTMLPurifier/Filter/YouTube.php | 39 + .../HTMLPurifier/HTMLPurifier/Generator.php | 183 + .../HTMLPurifier/HTMLDefinition.php | 420 ++ .../HTMLPurifier/HTMLPurifier/HTMLModule.php | 244 + .../HTMLPurifier/HTMLModule/Bdo.php | 31 + .../HTMLModule/CommonAttributes.php | 26 + .../HTMLPurifier/HTMLModule/Edit.php | 38 + .../HTMLPurifier/HTMLModule/Forms.php | 118 + .../HTMLPurifier/HTMLModule/Hypertext.php | 31 + .../HTMLPurifier/HTMLModule/Image.php | 40 + .../HTMLPurifier/HTMLModule/Legacy.php | 143 + .../HTMLPurifier/HTMLModule/List.php | 35 + .../HTMLPurifier/HTMLModule/Name.php | 21 + .../HTMLModule/NonXMLCommonAttributes.php | 14 + .../HTMLPurifier/HTMLModule/Object.php | 47 + .../HTMLPurifier/HTMLModule/Presentation.php | 36 + .../HTMLPurifier/HTMLModule/Proprietary.php | 33 + .../HTMLPurifier/HTMLModule/Ruby.php | 27 + .../HTMLPurifier/HTMLModule/SafeEmbed.php | 33 + .../HTMLPurifier/HTMLModule/SafeObject.php | 50 + .../HTMLPurifier/HTMLModule/Scripting.php | 54 + .../HTMLModule/StyleAttribute.php | 24 + .../HTMLPurifier/HTMLModule/Tables.php | 66 + .../HTMLPurifier/HTMLModule/Target.php | 23 + .../HTMLPurifier/HTMLModule/Text.php | 71 + .../HTMLPurifier/HTMLModule/Tidy.php | 207 + .../HTMLPurifier/HTMLModule/Tidy/Name.php | 24 + .../HTMLModule/Tidy/Proprietary.php | 23 + .../HTMLPurifier/HTMLModule/Tidy/Strict.php | 21 + .../HTMLModule/Tidy/Transitional.php | 9 + .../HTMLPurifier/HTMLModule/Tidy/XHTML.php | 17 + .../HTMLModule/Tidy/XHTMLAndHTML4.php | 161 + .../HTMLModule/XMLCommonAttributes.php | 14 + .../HTMLPurifier/HTMLModuleManager.php | 403 ++ .../HTMLPurifier/IDAccumulator.php | 53 + extlib/HTMLPurifier/HTMLPurifier/Injector.php | 239 + .../HTMLPurifier/Injector/AutoParagraph.php | 340 ++ .../HTMLPurifier/Injector/DisplayLinkURI.php | 26 + .../HTMLPurifier/Injector/Linkify.php | 46 + .../HTMLPurifier/Injector/PurifierLinkify.php | 45 + .../HTMLPurifier/Injector/RemoveEmpty.php | 51 + .../HTMLPurifier/Injector/SafeObject.php | 87 + extlib/HTMLPurifier/HTMLPurifier/Language.php | 163 + .../Language/classes/en-x-test.php | 12 + .../Language/messages/en-x-test.php | 11 + .../Language/messages/en-x-testmini.php | 12 + .../HTMLPurifier/Language/messages/en.php | 62 + .../HTMLPurifier/LanguageFactory.php | 198 + extlib/HTMLPurifier/HTMLPurifier/Length.php | 115 + extlib/HTMLPurifier/HTMLPurifier/Lexer.php | 298 ++ .../HTMLPurifier/Lexer/DOMLex.php | 213 + .../HTMLPurifier/Lexer/DirectLex.php | 490 +++ .../HTMLPurifier/Lexer/PEARSax3.php | 106 + .../HTMLPurifier/HTMLPurifier/Lexer/PH5P.php | 3906 +++++++++++++++++ .../HTMLPurifier/PercentEncoder.php | 98 + extlib/HTMLPurifier/HTMLPurifier/Printer.php | 176 + .../HTMLPurifier/Printer/CSSDefinition.php | 38 + .../HTMLPurifier/Printer/ConfigForm.css | 10 + .../HTMLPurifier/Printer/ConfigForm.js | 5 + .../HTMLPurifier/Printer/ConfigForm.php | 368 ++ .../HTMLPurifier/Printer/HTMLDefinition.php | 272 ++ .../HTMLPurifier/PropertyList.php | 86 + .../HTMLPurifier/PropertyListIterator.php | 32 + extlib/HTMLPurifier/HTMLPurifier/Strategy.php | 26 + .../HTMLPurifier/Strategy/Composite.php | 25 + .../HTMLPurifier/Strategy/Core.php | 18 + .../HTMLPurifier/Strategy/FixNesting.php | 328 ++ .../HTMLPurifier/Strategy/MakeWellFormed.php | 457 ++ .../Strategy/RemoveForeignElements.php | 171 + .../Strategy/ValidateAttributes.php | 39 + .../HTMLPurifier/HTMLPurifier/StringHash.php | 39 + .../HTMLPurifier/StringHashParser.php | 110 + .../HTMLPurifier/TagTransform.php | 36 + .../HTMLPurifier/TagTransform/Font.php | 96 + .../HTMLPurifier/TagTransform/Simple.php | 35 + extlib/HTMLPurifier/HTMLPurifier/Token.php | 57 + .../HTMLPurifier/Token/Comment.php | 22 + .../HTMLPurifier/HTMLPurifier/Token/Empty.php | 11 + .../HTMLPurifier/HTMLPurifier/Token/End.php | 19 + .../HTMLPurifier/HTMLPurifier/Token/Start.php | 11 + .../HTMLPurifier/HTMLPurifier/Token/Tag.php | 56 + .../HTMLPurifier/HTMLPurifier/Token/Text.php | 33 + .../HTMLPurifier/TokenFactory.php | 94 + extlib/HTMLPurifier/HTMLPurifier/URI.php | 173 + .../HTMLPurifier/URIDefinition.php | 93 + .../HTMLPurifier/HTMLPurifier/URIFilter.php | 45 + .../URIFilter/DisableExternal.php | 23 + .../URIFilter/DisableExternalResources.php | 12 + .../HTMLPurifier/URIFilter/HostBlacklist.php | 21 + .../HTMLPurifier/URIFilter/MakeAbsolute.php | 114 + .../HTMLPurifier/URIFilter/Munge.php | 58 + .../HTMLPurifier/HTMLPurifier/URIParser.php | 70 + .../HTMLPurifier/HTMLPurifier/URIScheme.php | 42 + .../HTMLPurifier/URIScheme/ftp.php | 43 + .../HTMLPurifier/URIScheme/http.php | 20 + .../HTMLPurifier/URIScheme/https.php | 12 + .../HTMLPurifier/URIScheme/mailto.php | 27 + .../HTMLPurifier/URIScheme/news.php | 22 + .../HTMLPurifier/URIScheme/nntp.php | 20 + .../HTMLPurifier/URISchemeRegistry.php | 68 + .../HTMLPurifier/UnitConverter.php | 254 ++ .../HTMLPurifier/HTMLPurifier/VarParser.php | 154 + .../HTMLPurifier/VarParser/Flexible.php | 96 + .../HTMLPurifier/VarParser/Native.php | 26 + .../HTMLPurifier/VarParserException.php | 11 + extlib/HTMLPurifier/LICENSE | 504 +++ 322 files changed, 24205 insertions(+) create mode 100644 extlib/HTMLPurifier/HTMLPurifier.auto.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier.autoload.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier.func.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier.includes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier.kses.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier.path.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier.safe-includes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrCollections.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Background.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Border.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Color.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Composite.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Filter.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Font.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Length.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Multiple.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Number.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Percentage.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/URI.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/Enum.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Bool.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Class.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Color.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/FrameTarget.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/ID.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Length.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/LinkTypes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/MultiLength.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Nmtokens.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Pixels.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/Integer.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/Lang.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/Switch.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/Text.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Email.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Host.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv4.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv6.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Background.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BdoDir.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BgColor.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BoolToCSS.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Border.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/EnumToCSS.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgRequired.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgSpace.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Input.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Lang.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Length.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Name.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/NameSync.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/SafeEmbed.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/SafeObject.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/SafeParam.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ScriptRequired.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Textarea.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrTypes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/AttrValidator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Bootstrap.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/CSSDefinition.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef/Chameleon.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef/Custom.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef/Empty.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef/Optional.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef/Required.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef/StrictBlockquote.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ChildDef/Table.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Config.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/Xml.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Exception.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Directive.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Id.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/InterchangeBuilder.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Validator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/ValidatorAtom.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema.ser create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Language.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Base.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Host.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/info.ini create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ContentSets.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Context.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Definition.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Memory.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Null.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Serializer.php create mode 100755 extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Serializer/README create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DefinitionCacheFactory.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Doctype.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/DoctypeRegistry.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ElementDef.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Encoder.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/EntityLookup.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/EntityLookup/entities.ser create mode 100644 extlib/HTMLPurifier/HTMLPurifier/EntityParser.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ErrorCollector.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/ErrorStruct.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Exception.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Filter.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Filter/YouTube.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Generator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLDefinition.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/CommonAttributes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Edit.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Forms.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Hypertext.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Image.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Legacy.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/List.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Object.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Presentation.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Proprietary.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Ruby.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeEmbed.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeObject.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/StyleAttribute.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tables.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Target.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Text.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Name.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Proprietary.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Strict.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Transitional.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/XHTML.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModule/XMLCommonAttributes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/IDAccumulator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Injector.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Injector/AutoParagraph.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Injector/DisplayLinkURI.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Injector/Linkify.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Injector/PurifierLinkify.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Injector/RemoveEmpty.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Injector/SafeObject.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Language.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Language/classes/en-x-test.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Language/messages/en-x-test.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Language/messages/en-x-testmini.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Language/messages/en.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/LanguageFactory.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Length.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Lexer.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Lexer/DOMLex.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Lexer/DirectLex.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/PercentEncoder.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Printer.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/PropertyList.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Strategy.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Strategy/Composite.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Strategy/Core.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/StringHash.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/StringHashParser.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/TagTransform.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/TagTransform/Font.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Token.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Token/Comment.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Token/Empty.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Token/End.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Token/Start.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Token/Tag.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/Token/Text.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/TokenFactory.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URI.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIDefinition.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIFilter.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternal.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIParser.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIScheme.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIScheme/http.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIScheme/https.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIScheme/mailto.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIScheme/news.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/UnitConverter.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/VarParser.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/VarParser/Native.php create mode 100644 extlib/HTMLPurifier/HTMLPurifier/VarParserException.php create mode 100644 extlib/HTMLPurifier/LICENSE diff --git a/extlib/HTMLPurifier/HTMLPurifier.auto.php b/extlib/HTMLPurifier/HTMLPurifier.auto.php new file mode 100644 index 0000000000..1960c399f8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier.auto.php @@ -0,0 +1,11 @@ +purify($html, $config); +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier.includes.php b/extlib/HTMLPurifier/HTMLPurifier.includes.php new file mode 100644 index 0000000000..7cfb970601 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier.includes.php @@ -0,0 +1,208 @@ + $attributes) { + $allowed_elements[$element] = true; + foreach ($attributes as $attribute => $x) { + $allowed_attributes["$element.$attribute"] = true; + } + } + $config->set('HTML.AllowedElements', $allowed_elements); + $config->set('HTML.AllowedAttributes', $allowed_attributes); + $allowed_schemes = array(); + if ($allowed_protocols !== null) { + $config->set('URI.AllowedSchemes', $allowed_protocols); + } + $purifier = new HTMLPurifier($config); + return $purifier->purify($string); +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier.path.php b/extlib/HTMLPurifier/HTMLPurifier.path.php new file mode 100644 index 0000000000..39b1b65319 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier.path.php @@ -0,0 +1,11 @@ +config = HTMLPurifier_Config::create($config); + + $this->strategy = new HTMLPurifier_Strategy_Core(); + + } + + /** + * Adds a filter to process the output. First come first serve + * @param $filter HTMLPurifier_Filter object + */ + public function addFilter($filter) { + trigger_error('HTMLPurifier->addFilter() is deprecated, use configuration directives in the Filter namespace or Filter.Custom', E_USER_WARNING); + $this->filters[] = $filter; + } + + /** + * Filters an HTML snippet/document to be XSS-free and standards-compliant. + * + * @param $html String of HTML to purify + * @param $config HTMLPurifier_Config object for this operation, if omitted, + * defaults to the config object specified during this + * object's construction. The parameter can also be any type + * that HTMLPurifier_Config::create() supports. + * @return Purified HTML + */ + public function purify($html, $config = null) { + + // :TODO: make the config merge in, instead of replace + $config = $config ? HTMLPurifier_Config::create($config) : $this->config; + + // implementation is partially environment dependant, partially + // configuration dependant + $lexer = HTMLPurifier_Lexer::create($config); + + $context = new HTMLPurifier_Context(); + + // setup HTML generator + $this->generator = new HTMLPurifier_Generator($config, $context); + $context->register('Generator', $this->generator); + + // set up global context variables + if ($config->get('Core.CollectErrors')) { + // may get moved out if other facilities use it + $language_factory = HTMLPurifier_LanguageFactory::instance(); + $language = $language_factory->create($config, $context); + $context->register('Locale', $language); + + $error_collector = new HTMLPurifier_ErrorCollector($context); + $context->register('ErrorCollector', $error_collector); + } + + // setup id_accumulator context, necessary due to the fact that + // AttrValidator can be called from many places + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + + $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context); + + // setup filters + $filter_flags = $config->getBatch('Filter'); + $custom_filters = $filter_flags['Custom']; + unset($filter_flags['Custom']); + $filters = array(); + foreach ($filter_flags as $filter => $flag) { + if (!$flag) continue; + if (strpos($filter, '.') !== false) continue; + $class = "HTMLPurifier_Filter_$filter"; + $filters[] = new $class; + } + foreach ($custom_filters as $filter) { + // maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat + $filters[] = $filter; + } + $filters = array_merge($filters, $this->filters); + // maybe prepare(), but later + + for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) { + $html = $filters[$i]->preFilter($html, $config, $context); + } + + // purified HTML + $html = + $this->generator->generateFromTokens( + // list of tokens + $this->strategy->execute( + // list of un-purified tokens + $lexer->tokenizeHTML( + // un-purified HTML + $html, $config, $context + ), + $config, $context + ) + ); + + for ($i = $filter_size - 1; $i >= 0; $i--) { + $html = $filters[$i]->postFilter($html, $config, $context); + } + + $html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context); + $this->context =& $context; + return $html; + } + + /** + * Filters an array of HTML snippets + * @param $config Optional HTMLPurifier_Config object for this operation. + * See HTMLPurifier::purify() for more details. + * @return Array of purified HTML + */ + public function purifyArray($array_of_html, $config = null) { + $context_array = array(); + foreach ($array_of_html as $key => $html) { + $array_of_html[$key] = $this->purify($html, $config); + $context_array[$key] = $this->context; + } + $this->context = $context_array; + return $array_of_html; + } + + /** + * Singleton for enforcing just one HTML Purifier in your system + * @param $prototype Optional prototype HTMLPurifier instance to + * overload singleton with, or HTMLPurifier_Config + * instance to configure the generated version with. + */ + public static function instance($prototype = null) { + if (!self::$instance || $prototype) { + if ($prototype instanceof HTMLPurifier) { + self::$instance = $prototype; + } elseif ($prototype) { + self::$instance = new HTMLPurifier($prototype); + } else { + self::$instance = new HTMLPurifier(); + } + } + return self::$instance; + } + + /** + * @note Backwards compatibility, see instance() + */ + public static function getInstance($prototype = null) { + return HTMLPurifier::instance($prototype); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier.safe-includes.php b/extlib/HTMLPurifier/HTMLPurifier.safe-includes.php new file mode 100644 index 0000000000..cf2c1d617a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier.safe-includes.php @@ -0,0 +1,202 @@ +attr_collections as $coll_i => $coll) { + if (!isset($this->info[$coll_i])) { + $this->info[$coll_i] = array(); + } + foreach ($coll as $attr_i => $attr) { + if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) { + // merge in includes + $this->info[$coll_i][$attr_i] = array_merge( + $this->info[$coll_i][$attr_i], $attr); + continue; + } + $this->info[$coll_i][$attr_i] = $attr; + } + } + } + // perform internal expansions and inclusions + foreach ($this->info as $name => $attr) { + // merge attribute collections that include others + $this->performInclusions($this->info[$name]); + // replace string identifiers with actual attribute objects + $this->expandIdentifiers($this->info[$name], $attr_types); + } + } + + /** + * Takes a reference to an attribute associative array and performs + * all inclusions specified by the zero index. + * @param &$attr Reference to attribute array + */ + public function performInclusions(&$attr) { + if (!isset($attr[0])) return; + $merge = $attr[0]; + $seen = array(); // recursion guard + // loop through all the inclusions + for ($i = 0; isset($merge[$i]); $i++) { + if (isset($seen[$merge[$i]])) continue; + $seen[$merge[$i]] = true; + // foreach attribute of the inclusion, copy it over + if (!isset($this->info[$merge[$i]])) continue; + foreach ($this->info[$merge[$i]] as $key => $value) { + if (isset($attr[$key])) continue; // also catches more inclusions + $attr[$key] = $value; + } + if (isset($this->info[$merge[$i]][0])) { + // recursion + $merge = array_merge($merge, $this->info[$merge[$i]][0]); + } + } + unset($attr[0]); + } + + /** + * Expands all string identifiers in an attribute array by replacing + * them with the appropriate values inside HTMLPurifier_AttrTypes + * @param &$attr Reference to attribute array + * @param $attr_types HTMLPurifier_AttrTypes instance + */ + public function expandIdentifiers(&$attr, $attr_types) { + + // because foreach will process new elements we add, make sure we + // skip duplicates + $processed = array(); + + foreach ($attr as $def_i => $def) { + // skip inclusions + if ($def_i === 0) continue; + + if (isset($processed[$def_i])) continue; + + // determine whether or not attribute is required + if ($required = (strpos($def_i, '*') !== false)) { + // rename the definition + unset($attr[$def_i]); + $def_i = trim($def_i, '*'); + $attr[$def_i] = $def; + } + + $processed[$def_i] = true; + + // if we've already got a literal object, move on + if (is_object($def)) { + // preserve previous required + $attr[$def_i]->required = ($required || $attr[$def_i]->required); + continue; + } + + if ($def === false) { + unset($attr[$def_i]); + continue; + } + + if ($t = $attr_types->get($def)) { + $attr[$def_i] = $t; + $attr[$def_i]->required = $required; + } else { + unset($attr[$def_i]); + } + } + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef.php new file mode 100644 index 0000000000..d32fa62d6a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef.php @@ -0,0 +1,87 @@ + by removing + * leading and trailing whitespace, ignoring line feeds, and replacing + * carriage returns and tabs with spaces. While most useful for HTML + * attributes specified as CDATA, it can also be applied to most CSS + * values. + * + * @note This method is not entirely standards compliant, as trim() removes + * more types of whitespace than specified in the spec. In practice, + * this is rarely a problem, as those extra characters usually have + * already been removed by HTMLPurifier_Encoder. + * + * @warning This processing is inconsistent with XML's whitespace handling + * as specified by section 3.3.3 and referenced XHTML 1.0 section + * 4.7. However, note that we are NOT necessarily + * parsing XML, thus, this behavior may still be correct. We + * assume that newlines have been normalized. + */ + public function parseCDATA($string) { + $string = trim($string); + $string = str_replace(array("\n", "\t", "\r"), ' ', $string); + return $string; + } + + /** + * Factory method for creating this class from a string. + * @param $string String construction info + * @return Created AttrDef object corresponding to $string + */ + public function make($string) { + // default implementation, return a flyweight of this object. + // If $string has an effect on the returned object (i.e. you + // need to overload this method), it is best + // to clone or instantiate new copies. (Instantiation is safer.) + return $this; + } + + /** + * Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work + * properly. THIS IS A HACK! + */ + protected function mungeRgb($string) { + return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS.php new file mode 100644 index 0000000000..953e706755 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS.php @@ -0,0 +1,87 @@ +parseCDATA($css); + + $definition = $config->getCSSDefinition(); + + // we're going to break the spec and explode by semicolons. + // This is because semicolon rarely appears in escaped form + // Doing this is generally flaky but fast + // IT MIGHT APPEAR IN URIs, see HTMLPurifier_AttrDef_CSSURI + // for details + + $declarations = explode(';', $css); + $propvalues = array(); + + /** + * Name of the current CSS property being validated. + */ + $property = false; + $context->register('CurrentCSSProperty', $property); + + foreach ($declarations as $declaration) { + if (!$declaration) continue; + if (!strpos($declaration, ':')) continue; + list($property, $value) = explode(':', $declaration, 2); + $property = trim($property); + $value = trim($value); + $ok = false; + do { + if (isset($definition->info[$property])) { + $ok = true; + break; + } + if (ctype_lower($property)) break; + $property = strtolower($property); + if (isset($definition->info[$property])) { + $ok = true; + break; + } + } while(0); + if (!$ok) continue; + // inefficient call, since the validator will do this again + if (strtolower(trim($value)) !== 'inherit') { + // inherit works for everything (but only on the base property) + $result = $definition->info[$property]->validate( + $value, $config, $context ); + } else { + $result = 'inherit'; + } + if ($result === false) continue; + $propvalues[$property] = $result; + } + + $context->destroy('CurrentCSSProperty'); + + // procedure does not write the new CSS simultaneously, so it's + // slightly inefficient, but it's the only way of getting rid of + // duplicates. Perhaps config to optimize it, but not now. + + $new_declarations = ''; + foreach ($propvalues as $prop => $value) { + $new_declarations .= "$prop:$value;"; + } + + return $new_declarations ? $new_declarations : false; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php new file mode 100644 index 0000000000..292c040d4b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php @@ -0,0 +1,21 @@ + 1.0) $result = '1'; + return $result; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Background.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Background.php new file mode 100644 index 0000000000..3a3d20cd6a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Background.php @@ -0,0 +1,87 @@ +getCSSDefinition(); + $this->info['background-color'] = $def->info['background-color']; + $this->info['background-image'] = $def->info['background-image']; + $this->info['background-repeat'] = $def->info['background-repeat']; + $this->info['background-attachment'] = $def->info['background-attachment']; + $this->info['background-position'] = $def->info['background-position']; + } + + public function validate($string, $config, $context) { + + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') return false; + + // munge rgb() decl if necessary + $string = $this->mungeRgb($string); + + // assumes URI doesn't have spaces in it + $bits = explode(' ', strtolower($string)); // bits to process + + $caught = array(); + $caught['color'] = false; + $caught['image'] = false; + $caught['repeat'] = false; + $caught['attachment'] = false; + $caught['position'] = false; + + $i = 0; // number of catches + $none = false; + + foreach ($bits as $bit) { + if ($bit === '') continue; + foreach ($caught as $key => $status) { + if ($key != 'position') { + if ($status !== false) continue; + $r = $this->info['background-' . $key]->validate($bit, $config, $context); + } else { + $r = $bit; + } + if ($r === false) continue; + if ($key == 'position') { + if ($caught[$key] === false) $caught[$key] = ''; + $caught[$key] .= $r . ' '; + } else { + $caught[$key] = $r; + } + $i++; + break; + } + } + + if (!$i) return false; + if ($caught['position'] !== false) { + $caught['position'] = $this->info['background-position']-> + validate($caught['position'], $config, $context); + } + + $ret = array(); + foreach ($caught as $value) { + if ($value === false) continue; + $ret[] = $value; + } + + if (empty($ret)) return false; + return implode(' ', $ret); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php new file mode 100644 index 0000000000..35df3985e2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php @@ -0,0 +1,126 @@ + | | left | center | right + ] + [ + | | top | center | bottom + ]? + ] | + [ // this signifies that the vertical and horizontal adjectives + // can be arbitrarily ordered, however, there can only be two, + // one of each, or none at all + [ + left | center | right + ] || + [ + top | center | bottom + ] + ] + top, left = 0% + center, (none) = 50% + bottom, right = 100% +*/ + +/* QuirksMode says: + keyword + length/percentage must be ordered correctly, as per W3C + + Internet Explorer and Opera, however, support arbitrary ordering. We + should fix it up. + + Minor issue though, not strictly necessary. +*/ + +// control freaks may appreciate the ability to convert these to +// percentages or something, but it's not necessary + +/** + * Validates the value of background-position. + */ +class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef +{ + + protected $length; + protected $percentage; + + public function __construct() { + $this->length = new HTMLPurifier_AttrDef_CSS_Length(); + $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); + } + + public function validate($string, $config, $context) { + $string = $this->parseCDATA($string); + $bits = explode(' ', $string); + + $keywords = array(); + $keywords['h'] = false; // left, right + $keywords['v'] = false; // top, bottom + $keywords['c'] = false; // center + $measures = array(); + + $i = 0; + + $lookup = array( + 'top' => 'v', + 'bottom' => 'v', + 'left' => 'h', + 'right' => 'h', + 'center' => 'c' + ); + + foreach ($bits as $bit) { + if ($bit === '') continue; + + // test for keyword + $lbit = ctype_lower($bit) ? $bit : strtolower($bit); + if (isset($lookup[$lbit])) { + $status = $lookup[$lbit]; + $keywords[$status] = $lbit; + $i++; + } + + // test for length + $r = $this->length->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + + // test for percentage + $r = $this->percentage->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + + } + + if (!$i) return false; // no valid values were caught + + + $ret = array(); + + // first keyword + if ($keywords['h']) $ret[] = $keywords['h']; + elseif (count($measures)) $ret[] = array_shift($measures); + elseif ($keywords['c']) { + $ret[] = $keywords['c']; + $keywords['c'] = false; // prevent re-use: center = center center + } + + if ($keywords['v']) $ret[] = $keywords['v']; + elseif (count($measures)) $ret[] = array_shift($measures); + elseif ($keywords['c']) $ret[] = $keywords['c']; + + if (empty($ret)) return false; + return implode(' ', $ret); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Border.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Border.php new file mode 100644 index 0000000000..42a1d1b4ae --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Border.php @@ -0,0 +1,43 @@ +getCSSDefinition(); + $this->info['border-width'] = $def->info['border-width']; + $this->info['border-style'] = $def->info['border-style']; + $this->info['border-top-color'] = $def->info['border-top-color']; + } + + public function validate($string, $config, $context) { + $string = $this->parseCDATA($string); + $string = $this->mungeRgb($string); + $bits = explode(' ', $string); + $done = array(); // segments we've finished + $ret = ''; // return value + foreach ($bits as $bit) { + foreach ($this->info as $propname => $validator) { + if (isset($done[$propname])) continue; + $r = $validator->validate($bit, $config, $context); + if ($r !== false) { + $ret .= $r . ' '; + $done[$propname] = true; + break; + } + } + } + return rtrim($ret); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Color.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Color.php new file mode 100644 index 0000000000..07f95a6719 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Color.php @@ -0,0 +1,78 @@ +get('Core.ColorKeywords'); + + $color = trim($color); + if ($color === '') return false; + + $lower = strtolower($color); + if (isset($colors[$lower])) return $colors[$lower]; + + if (strpos($color, 'rgb(') !== false) { + // rgb literal handling + $length = strlen($color); + if (strpos($color, ')') !== $length - 1) return false; + $triad = substr($color, 4, $length - 4 - 1); + $parts = explode(',', $triad); + if (count($parts) !== 3) return false; + $type = false; // to ensure that they're all the same type + $new_parts = array(); + foreach ($parts as $part) { + $part = trim($part); + if ($part === '') return false; + $length = strlen($part); + if ($part[$length - 1] === '%') { + // handle percents + if (!$type) { + $type = 'percentage'; + } elseif ($type !== 'percentage') { + return false; + } + $num = (float) substr($part, 0, $length - 1); + if ($num < 0) $num = 0; + if ($num > 100) $num = 100; + $new_parts[] = "$num%"; + } else { + // handle integers + if (!$type) { + $type = 'integer'; + } elseif ($type !== 'integer') { + return false; + } + $num = (int) $part; + if ($num < 0) $num = 0; + if ($num > 255) $num = 255; + $new_parts[] = (string) $num; + } + } + $new_triad = implode(',', $new_parts); + $color = "rgb($new_triad)"; + } else { + // hexadecimal handling + if ($color[0] === '#') { + $hex = substr($color, 1); + } else { + $hex = $color; + $color = '#' . $color; + } + $length = strlen($hex); + if ($length !== 3 && $length !== 6) return false; + if (!ctype_xdigit($hex)) return false; + } + + return $color; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Composite.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Composite.php new file mode 100644 index 0000000000..de1289cba8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Composite.php @@ -0,0 +1,38 @@ +defs = $defs; + } + + public function validate($string, $config, $context) { + foreach ($this->defs as $i => $def) { + $result = $this->defs[$i]->validate($string, $config, $context); + if ($result !== false) return $result; + } + return false; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php new file mode 100644 index 0000000000..6599c5b2dd --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php @@ -0,0 +1,28 @@ +def = $def; + $this->element = $element; + } + /** + * Checks if CurrentToken is set and equal to $this->element + */ + public function validate($string, $config, $context) { + $token = $context->get('CurrentToken', true); + if ($token && $token->name == $this->element) return false; + return $this->def->validate($string, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Filter.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Filter.php new file mode 100644 index 0000000000..147894b861 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Filter.php @@ -0,0 +1,54 @@ +intValidator = new HTMLPurifier_AttrDef_Integer(); + } + + public function validate($value, $config, $context) { + $value = $this->parseCDATA($value); + if ($value === 'none') return $value; + // if we looped this we could support multiple filters + $function_length = strcspn($value, '('); + $function = trim(substr($value, 0, $function_length)); + if ($function !== 'alpha' && + $function !== 'Alpha' && + $function !== 'progid:DXImageTransform.Microsoft.Alpha' + ) return false; + $cursor = $function_length + 1; + $parameters_length = strcspn($value, ')', $cursor); + $parameters = substr($value, $cursor, $parameters_length); + $params = explode(',', $parameters); + $ret_params = array(); + $lookup = array(); + foreach ($params as $param) { + list($key, $value) = explode('=', $param); + $key = trim($key); + $value = trim($value); + if (isset($lookup[$key])) continue; + if ($key !== 'opacity') continue; + $value = $this->intValidator->validate($value, $config, $context); + if ($value === false) continue; + $int = (int) $value; + if ($int > 100) $value = '100'; + if ($int < 0) $value = '0'; + $ret_params[] = "$key=$value"; + $lookup[$key] = true; + } + $ret_parameters = implode(',', $ret_params); + $ret_function = "$function($ret_parameters)"; + return $ret_function; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Font.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Font.php new file mode 100644 index 0000000000..699ee0b701 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Font.php @@ -0,0 +1,149 @@ +getCSSDefinition(); + $this->info['font-style'] = $def->info['font-style']; + $this->info['font-variant'] = $def->info['font-variant']; + $this->info['font-weight'] = $def->info['font-weight']; + $this->info['font-size'] = $def->info['font-size']; + $this->info['line-height'] = $def->info['line-height']; + $this->info['font-family'] = $def->info['font-family']; + } + + public function validate($string, $config, $context) { + + static $system_fonts = array( + 'caption' => true, + 'icon' => true, + 'menu' => true, + 'message-box' => true, + 'small-caption' => true, + 'status-bar' => true + ); + + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') return false; + + // check if it's one of the keywords + $lowercase_string = strtolower($string); + if (isset($system_fonts[$lowercase_string])) { + return $lowercase_string; + } + + $bits = explode(' ', $string); // bits to process + $stage = 0; // this indicates what we're looking for + $caught = array(); // which stage 0 properties have we caught? + $stage_1 = array('font-style', 'font-variant', 'font-weight'); + $final = ''; // output + + for ($i = 0, $size = count($bits); $i < $size; $i++) { + if ($bits[$i] === '') continue; + switch ($stage) { + + // attempting to catch font-style, font-variant or font-weight + case 0: + foreach ($stage_1 as $validator_name) { + if (isset($caught[$validator_name])) continue; + $r = $this->info[$validator_name]->validate( + $bits[$i], $config, $context); + if ($r !== false) { + $final .= $r . ' '; + $caught[$validator_name] = true; + break; + } + } + // all three caught, continue on + if (count($caught) >= 3) $stage = 1; + if ($r !== false) break; + + // attempting to catch font-size and perhaps line-height + case 1: + $found_slash = false; + if (strpos($bits[$i], '/') !== false) { + list($font_size, $line_height) = + explode('/', $bits[$i]); + if ($line_height === '') { + // ooh, there's a space after the slash! + $line_height = false; + $found_slash = true; + } + } else { + $font_size = $bits[$i]; + $line_height = false; + } + $r = $this->info['font-size']->validate( + $font_size, $config, $context); + if ($r !== false) { + $final .= $r; + // attempt to catch line-height + if ($line_height === false) { + // we need to scroll forward + for ($j = $i + 1; $j < $size; $j++) { + if ($bits[$j] === '') continue; + if ($bits[$j] === '/') { + if ($found_slash) { + return false; + } else { + $found_slash = true; + continue; + } + } + $line_height = $bits[$j]; + break; + } + } else { + // slash already found + $found_slash = true; + $j = $i; + } + if ($found_slash) { + $i = $j; + $r = $this->info['line-height']->validate( + $line_height, $config, $context); + if ($r !== false) { + $final .= '/' . $r; + } + } + $final .= ' '; + $stage = 2; + break; + } + return false; + + // attempting to catch font-family + case 2: + $font_family = + implode(' ', array_slice($bits, $i, $size - $i)); + $r = $this->info['font-family']->validate( + $font_family, $config, $context); + if ($r !== false) { + $final .= $r . ' '; + // processing completed successfully + return rtrim($final); + } + return false; + } + } + return false; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php new file mode 100644 index 0000000000..705ac893d1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php @@ -0,0 +1,90 @@ + true, + 'sans-serif' => true, + 'monospace' => true, + 'fantasy' => true, + 'cursive' => true + ); + + // assume that no font names contain commas in them + $fonts = explode(',', $string); + $final = ''; + foreach($fonts as $font) { + $font = trim($font); + if ($font === '') continue; + // match a generic name + if (isset($generic_names[$font])) { + $final .= $font . ', '; + continue; + } + // match a quoted name + if ($font[0] === '"' || $font[0] === "'") { + $length = strlen($font); + if ($length <= 2) continue; + $quote = $font[0]; + if ($font[$length - 1] !== $quote) continue; + $font = substr($font, 1, $length - 2); + + $new_font = ''; + for ($i = 0, $c = strlen($font); $i < $c; $i++) { + if ($font[$i] === '\\') { + $i++; + if ($i >= $c) { + $new_font .= '\\'; + break; + } + if (ctype_xdigit($font[$i])) { + $code = $font[$i]; + for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) { + if (!ctype_xdigit($font[$i])) break; + $code .= $font[$i]; + } + // We have to be extremely careful when adding + // new characters, to make sure we're not breaking + // the encoding. + $char = HTMLPurifier_Encoder::unichr(hexdec($code)); + if (HTMLPurifier_Encoder::cleanUTF8($char) === '') continue; + $new_font .= $char; + if ($i < $c && trim($font[$i]) !== '') $i--; + continue; + } + if ($font[$i] === "\n") continue; + } + $new_font .= $font[$i]; + } + + $font = $new_font; + } + // $font is a pure representation of the font name + + if (ctype_alnum($font) && $font !== '') { + // very simple font, allow it in unharmed + $final .= $font . ', '; + continue; + } + + // complicated font, requires quoting + + // armor single quotes and new lines + $font = str_replace("\\", "\\\\", $font); + $font = str_replace("'", "\\'", $font); + $final .= "'$font', "; + } + $final = rtrim($final, ', '); + if ($final === '') return false; + return $final; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php new file mode 100644 index 0000000000..4e6b35e5a0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php @@ -0,0 +1,40 @@ +def = $def; + $this->allow = $allow; + } + /** + * Intercepts and removes !important if necessary + */ + public function validate($string, $config, $context) { + // test for ! and important tokens + $string = trim($string); + $is_important = false; + // :TODO: optimization: test directly for !important and ! important + if (strlen($string) >= 9 && substr($string, -9) === 'important') { + $temp = rtrim(substr($string, 0, -9)); + // use a temp, because we might want to restore important + if (strlen($temp) >= 1 && substr($temp, -1) === '!') { + $string = rtrim(substr($temp, 0, -1)); + $is_important = true; + } + } + $string = $this->def->validate($string, $config, $context); + if ($this->allow && $is_important) $string .= ' !important'; + return $string; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Length.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Length.php new file mode 100644 index 0000000000..a07ec58135 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Length.php @@ -0,0 +1,47 @@ +min = $min !== null ? HTMLPurifier_Length::make($min) : null; + $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; + } + + public function validate($string, $config, $context) { + $string = $this->parseCDATA($string); + + // Optimizations + if ($string === '') return false; + if ($string === '0') return '0'; + if (strlen($string) === 1) return false; + + $length = HTMLPurifier_Length::make($string); + if (!$length->isValid()) return false; + + if ($this->min) { + $c = $length->compareTo($this->min); + if ($c === false) return false; + if ($c < 0) return false; + } + if ($this->max) { + $c = $length->compareTo($this->max); + if ($c === false) return false; + if ($c > 0) return false; + } + + return $length->toString(); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php new file mode 100644 index 0000000000..4406868c08 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php @@ -0,0 +1,78 @@ +getCSSDefinition(); + $this->info['list-style-type'] = $def->info['list-style-type']; + $this->info['list-style-position'] = $def->info['list-style-position']; + $this->info['list-style-image'] = $def->info['list-style-image']; + } + + public function validate($string, $config, $context) { + + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') return false; + + // assumes URI doesn't have spaces in it + $bits = explode(' ', strtolower($string)); // bits to process + + $caught = array(); + $caught['type'] = false; + $caught['position'] = false; + $caught['image'] = false; + + $i = 0; // number of catches + $none = false; + + foreach ($bits as $bit) { + if ($i >= 3) return; // optimization bit + if ($bit === '') continue; + foreach ($caught as $key => $status) { + if ($status !== false) continue; + $r = $this->info['list-style-' . $key]->validate($bit, $config, $context); + if ($r === false) continue; + if ($r === 'none') { + if ($none) continue; + else $none = true; + if ($key == 'image') continue; + } + $caught[$key] = $r; + $i++; + break; + } + } + + if (!$i) return false; + + $ret = array(); + + // construct type + if ($caught['type']) $ret[] = $caught['type']; + + // construct image + if ($caught['image']) $ret[] = $caught['image']; + + // construct position + if ($caught['position']) $ret[] = $caught['position']; + + if (empty($ret)) return false; + return implode(' ', $ret); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Multiple.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Multiple.php new file mode 100644 index 0000000000..4d62a40d7f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Multiple.php @@ -0,0 +1,58 @@ +single = $single; + $this->max = $max; + } + + public function validate($string, $config, $context) { + $string = $this->parseCDATA($string); + if ($string === '') return false; + $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n + $length = count($parts); + $final = ''; + for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { + if (ctype_space($parts[$i])) continue; + $result = $this->single->validate($parts[$i], $config, $context); + if ($result !== false) { + $final .= $result . ' '; + $num++; + } + } + if ($final === '') return false; + return rtrim($final); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Number.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Number.php new file mode 100644 index 0000000000..3f99e12ec2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Number.php @@ -0,0 +1,69 @@ +non_negative = $non_negative; + } + + /** + * @warning Some contexts do not pass $config, $context. These + * variables should not be used without checking HTMLPurifier_Length + */ + public function validate($number, $config, $context) { + + $number = $this->parseCDATA($number); + + if ($number === '') return false; + if ($number === '0') return '0'; + + $sign = ''; + switch ($number[0]) { + case '-': + if ($this->non_negative) return false; + $sign = '-'; + case '+': + $number = substr($number, 1); + } + + if (ctype_digit($number)) { + $number = ltrim($number, '0'); + return $number ? $sign . $number : '0'; + } + + // Period is the only non-numeric character allowed + if (strpos($number, '.') === false) return false; + + list($left, $right) = explode('.', $number, 2); + + if ($left === '' && $right === '') return false; + if ($left !== '' && !ctype_digit($left)) return false; + + $left = ltrim($left, '0'); + $right = rtrim($right, '0'); + + if ($right === '') { + return $left ? $sign . $left : '0'; + } elseif (!ctype_digit($right)) { + return false; + } + + return $sign . $left . '.' . $right; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Percentage.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Percentage.php new file mode 100644 index 0000000000..c34b8fc3c3 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Percentage.php @@ -0,0 +1,40 @@ +number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); + } + + public function validate($string, $config, $context) { + + $string = $this->parseCDATA($string); + + if ($string === '') return false; + $length = strlen($string); + if ($length === 1) return false; + if ($string[$length - 1] !== '%') return false; + + $number = substr($string, 0, $length - 1); + $number = $this->number_def->validate($number, $config, $context); + + if ($number === false) return false; + return "$number%"; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php new file mode 100644 index 0000000000..772c922d80 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php @@ -0,0 +1,38 @@ + true, + 'overline' => true, + 'underline' => true, + ); + + $string = strtolower($this->parseCDATA($string)); + + if ($string === 'none') return $string; + + $parts = explode(' ', $string); + $final = ''; + foreach ($parts as $part) { + if (isset($allowed_values[$part])) { + $final .= $part . ' '; + } + } + $final = rtrim($final); + if ($final === '') return false; + return $final; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/URI.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/URI.php new file mode 100644 index 0000000000..435d7930bb --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/CSS/URI.php @@ -0,0 +1,56 @@ +parseCDATA($uri_string); + if (strpos($uri_string, 'url(') !== 0) return false; + $uri_string = substr($uri_string, 4); + $new_length = strlen($uri_string) - 1; + if ($uri_string[$new_length] != ')') return false; + $uri = trim(substr($uri_string, 0, $new_length)); + + if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { + $quote = $uri[0]; + $new_length = strlen($uri) - 1; + if ($uri[$new_length] !== $quote) return false; + $uri = substr($uri, 1, $new_length - 1); + } + + $keys = array( '(', ')', ',', ' ', '"', "'"); + $values = array('\\(', '\\)', '\\,', '\\ ', '\\"', "\\'"); + $uri = str_replace($values, $keys, $uri); + + $result = parent::validate($uri, $config, $context); + + if ($result === false) return false; + + // escape necessary characters according to CSS spec + // except for the comma, none of these should appear in the + // URI at all + $result = str_replace($keys, $values, $result); + + return "url($result)"; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Enum.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Enum.php new file mode 100644 index 0000000000..5d603ebcc6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Enum.php @@ -0,0 +1,65 @@ +valid_values = array_flip($valid_values); + $this->case_sensitive = $case_sensitive; + } + + public function validate($string, $config, $context) { + $string = trim($string); + if (!$this->case_sensitive) { + // we may want to do full case-insensitive libraries + $string = ctype_lower($string) ? $string : strtolower($string); + } + $result = isset($this->valid_values[$string]); + + return $result ? $string : false; + } + + /** + * @param $string In form of comma-delimited list of case-insensitive + * valid values. Example: "foo,bar,baz". Prepend "s:" to make + * case sensitive + */ + public function make($string) { + if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') { + $string = substr($string, 2); + $sensitive = true; + } else { + $sensitive = false; + } + $values = explode(',', $string); + return new HTMLPurifier_AttrDef_Enum($values, $sensitive); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Bool.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Bool.php new file mode 100644 index 0000000000..e06987eb8d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Bool.php @@ -0,0 +1,28 @@ +name = $name;} + + public function validate($string, $config, $context) { + if (empty($string)) return false; + return $this->name; + } + + /** + * @param $string Name of attribute + */ + public function make($string) { + return new HTMLPurifier_AttrDef_HTML_Bool($string); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Class.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Class.php new file mode 100644 index 0000000000..370068d975 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Class.php @@ -0,0 +1,34 @@ +getDefinition('HTML')->doctype->name; + if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { + return parent::split($string, $config, $context); + } else { + return preg_split('/\s+/', $string); + } + } + protected function filter($tokens, $config, $context) { + $allowed = $config->get('Attr.AllowedClasses'); + $forbidden = $config->get('Attr.ForbiddenClasses'); + $ret = array(); + foreach ($tokens as $token) { + if ( + ($allowed === null || isset($allowed[$token])) && + !isset($forbidden[$token]) && + // We need this O(n) check because of PHP's array + // implementation that casts -0 to 0. + !in_array($token, $ret, true) + ) { + $ret[] = $token; + } + } + return $ret; + } +} diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Color.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Color.php new file mode 100644 index 0000000000..d01e20454e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Color.php @@ -0,0 +1,32 @@ +get('Core.ColorKeywords'); + + $string = trim($string); + + if (empty($string)) return false; + if (isset($colors[$string])) return $colors[$string]; + if ($string[0] === '#') $hex = substr($string, 1); + else $hex = $string; + + $length = strlen($hex); + if ($length !== 3 && $length !== 6) return false; + if (!ctype_xdigit($hex)) return false; + if ($length === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; + + return "#$hex"; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/FrameTarget.php new file mode 100644 index 0000000000..ae6ea7c01d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/FrameTarget.php @@ -0,0 +1,21 @@ +valid_values === false) $this->valid_values = $config->get('Attr.AllowedFrameTargets'); + return parent::validate($string, $config, $context); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/ID.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/ID.php new file mode 100644 index 0000000000..81d03762de --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/ID.php @@ -0,0 +1,70 @@ +get('Attr.EnableID')) return false; + + $id = trim($id); // trim it first + + if ($id === '') return false; + + $prefix = $config->get('Attr.IDPrefix'); + if ($prefix !== '') { + $prefix .= $config->get('Attr.IDPrefixLocal'); + // prevent re-appending the prefix + if (strpos($id, $prefix) !== 0) $id = $prefix . $id; + } elseif ($config->get('Attr.IDPrefixLocal') !== '') { + trigger_error('%Attr.IDPrefixLocal cannot be used unless '. + '%Attr.IDPrefix is set', E_USER_WARNING); + } + + //if (!$this->ref) { + $id_accumulator =& $context->get('IDAccumulator'); + if (isset($id_accumulator->ids[$id])) return false; + //} + + // we purposely avoid using regex, hopefully this is faster + + if (ctype_alpha($id)) { + $result = true; + } else { + if (!ctype_alpha(@$id[0])) return false; + $trim = trim( // primitive style of regexps, I suppose + $id, + 'A..Za..z0..9:-._' + ); + $result = ($trim === ''); + } + + $regexp = $config->get('Attr.IDBlacklistRegexp'); + if ($regexp && preg_match($regexp, $id)) { + return false; + } + + if (/*!$this->ref && */$result) $id_accumulator->add($id); + + // if no change was made to the ID, return the result + // else, return the new id if stripping whitespace made it + // valid, or return false. + return $result ? $id : false; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Length.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Length.php new file mode 100644 index 0000000000..a242f9c238 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Length.php @@ -0,0 +1,41 @@ + 100) return '100%'; + + return ((string) $points) . '%'; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/LinkTypes.php new file mode 100644 index 0000000000..76d25ed088 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/LinkTypes.php @@ -0,0 +1,53 @@ + 'AllowedRel', + 'rev' => 'AllowedRev' + ); + if (!isset($configLookup[$name])) { + trigger_error('Unrecognized attribute name for link '. + 'relationship.', E_USER_ERROR); + return; + } + $this->name = $configLookup[$name]; + } + + public function validate($string, $config, $context) { + + $allowed = $config->get('Attr.' . $this->name); + if (empty($allowed)) return false; + + $string = $this->parseCDATA($string); + $parts = explode(' ', $string); + + // lookup to prevent duplicates + $ret_lookup = array(); + foreach ($parts as $part) { + $part = strtolower(trim($part)); + if (!isset($allowed[$part])) continue; + $ret_lookup[$part] = true; + } + + if (empty($ret_lookup)) return false; + $string = implode(' ', array_keys($ret_lookup)); + + return $string; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/MultiLength.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/MultiLength.php new file mode 100644 index 0000000000..c72fc76e4d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/MultiLength.php @@ -0,0 +1,41 @@ +split($string, $config, $context); + $tokens = $this->filter($tokens, $config, $context); + if (empty($tokens)) return false; + return implode(' ', $tokens); + + } + + /** + * Splits a space separated list of tokens into its constituent parts. + */ + protected function split($string, $config, $context) { + // OPTIMIZABLE! + // do the preg_match, capture all subpatterns for reformulation + + // we don't support U+00A1 and up codepoints or + // escaping because I don't know how to do that with regexps + // and plus it would complicate optimization efforts (you never + // see that anyway). + $pattern = '/(?:(?<=\s)|\A)'. // look behind for space or string start + '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)'. + '(?:(?=\s)|\z)/'; // look ahead for space or string end + preg_match_all($pattern, $string, $matches); + return $matches[1]; + } + + /** + * Template method for removing certain tokens based on arbitrary criteria. + * @note If we wanted to be really functional, we'd do an array_filter + * with a callback. But... we're not. + */ + protected function filter($tokens, $config, $context) { + return $tokens; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Pixels.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Pixels.php new file mode 100644 index 0000000000..4cb2c1b857 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Pixels.php @@ -0,0 +1,48 @@ +max = $max; + } + + public function validate($string, $config, $context) { + + $string = trim($string); + if ($string === '0') return $string; + if ($string === '') return false; + $length = strlen($string); + if (substr($string, $length - 2) == 'px') { + $string = substr($string, 0, $length - 2); + } + if (!is_numeric($string)) return false; + $int = (int) $string; + + if ($int < 0) return '0'; + + // upper-bound value, extremely high values can + // crash operating systems, see + // WARNING, above link WILL crash you if you're using Windows + + if ($this->max !== null && $int > $this->max) return (string) $this->max; + + return (string) $int; + + } + + public function make($string) { + if ($string === '') $max = null; + else $max = (int) $string; + $class = get_class($this); + return new $class($max); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Integer.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Integer.php new file mode 100644 index 0000000000..d59738d2a2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Integer.php @@ -0,0 +1,73 @@ +negative = $negative; + $this->zero = $zero; + $this->positive = $positive; + } + + public function validate($integer, $config, $context) { + + $integer = $this->parseCDATA($integer); + if ($integer === '') return false; + + // we could possibly simply typecast it to integer, but there are + // certain fringe cases that must not return an integer. + + // clip leading sign + if ( $this->negative && $integer[0] === '-' ) { + $digits = substr($integer, 1); + if ($digits === '0') $integer = '0'; // rm minus sign for zero + } elseif( $this->positive && $integer[0] === '+' ) { + $digits = $integer = substr($integer, 1); // rm unnecessary plus + } else { + $digits = $integer; + } + + // test if it's numeric + if (!ctype_digit($digits)) return false; + + // perform scope tests + if (!$this->zero && $integer == 0) return false; + if (!$this->positive && $integer > 0) return false; + if (!$this->negative && $integer < 0) return false; + + return $integer; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Lang.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Lang.php new file mode 100644 index 0000000000..10e6da56db --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Lang.php @@ -0,0 +1,73 @@ + 8 || !ctype_alnum($subtags[1])) { + return $new_string; + } + if (!ctype_lower($subtags[1])) $subtags[1] = strtolower($subtags[1]); + + $new_string .= '-' . $subtags[1]; + if ($num_subtags == 2) return $new_string; + + // process all other subtags, index 2 and up + for ($i = 2; $i < $num_subtags; $i++) { + $length = strlen($subtags[$i]); + if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) { + return $new_string; + } + if (!ctype_lower($subtags[$i])) { + $subtags[$i] = strtolower($subtags[$i]); + } + $new_string .= '-' . $subtags[$i]; + } + + return $new_string; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Switch.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Switch.php new file mode 100644 index 0000000000..c9e3ed193e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Switch.php @@ -0,0 +1,34 @@ +tag = $tag; + $this->withTag = $with_tag; + $this->withoutTag = $without_tag; + } + + public function validate($string, $config, $context) { + $token = $context->get('CurrentToken', true); + if (!$token || $token->name !== $this->tag) { + return $this->withoutTag->validate($string, $config, $context); + } else { + return $this->withTag->validate($string, $config, $context); + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Text.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Text.php new file mode 100644 index 0000000000..c6216cc531 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/Text.php @@ -0,0 +1,15 @@ +parseCDATA($string); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI.php new file mode 100644 index 0000000000..01a6d83e95 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI.php @@ -0,0 +1,77 @@ +parser = new HTMLPurifier_URIParser(); + $this->embedsResource = (bool) $embeds_resource; + } + + public function make($string) { + $embeds = (bool) $string; + return new HTMLPurifier_AttrDef_URI($embeds); + } + + public function validate($uri, $config, $context) { + + if ($config->get('URI.Disable')) return false; + + $uri = $this->parseCDATA($uri); + + // parse the URI + $uri = $this->parser->parse($uri); + if ($uri === false) return false; + + // add embedded flag to context for validators + $context->register('EmbeddedURI', $this->embedsResource); + + $ok = false; + do { + + // generic validation + $result = $uri->validate($config, $context); + if (!$result) break; + + // chained filtering + $uri_def = $config->getDefinition('URI'); + $result = $uri_def->filter($uri, $config, $context); + if (!$result) break; + + // scheme-specific validation + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) break; + if ($this->embedsResource && !$scheme_obj->browsable) break; + $result = $scheme_obj->validate($uri, $config, $context); + if (!$result) break; + + // Post chained filtering + $result = $uri_def->postFilter($uri, $config, $context); + if (!$result) break; + + // survived gauntlet + $ok = true; + + } while (false); + + $context->destroy('EmbeddedURI'); + if (!$ok) return false; + + // back to string + return $uri->toString(); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Email.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Email.php new file mode 100644 index 0000000000..bfee9d166c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Email.php @@ -0,0 +1,17 @@ +" + // that needs more percent encoding to be done + if ($string == '') return false; + $string = trim($string); + $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); + return $result ? $string : false; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Host.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Host.php new file mode 100644 index 0000000000..2156c10c66 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/Host.php @@ -0,0 +1,62 @@ +ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); + $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); + } + + public function validate($string, $config, $context) { + $length = strlen($string); + if ($string === '') return ''; + if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') { + //IPv6 + $ip = substr($string, 1, $length - 2); + $valid = $this->ipv6->validate($ip, $config, $context); + if ($valid === false) return false; + return '['. $valid . ']'; + } + + // need to do checks on unusual encodings too + $ipv4 = $this->ipv4->validate($string, $config, $context); + if ($ipv4 !== false) return $ipv4; + + // A regular domain name. + + // This breaks I18N domain names, but we don't have proper IRI support, + // so force users to insert Punycode. If there's complaining we'll + // try to fix things into an international friendly form. + + // The productions describing this are: + $a = '[a-z]'; // alpha + $an = '[a-z0-9]'; // alphanum + $and = '[a-z0-9-]'; // alphanum | "-" + // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + $domainlabel = "$an($and*$an)?"; + // toplabel = alpha | alpha *( alphanum | "-" ) alphanum + $toplabel = "$a($and*$an)?"; + // hostname = *( domainlabel "." ) toplabel [ "." ] + $match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string); + if (!$match) return false; + + return $string; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv4.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv4.php new file mode 100644 index 0000000000..ec4cf591b8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv4.php @@ -0,0 +1,39 @@ +ip4) $this->_loadRegex(); + + if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) + { + return $aIP; + } + + return false; + + } + + /** + * Lazy load function to prevent regex from being stuffed in + * cache. + */ + protected function _loadRegex() { + $oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 + $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})"; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv6.php b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv6.php new file mode 100644 index 0000000000..9454e9be50 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrDef/URI/IPv6.php @@ -0,0 +1,99 @@ +ip4) $this->_loadRegex(); + + $original = $aIP; + + $hex = '[0-9a-fA-F]'; + $blk = '(?:' . $hex . '{1,4})'; + $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 + + // prefix check + if (strpos($aIP, '/') !== false) + { + if (preg_match('#' . $pre . '$#s', $aIP, $find)) + { + $aIP = substr($aIP, 0, 0-strlen($find[0])); + unset($find); + } + else + { + return false; + } + } + + // IPv4-compatiblity check + if (preg_match('#(?<=:'.')' . $this->ip4 . '$#s', $aIP, $find)) + { + $aIP = substr($aIP, 0, 0-strlen($find[0])); + $ip = explode('.', $find[0]); + $ip = array_map('dechex', $ip); + $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; + unset($find, $ip); + } + + // compression check + $aIP = explode('::', $aIP); + $c = count($aIP); + if ($c > 2) + { + return false; + } + elseif ($c == 2) + { + list($first, $second) = $aIP; + $first = explode(':', $first); + $second = explode(':', $second); + + if (count($first) + count($second) > 8) + { + return false; + } + + while(count($first) < 8) + { + array_push($first, '0'); + } + + array_splice($first, 8 - count($second), 8, $second); + $aIP = $first; + unset($first,$second); + } + else + { + $aIP = explode(':', $aIP[0]); + } + $c = count($aIP); + + if ($c != 8) + { + return false; + } + + // All the pieces should be 16-bit hex strings. Are they? + foreach ($aIP as $piece) + { + if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) + { + return false; + } + } + + return $original; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform.php new file mode 100644 index 0000000000..e61d3e01b6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform.php @@ -0,0 +1,56 @@ +confiscateAttr($attr, 'background'); + // some validation should happen here + + $this->prependCSS($attr, "background-image:url($background);"); + + return $attr; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BdoDir.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BdoDir.php new file mode 100644 index 0000000000..4d1a05665e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BdoDir.php @@ -0,0 +1,19 @@ +get('Attr.DefaultTextDir'); + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BgColor.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BgColor.php new file mode 100644 index 0000000000..ad3916bb96 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BgColor.php @@ -0,0 +1,23 @@ +confiscateAttr($attr, 'bgcolor'); + // some validation should happen here + + $this->prependCSS($attr, "background-color:$bgcolor;"); + + return $attr; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BoolToCSS.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BoolToCSS.php new file mode 100644 index 0000000000..51159b6715 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/BoolToCSS.php @@ -0,0 +1,36 @@ +attr = $attr; + $this->css = $css; + } + + public function transform($attr, $config, $context) { + if (!isset($attr[$this->attr])) return $attr; + unset($attr[$this->attr]); + $this->prependCSS($attr, $this->css); + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Border.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Border.php new file mode 100644 index 0000000000..476b0b079b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Border.php @@ -0,0 +1,18 @@ +confiscateAttr($attr, 'border'); + // some validation should happen here + $this->prependCSS($attr, "border:{$border_width}px solid;"); + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/EnumToCSS.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/EnumToCSS.php new file mode 100644 index 0000000000..2a5b4514ab --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/EnumToCSS.php @@ -0,0 +1,58 @@ +attr = $attr; + $this->enumToCSS = $enum_to_css; + $this->caseSensitive = (bool) $case_sensitive; + } + + public function transform($attr, $config, $context) { + + if (!isset($attr[$this->attr])) return $attr; + + $value = trim($attr[$this->attr]); + unset($attr[$this->attr]); + + if (!$this->caseSensitive) $value = strtolower($value); + + if (!isset($this->enumToCSS[$value])) { + return $attr; + } + + $this->prependCSS($attr, $this->enumToCSS[$value]); + + return $attr; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgRequired.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgRequired.php new file mode 100644 index 0000000000..a219479a02 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgRequired.php @@ -0,0 +1,42 @@ +get('Core.RemoveInvalidImg')) return $attr; + $attr['src'] = $config->get('Attr.DefaultInvalidImage'); + $src = false; + } + + if (!isset($attr['alt'])) { + if ($src) { + $alt = $config->get('Attr.DefaultImageAlt'); + if ($alt === null) { + $attr['alt'] = basename($attr['src']); + } else { + $attr['alt'] = $alt; + } + } else { + $attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt'); + } + } + + return $attr; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgSpace.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgSpace.php new file mode 100644 index 0000000000..fd84c10c36 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ImgSpace.php @@ -0,0 +1,44 @@ + array('left', 'right'), + 'vspace' => array('top', 'bottom') + ); + + public function __construct($attr) { + $this->attr = $attr; + if (!isset($this->css[$attr])) { + trigger_error(htmlspecialchars($attr) . ' is not valid space attribute'); + } + } + + public function transform($attr, $config, $context) { + + if (!isset($attr[$this->attr])) return $attr; + + $width = $this->confiscateAttr($attr, $this->attr); + // some validation could happen here + + if (!isset($this->css[$this->attr])) return $attr; + + $style = ''; + foreach ($this->css[$this->attr] as $suffix) { + $property = "margin-$suffix"; + $style .= "$property:{$width}px;"; + } + + $this->prependCSS($attr, $style); + + return $attr; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Input.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Input.php new file mode 100644 index 0000000000..16829552d1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Input.php @@ -0,0 +1,40 @@ +pixels = new HTMLPurifier_AttrDef_HTML_Pixels(); + } + + public function transform($attr, $config, $context) { + if (!isset($attr['type'])) $t = 'text'; + else $t = strtolower($attr['type']); + if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') { + unset($attr['checked']); + } + if (isset($attr['maxlength']) && $t !== 'text' && $t !== 'password') { + unset($attr['maxlength']); + } + if (isset($attr['size']) && $t !== 'text' && $t !== 'password') { + $result = $this->pixels->validate($attr['size'], $config, $context); + if ($result === false) unset($attr['size']); + else $attr['size'] = $result; + } + if (isset($attr['src']) && $t !== 'image') { + unset($attr['src']); + } + if (!isset($attr['value']) && ($t === 'radio' || $t === 'checkbox')) { + $attr['value'] = ''; + } + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Lang.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Lang.php new file mode 100644 index 0000000000..5869e7f820 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Lang.php @@ -0,0 +1,28 @@ +name = $name; + $this->cssName = $css_name ? $css_name : $name; + } + + public function transform($attr, $config, $context) { + if (!isset($attr[$this->name])) return $attr; + $length = $this->confiscateAttr($attr, $this->name); + if(ctype_digit($length)) $length .= 'px'; + $this->prependCSS($attr, $this->cssName . ":$length;"); + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Name.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Name.php new file mode 100644 index 0000000000..15315bc735 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Name.php @@ -0,0 +1,21 @@ +get('HTML.Attr.Name.UseCDATA')) return $attr; + if (!isset($attr['name'])) return $attr; + $id = $this->confiscateAttr($attr, 'name'); + if ( isset($attr['id'])) return $attr; + $attr['id'] = $id; + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/NameSync.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/NameSync.php new file mode 100644 index 0000000000..a95638c140 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/NameSync.php @@ -0,0 +1,27 @@ +idDef = new HTMLPurifier_AttrDef_HTML_ID(); + } + + public function transform($attr, $config, $context) { + if (!isset($attr['name'])) return $attr; + $name = $attr['name']; + if (isset($attr['id']) && $attr['id'] === $name) return $attr; + $result = $this->idDef->validate($name, $config, $context); + if ($result === false) unset($attr['name']); + else $attr['name'] = $result; + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/SafeEmbed.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/SafeEmbed.php new file mode 100644 index 0000000000..4da449981f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/SafeEmbed.php @@ -0,0 +1,15 @@ +uri = new HTMLPurifier_AttrDef_URI(true); // embedded + } + + public function transform($attr, $config, $context) { + // If we add support for other objects, we'll need to alter the + // transforms. + switch ($attr['name']) { + // application/x-shockwave-flash + // Keep this synchronized with Injector/SafeObject.php + case 'allowScriptAccess': + $attr['value'] = 'never'; + break; + case 'allowNetworking': + $attr['value'] = 'internal'; + break; + case 'wmode': + $attr['value'] = 'window'; + break; + case 'movie': + $attr['value'] = $this->uri->validate($attr['value'], $config, $context); + break; + // add other cases to support other param name/value pairs + default: + $attr['name'] = $attr['value'] = null; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ScriptRequired.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ScriptRequired.php new file mode 100644 index 0000000000..4499050a22 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/ScriptRequired.php @@ -0,0 +1,16 @@ + + */ +class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform +{ + public function transform($attr, $config, $context) { + if (!isset($attr['type'])) { + $attr['type'] = 'text/javascript'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Textarea.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Textarea.php new file mode 100644 index 0000000000..81ac3488ba --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTransform/Textarea.php @@ -0,0 +1,18 @@ + + */ +class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform +{ + + public function transform($attr, $config, $context) { + // Calculated from Firefox + if (!isset($attr['cols'])) $attr['cols'] = '22'; + if (!isset($attr['rows'])) $attr['rows'] = '3'; + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrTypes.php b/extlib/HTMLPurifier/HTMLPurifier/AttrTypes.php new file mode 100644 index 0000000000..fc2ea4e588 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrTypes.php @@ -0,0 +1,77 @@ +info['Enum'] = new HTMLPurifier_AttrDef_Enum(); + $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); + + $this->info['CDATA'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID(); + $this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length(); + $this->info['MultiLength'] = new HTMLPurifier_AttrDef_HTML_MultiLength(); + $this->info['NMTOKENS'] = new HTMLPurifier_AttrDef_HTML_Nmtokens(); + $this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels(); + $this->info['Text'] = new HTMLPurifier_AttrDef_Text(); + $this->info['URI'] = new HTMLPurifier_AttrDef_URI(); + $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); + $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); + + // unimplemented aliases + $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ContentTypes'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Charsets'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Character'] = new HTMLPurifier_AttrDef_Text(); + + // "proprietary" types + $this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class(); + + // number is really a positive integer (one or more digits) + // FIXME: ^^ not always, see start and value of list items + $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); + } + + /** + * Retrieves a type + * @param $type String type name + * @return Object AttrDef for type + */ + public function get($type) { + + // determine if there is any extra info tacked on + if (strpos($type, '#') !== false) list($type, $string) = explode('#', $type, 2); + else $string = ''; + + if (!isset($this->info[$type])) { + trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); + return; + } + + return $this->info[$type]->make($string); + + } + + /** + * Sets a new implementation for a type + * @param $type String type name + * @param $impl Object AttrDef for type + */ + public function set($type, $impl) { + $this->info[$type] = $impl; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/AttrValidator.php b/extlib/HTMLPurifier/HTMLPurifier/AttrValidator.php new file mode 100644 index 0000000000..829a0f8f22 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/AttrValidator.php @@ -0,0 +1,162 @@ +getHTMLDefinition(); + $e =& $context->get('ErrorCollector', true); + + // initialize IDAccumulator if necessary + $ok =& $context->get('IDAccumulator', true); + if (!$ok) { + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + } + + // initialize CurrentToken if necessary + $current_token =& $context->get('CurrentToken', true); + if (!$current_token) $context->register('CurrentToken', $token); + + if ( + !$token instanceof HTMLPurifier_Token_Start && + !$token instanceof HTMLPurifier_Token_Empty + ) return $token; + + // create alias to global definition array, see also $defs + // DEFINITION CALL + $d_defs = $definition->info_global_attr; + + // don't update token until the very end, to ensure an atomic update + $attr = $token->attr; + + // do global transformations (pre) + // nothing currently utilizes this + foreach ($definition->info_attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + + // do local transformations only applicable to this element (pre) + // ex.

to

+ foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + + // create alias to this element's attribute definition array, see + // also $d_defs (global attribute definition array) + // DEFINITION CALL + $defs = $definition->info[$token->name]->attr; + + $attr_key = false; + $context->register('CurrentAttr', $attr_key); + + // iterate through all the attribute keypairs + // Watch out for name collisions: $key has previously been used + foreach ($attr as $attr_key => $value) { + + // call the definition + if ( isset($defs[$attr_key]) ) { + // there is a local definition defined + if ($defs[$attr_key] === false) { + // We've explicitly been told not to allow this element. + // This is usually when there's a global definition + // that must be overridden. + // Theoretically speaking, we could have a + // AttrDef_DenyAll, but this is faster! + $result = false; + } else { + // validate according to the element's definition + $result = $defs[$attr_key]->validate( + $value, $config, $context + ); + } + } elseif ( isset($d_defs[$attr_key]) ) { + // there is a global definition defined, validate according + // to the global definition + $result = $d_defs[$attr_key]->validate( + $value, $config, $context + ); + } else { + // system never heard of the attribute? DELETE! + $result = false; + } + + // put the results into effect + if ($result === false || $result === null) { + // this is a generic error message that should replaced + // with more specific ones when possible + if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed'); + + // remove the attribute + unset($attr[$attr_key]); + } elseif (is_string($result)) { + // generally, if a substitution is happening, there + // was some sort of implicit correction going on. We'll + // delegate it to the attribute classes to say exactly what. + + // simple substitution + $attr[$attr_key] = $result; + } else { + // nothing happens + } + + // we'd also want slightly more complicated substitution + // involving an array as the return value, + // although we're not sure how colliding attributes would + // resolve (certain ones would be completely overriden, + // others would prepend themselves). + } + + $context->destroy('CurrentAttr'); + + // post transforms + + // global (error reporting untested) + foreach ($definition->info_attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + + // local (error reporting untested) + foreach ($definition->info[$token->name]->attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + + $token->attr = $attr; + + // destroy CurrentToken if we made it ourselves + if (!$current_token) $context->destroy('CurrentToken'); + + } + + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Bootstrap.php b/extlib/HTMLPurifier/HTMLPurifier/Bootstrap.php new file mode 100644 index 0000000000..559f61a232 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Bootstrap.php @@ -0,0 +1,98 @@ + +if (!defined('PHP_EOL')) { + switch (strtoupper(substr(PHP_OS, 0, 3))) { + case 'WIN': + define('PHP_EOL', "\r\n"); + break; + case 'DAR': + define('PHP_EOL', "\r"); + break; + default: + define('PHP_EOL', "\n"); + } +} + +/** + * Bootstrap class that contains meta-functionality for HTML Purifier such as + * the autoload function. + * + * @note + * This class may be used without any other files from HTML Purifier. + */ +class HTMLPurifier_Bootstrap +{ + + /** + * Autoload function for HTML Purifier + * @param $class Class to load + */ + public static function autoload($class) { + $file = HTMLPurifier_Bootstrap::getPath($class); + if (!$file) return false; + require HTMLPURIFIER_PREFIX . '/' . $file; + return true; + } + + /** + * Returns the path for a specific class. + */ + public static function getPath($class) { + if (strncmp('HTMLPurifier', $class, 12) !== 0) return false; + // Custom implementations + if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { + $code = str_replace('_', '-', substr($class, 22)); + $file = 'HTMLPurifier/Language/classes/' . $code . '.php'; + } else { + $file = str_replace('_', '/', $class) . '.php'; + } + if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) return false; + return $file; + } + + /** + * "Pre-registers" our autoloader on the SPL stack. + */ + public static function registerAutoload() { + $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); + if ( ($funcs = spl_autoload_functions()) === false ) { + spl_autoload_register($autoload); + } elseif (function_exists('spl_autoload_unregister')) { + $compat = version_compare(PHP_VERSION, '5.1.2', '<=') && + version_compare(PHP_VERSION, '5.1.0', '>='); + foreach ($funcs as $func) { + if (is_array($func)) { + // :TRICKY: There are some compatibility issues and some + // places where we need to error out + $reflector = new ReflectionMethod($func[0], $func[1]); + if (!$reflector->isStatic()) { + throw new Exception(' + HTML Purifier autoloader registrar is not compatible + with non-static object methods due to PHP Bug #44144; + Please do not use HTMLPurifier.autoload.php (or any + file that includes this file); instead, place the code: + spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\')) + after your own autoloaders. + '); + } + // Suprisingly, spl_autoload_register supports the + // Class::staticMethod callback format, although call_user_func doesn't + if ($compat) $func = implode('::', $func); + } + spl_autoload_unregister($func); + } + spl_autoload_register($autoload); + foreach ($funcs as $func) spl_autoload_register($func); + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/CSSDefinition.php b/extlib/HTMLPurifier/HTMLPurifier/CSSDefinition.php new file mode 100644 index 0000000000..6a2e6f56d9 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/CSSDefinition.php @@ -0,0 +1,292 @@ +info['text-align'] = new HTMLPurifier_AttrDef_Enum( + array('left', 'right', 'center', 'justify'), false); + + $border_style = + $this->info['border-bottom-style'] = + $this->info['border-right-style'] = + $this->info['border-left-style'] = + $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( + array('none', 'hidden', 'dotted', 'dashed', 'solid', 'double', + 'groove', 'ridge', 'inset', 'outset'), false); + + $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); + + $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( + array('none', 'left', 'right', 'both'), false); + $this->info['float'] = new HTMLPurifier_AttrDef_Enum( + array('none', 'left', 'right'), false); + $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( + array('normal', 'italic', 'oblique'), false); + $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( + array('normal', 'small-caps'), false); + + $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('none')), + new HTMLPurifier_AttrDef_CSS_URI() + ) + ); + + $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( + array('inside', 'outside'), false); + $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( + array('disc', 'circle', 'square', 'decimal', 'lower-roman', + 'upper-roman', 'lower-alpha', 'upper-alpha', 'none'), false); + $this->info['list-style-image'] = $uri_or_none; + + $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); + + $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( + array('capitalize', 'uppercase', 'lowercase', 'none'), false); + $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['background-image'] = $uri_or_none; + $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( + array('repeat', 'repeat-x', 'repeat-y', 'no-repeat') + ); + $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( + array('scroll', 'fixed') + ); + $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); + + $border_color = + $this->info['border-top-color'] = + $this->info['border-bottom-color'] = + $this->info['border-left-color'] = + $this->info['border-right-color'] = + $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_Enum(array('transparent')), + new HTMLPurifier_AttrDef_CSS_Color() + )); + + $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); + + $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); + + $border_width = + $this->info['border-top-width'] = + $this->info['border-bottom-width'] = + $this->info['border-left-width'] = + $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')), + new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative + )); + + $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); + + $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Length() + )); + + $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Length() + )); + + $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_Enum(array('xx-small', 'x-small', + 'small', 'medium', 'large', 'x-large', 'xx-large', + 'larger', 'smaller')), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + )); + + $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + )); + + $margin = + $this->info['margin-top'] = + $this->info['margin-bottom'] = + $this->info['margin-left'] = + $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(array('auto')) + )); + + $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); + + // non-negative + $padding = + $this->info['padding-top'] = + $this->info['padding-bottom'] = + $this->info['padding-left'] = + $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + )); + + $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); + + $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + )); + + $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(array('auto')) + )); + $max = $config->get('CSS.MaxImgLength'); + + $this->info['width'] = + $this->info['height'] = + $max === null ? + $trusted_wh : + new HTMLPurifier_AttrDef_Switch('img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(array('auto')) + )), + // For everyone else: + $trusted_wh + ); + + $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); + + $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); + + // this could use specialized code + $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( + array('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', + '400', '500', '600', '700', '800', '900'), false); + + // MUST be called after other font properties, as it references + // a CSSDefinition object + $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config); + + // same here + $this->info['border'] = + $this->info['border-bottom'] = + $this->info['border-top'] = + $this->info['border-left'] = + $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); + + $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(array( + 'collapse', 'separate')); + + $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(array( + 'top', 'bottom')); + + $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(array( + 'auto', 'fixed')); + + $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + new HTMLPurifier_AttrDef_Enum(array('baseline', 'sub', 'super', + 'top', 'text-top', 'middle', 'bottom', 'text-bottom')), + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + )); + + $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); + + // partial support + $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap')); + + if ($config->get('CSS.Proprietary')) { + $this->doSetupProprietary($config); + } + + if ($config->get('CSS.AllowTricky')) { + $this->doSetupTricky($config); + } + + $allow_important = $config->get('CSS.AllowImportant'); + // wrap all attr-defs with decorator that handles !important + foreach ($this->info as $k => $v) { + $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important); + } + + $this->setupConfigStuff($config); + } + + protected function doSetupProprietary($config) { + // Internet Explorer only scrollbar colors + $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + // technically not proprietary, but CSS3, and no one supports it + $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + + // only opacity, for now + $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); + + } + + protected function doSetupTricky($config) { + $this->info['display'] = new HTMLPurifier_AttrDef_Enum(array( + 'inline', 'block', 'list-item', 'run-in', 'compact', + 'marker', 'table', 'inline-table', 'table-row-group', + 'table-header-group', 'table-footer-group', 'table-row', + 'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none' + )); + $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(array( + 'visible', 'hidden', 'collapse' + )); + $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll')); + } + + + /** + * Performs extra config-based processing. Based off of + * HTMLPurifier_HTMLDefinition. + * @todo Refactor duplicate elements into common class (probably using + * composition, not inheritance). + */ + protected function setupConfigStuff($config) { + + // setup allowed elements + $support = "(for information on implementing this, see the ". + "support forums) "; + $allowed_attributes = $config->get('CSS.AllowedProperties'); + if ($allowed_attributes !== null) { + foreach ($this->info as $name => $d) { + if(!isset($allowed_attributes[$name])) unset($this->info[$name]); + unset($allowed_attributes[$name]); + } + // emit errors + foreach ($allowed_attributes as $name => $d) { + // :TODO: Is this htmlspecialchars() call really necessary? + $name = htmlspecialchars($name); + trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING); + } + } + + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ChildDef.php b/extlib/HTMLPurifier/HTMLPurifier/ChildDef.php new file mode 100644 index 0000000000..c5d5216dab --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ChildDef.php @@ -0,0 +1,48 @@ +elements; + } + + /** + * Validates nodes according to definition and returns modification. + * + * @param $tokens_of_children Array of HTMLPurifier_Token + * @param $config HTMLPurifier_Config object + * @param $context HTMLPurifier_Context object + * @return bool true to leave nodes as is + * @return bool false to remove parent node + * @return array of replacement child tokens + */ + abstract public function validateChildren($tokens_of_children, $config, $context); +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Chameleon.php b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Chameleon.php new file mode 100644 index 0000000000..15c364ee33 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Chameleon.php @@ -0,0 +1,48 @@ +inline = new HTMLPurifier_ChildDef_Optional($inline); + $this->block = new HTMLPurifier_ChildDef_Optional($block); + $this->elements = $this->block->elements; + } + + public function validateChildren($tokens_of_children, $config, $context) { + if ($context->get('IsInline') === false) { + return $this->block->validateChildren( + $tokens_of_children, $config, $context); + } else { + return $this->inline->validateChildren( + $tokens_of_children, $config, $context); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Custom.php b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Custom.php new file mode 100644 index 0000000000..b68047b4b5 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Custom.php @@ -0,0 +1,90 @@ +dtd_regex = $dtd_regex; + $this->_compileRegex(); + } + /** + * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) + */ + protected function _compileRegex() { + $raw = str_replace(' ', '', $this->dtd_regex); + if ($raw{0} != '(') { + $raw = "($raw)"; + } + $el = '[#a-zA-Z0-9_.-]+'; + $reg = $raw; + + // COMPLICATED! AND MIGHT BE BUGGY! I HAVE NO CLUE WHAT I'M + // DOING! Seriously: if there's problems, please report them. + + // collect all elements into the $elements array + preg_match_all("/$el/", $reg, $matches); + foreach ($matches[0] as $match) { + $this->elements[$match] = true; + } + + // setup all elements as parentheticals with leading commas + $reg = preg_replace("/$el/", '(,\\0)', $reg); + + // remove commas when they were not solicited + $reg = preg_replace("/([^,(|]\(+),/", '\\1', $reg); + + // remove all non-paranthetical commas: they are handled by first regex + $reg = preg_replace("/,\(/", '(', $reg); + + $this->_pcre_regex = $reg; + } + public function validateChildren($tokens_of_children, $config, $context) { + $list_of_children = ''; + $nesting = 0; // depth into the nest + foreach ($tokens_of_children as $token) { + if (!empty($token->is_whitespace)) continue; + + $is_child = ($nesting == 0); // direct + + if ($token instanceof HTMLPurifier_Token_Start) { + $nesting++; + } elseif ($token instanceof HTMLPurifier_Token_End) { + $nesting--; + } + + if ($is_child) { + $list_of_children .= $token->name . ','; + } + } + // add leading comma to deal with stray comma declarations + $list_of_children = ',' . rtrim($list_of_children, ','); + $okay = + preg_match( + '/^,?'.$this->_pcre_regex.'$/', + $list_of_children + ); + + return (bool) $okay; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Empty.php b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Empty.php new file mode 100644 index 0000000000..13171f6651 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Empty.php @@ -0,0 +1,20 @@ +whitespace) return $tokens_of_children; + else return array(); + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Required.php b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Required.php new file mode 100644 index 0000000000..4889f249b8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Required.php @@ -0,0 +1,117 @@ + $x) { + $elements[$i] = true; + if (empty($i)) unset($elements[$i]); // remove blank + } + } + $this->elements = $elements; + } + public $allow_empty = false; + public $type = 'required'; + public function validateChildren($tokens_of_children, $config, $context) { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($tokens_of_children)) return false; + + // the new set of children + $result = array(); + + // current depth into the nest + $nesting = 0; + + // whether or not we're deleting a node + $is_deleting = false; + + // whether or not parsed character data is allowed + // this controls whether or not we silently drop a tag + // or generate escaped HTML from it + $pcdata_allowed = isset($this->elements['#PCDATA']); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + // some configuration + $escape_invalid_children = $config->get('Core.EscapeInvalidChildren'); + + // generator + $gen = new HTMLPurifier_Generator($config, $context); + + foreach ($tokens_of_children as $token) { + if (!empty($token->is_whitespace)) { + $result[] = $token; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + $is_child = ($nesting == 0); + + if ($token instanceof HTMLPurifier_Token_Start) { + $nesting++; + } elseif ($token instanceof HTMLPurifier_Token_End) { + $nesting--; + } + + if ($is_child) { + $is_deleting = false; + if (!isset($this->elements[$token->name])) { + $is_deleting = true; + if ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text) { + $result[] = $token; + } elseif ($pcdata_allowed && $escape_invalid_children) { + $result[] = new HTMLPurifier_Token_Text( + $gen->generateFromToken($token) + ); + } + continue; + } + } + if (!$is_deleting || ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text)) { + $result[] = $token; + } elseif ($pcdata_allowed && $escape_invalid_children) { + $result[] = + new HTMLPurifier_Token_Text( + $gen->generateFromToken($token) + ); + } else { + // drop silently + } + } + if (empty($result)) return false; + if ($all_whitespace) { + $this->whitespace = true; + return false; + } + if ($tokens_of_children == $result) return true; + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ChildDef/StrictBlockquote.php b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/StrictBlockquote.php new file mode 100644 index 0000000000..dfae8a6e5e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/StrictBlockquote.php @@ -0,0 +1,88 @@ +init($config); + return $this->fake_elements; + } + + public function validateChildren($tokens_of_children, $config, $context) { + + $this->init($config); + + // trick the parent class into thinking it allows more + $this->elements = $this->fake_elements; + $result = parent::validateChildren($tokens_of_children, $config, $context); + $this->elements = $this->real_elements; + + if ($result === false) return array(); + if ($result === true) $result = $tokens_of_children; + + $def = $config->getHTMLDefinition(); + $block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper); + $block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper); + $is_inline = false; + $depth = 0; + $ret = array(); + + // assuming that there are no comment tokens + foreach ($result as $i => $token) { + $token = $result[$i]; + // ifs are nested for readability + if (!$is_inline) { + if (!$depth) { + if ( + ($token instanceof HTMLPurifier_Token_Text && !$token->is_whitespace) || + (!$token instanceof HTMLPurifier_Token_Text && !isset($this->elements[$token->name])) + ) { + $is_inline = true; + $ret[] = $block_wrap_start; + } + } + } else { + if (!$depth) { + // starting tokens have been inline text / empty + if ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) { + if (isset($this->elements[$token->name])) { + // ended + $ret[] = $block_wrap_end; + $is_inline = false; + } + } + } + } + $ret[] = $token; + if ($token instanceof HTMLPurifier_Token_Start) $depth++; + if ($token instanceof HTMLPurifier_Token_End) $depth--; + } + if ($is_inline) $ret[] = $block_wrap_end; + return $ret; + } + + private function init($config) { + if (!$this->init) { + $def = $config->getHTMLDefinition(); + // allow all inline elements + $this->real_elements = $this->elements; + $this->fake_elements = $def->info_content_sets['Flow']; + $this->fake_elements['#PCDATA'] = true; + $this->init = true; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Table.php b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Table.php new file mode 100644 index 0000000000..34f0227dd2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ChildDef/Table.php @@ -0,0 +1,142 @@ + true, 'tbody' => true, 'thead' => true, + 'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true); + public function __construct() {} + public function validateChildren($tokens_of_children, $config, $context) { + if (empty($tokens_of_children)) return false; + + // this ensures that the loop gets run one last time before closing + // up. It's a little bit of a hack, but it works! Just make sure you + // get rid of the token later. + $tokens_of_children[] = false; + + // only one of these elements is allowed in a table + $caption = false; + $thead = false; + $tfoot = false; + + // as many of these as you want + $cols = array(); + $content = array(); + + $nesting = 0; // current depth so we can determine nodes + $is_collecting = false; // are we globbing together tokens to package + // into one of the collectors? + $collection = array(); // collected nodes + $tag_index = 0; // the first node might be whitespace, + // so this tells us where the start tag is + + foreach ($tokens_of_children as $token) { + $is_child = ($nesting == 0); + + if ($token === false) { + // terminating sequence started + } elseif ($token instanceof HTMLPurifier_Token_Start) { + $nesting++; + } elseif ($token instanceof HTMLPurifier_Token_End) { + $nesting--; + } + + // handle node collection + if ($is_collecting) { + if ($is_child) { + // okay, let's stash the tokens away + // first token tells us the type of the collection + switch ($collection[$tag_index]->name) { + case 'tr': + case 'tbody': + $content[] = $collection; + break; + case 'caption': + if ($caption !== false) break; + $caption = $collection; + break; + case 'thead': + case 'tfoot': + // access the appropriate variable, $thead or $tfoot + $var = $collection[$tag_index]->name; + if ($$var === false) { + $$var = $collection; + } else { + // transmutate the first and less entries into + // tbody tags, and then put into content + $collection[$tag_index]->name = 'tbody'; + $collection[count($collection)-1]->name = 'tbody'; + $content[] = $collection; + } + break; + case 'colgroup': + $cols[] = $collection; + break; + } + $collection = array(); + $is_collecting = false; + $tag_index = 0; + } else { + // add the node to the collection + $collection[] = $token; + } + } + + // terminate + if ($token === false) break; + + if ($is_child) { + // determine what we're dealing with + if ($token->name == 'col') { + // the only empty tag in the possie, we can handle it + // immediately + $cols[] = array_merge($collection, array($token)); + $collection = array(); + $tag_index = 0; + continue; + } + switch($token->name) { + case 'caption': + case 'colgroup': + case 'thead': + case 'tfoot': + case 'tbody': + case 'tr': + $is_collecting = true; + $collection[] = $token; + continue; + default: + if (!empty($token->is_whitespace)) { + $collection[] = $token; + $tag_index++; + } + continue; + } + } + } + + if (empty($content)) return false; + + $ret = array(); + if ($caption !== false) $ret = array_merge($ret, $caption); + if ($cols !== false) foreach ($cols as $token_array) $ret = array_merge($ret, $token_array); + if ($thead !== false) $ret = array_merge($ret, $thead); + if ($tfoot !== false) $ret = array_merge($ret, $tfoot); + foreach ($content as $token_array) $ret = array_merge($ret, $token_array); + if (!empty($collection) && $is_collecting == false){ + // grab the trailing space + $ret = array_merge($ret, $collection); + } + + array_pop($tokens_of_children); // remove phantom token + + return ($ret === $tokens_of_children) ? true : $ret; + + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Config.php b/extlib/HTMLPurifier/HTMLPurifier/Config.php new file mode 100644 index 0000000000..a01706043a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Config.php @@ -0,0 +1,580 @@ +defaultPlist; + $this->plist = new HTMLPurifier_PropertyList($parent); + $this->def = $definition; // keep a copy around for checking + $this->parser = new HTMLPurifier_VarParser_Flexible(); + } + + /** + * Convenience constructor that creates a config object based on a mixed var + * @param mixed $config Variable that defines the state of the config + * object. Can be: a HTMLPurifier_Config() object, + * an array of directives based on loadArray(), + * or a string filename of an ini file. + * @param HTMLPurifier_ConfigSchema Schema object + * @return Configured HTMLPurifier_Config object + */ + public static function create($config, $schema = null) { + if ($config instanceof HTMLPurifier_Config) { + // pass-through + return $config; + } + if (!$schema) { + $ret = HTMLPurifier_Config::createDefault(); + } else { + $ret = new HTMLPurifier_Config($schema); + } + if (is_string($config)) $ret->loadIni($config); + elseif (is_array($config)) $ret->loadArray($config); + return $ret; + } + + /** + * Creates a new config object that inherits from a previous one. + * @param HTMLPurifier_Config $config Configuration object to inherit + * from. + * @return HTMLPurifier_Config object with $config as its parent. + */ + public static function inherit(HTMLPurifier_Config $config) { + return new HTMLPurifier_Config($config->def, $config->plist); + } + + /** + * Convenience constructor that creates a default configuration object. + * @return Default HTMLPurifier_Config object. + */ + public static function createDefault() { + $definition = HTMLPurifier_ConfigSchema::instance(); + $config = new HTMLPurifier_Config($definition); + return $config; + } + + /** + * Retreives a value from the configuration. + * @param $key String key + */ + public function get($key, $a = null) { + if ($a !== null) { + $this->triggerError("Using deprecated API: use \$config->get('$key.$a') instead", E_USER_WARNING); + $key = "$key.$a"; + } + if (!$this->finalized) $this->autoFinalize(); + if (!isset($this->def->info[$key])) { + // can't add % due to SimpleTest bug + $this->triggerError('Cannot retrieve value of undefined directive ' . htmlspecialchars($key), + E_USER_WARNING); + return; + } + if (isset($this->def->info[$key]->isAlias)) { + $d = $this->def->info[$key]; + $this->triggerError('Cannot get value from aliased directive, use real name ' . $d->key, + E_USER_ERROR); + return; + } + if ($this->lock) { + list($ns) = explode('.', $key); + if ($ns !== $this->lock) { + $this->triggerError('Cannot get value of namespace ' . $ns . ' when lock for ' . $this->lock . ' is active, this probably indicates a Definition setup method is accessing directives that are not within its namespace', E_USER_ERROR); + return; + } + } + return $this->plist->get($key); + } + + /** + * Retreives an array of directives to values from a given namespace + * @param $namespace String namespace + */ + public function getBatch($namespace) { + if (!$this->finalized) $this->autoFinalize(); + $full = $this->getAll(); + if (!isset($full[$namespace])) { + $this->triggerError('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace), + E_USER_WARNING); + return; + } + return $full[$namespace]; + } + + /** + * Returns a md5 signature of a segment of the configuration object + * that uniquely identifies that particular configuration + * @note Revision is handled specially and is removed from the batch + * before processing! + * @param $namespace Namespace to get serial for + */ + public function getBatchSerial($namespace) { + if (empty($this->serials[$namespace])) { + $batch = $this->getBatch($namespace); + unset($batch['DefinitionRev']); + $this->serials[$namespace] = md5(serialize($batch)); + } + return $this->serials[$namespace]; + } + + /** + * Returns a md5 signature for the entire configuration object + * that uniquely identifies that particular configuration + */ + public function getSerial() { + if (empty($this->serial)) { + $this->serial = md5(serialize($this->getAll())); + } + return $this->serial; + } + + /** + * Retrieves all directives, organized by namespace + * @warning This is a pretty inefficient function, avoid if you can + */ + public function getAll() { + if (!$this->finalized) $this->autoFinalize(); + $ret = array(); + foreach ($this->plist->squash() as $name => $value) { + list($ns, $key) = explode('.', $name, 2); + $ret[$ns][$key] = $value; + } + return $ret; + } + + /** + * Sets a value to configuration. + * @param $key String key + * @param $value Mixed value + */ + public function set($key, $value, $a = null) { + if (strpos($key, '.') === false) { + $namespace = $key; + $directive = $value; + $value = $a; + $key = "$key.$directive"; + $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE); + } else { + list($namespace) = explode('.', $key); + } + if ($this->isFinalized('Cannot set directive after finalization')) return; + if (!isset($this->def->info[$key])) { + $this->triggerError('Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', + E_USER_WARNING); + return; + } + $def = $this->def->info[$key]; + + if (isset($def->isAlias)) { + if ($this->aliasMode) { + $this->triggerError('Double-aliases not allowed, please fix '. + 'ConfigSchema bug with' . $key, E_USER_ERROR); + return; + } + $this->aliasMode = true; + $this->set($def->key, $value); + $this->aliasMode = false; + $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE); + return; + } + + // Raw type might be negative when using the fully optimized form + // of stdclass, which indicates allow_null == true + $rtype = is_int($def) ? $def : $def->type; + if ($rtype < 0) { + $type = -$rtype; + $allow_null = true; + } else { + $type = $rtype; + $allow_null = isset($def->allow_null); + } + + try { + $value = $this->parser->parse($value, $type, $allow_null); + } catch (HTMLPurifier_VarParserException $e) { + $this->triggerError('Value for ' . $key . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING); + return; + } + if (is_string($value) && is_object($def)) { + // resolve value alias if defined + if (isset($def->aliases[$value])) { + $value = $def->aliases[$value]; + } + // check to see if the value is allowed + if (isset($def->allowed) && !isset($def->allowed[$value])) { + $this->triggerError('Value not supported, valid values are: ' . + $this->_listify($def->allowed), E_USER_WARNING); + return; + } + } + $this->plist->set($key, $value); + + // reset definitions if the directives they depend on changed + // this is a very costly process, so it's discouraged + // with finalization + if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') { + $this->definitions[$namespace] = null; + } + + $this->serials[$namespace] = false; + } + + /** + * Convenience function for error reporting + */ + private function _listify($lookup) { + $list = array(); + foreach ($lookup as $name => $b) $list[] = $name; + return implode(', ', $list); + } + + /** + * Retrieves object reference to the HTML definition. + * @param $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + */ + public function getHTMLDefinition($raw = false) { + return $this->getDefinition('HTML', $raw); + } + + /** + * Retrieves object reference to the CSS definition + * @param $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + */ + public function getCSSDefinition($raw = false) { + return $this->getDefinition('CSS', $raw); + } + + /** + * Retrieves a definition + * @param $type Type of definition: HTML, CSS, etc + * @param $raw Whether or not definition should be returned raw + */ + public function getDefinition($type, $raw = false) { + if (!$this->finalized) $this->autoFinalize(); + // temporarily suspend locks, so we can handle recursive definition calls + $lock = $this->lock; + $this->lock = null; + $factory = HTMLPurifier_DefinitionCacheFactory::instance(); + $cache = $factory->create($type, $this); + $this->lock = $lock; + if (!$raw) { + // see if we can quickly supply a definition + if (!empty($this->definitions[$type])) { + if (!$this->definitions[$type]->setup) { + $this->definitions[$type]->setup($this); + $cache->set($this->definitions[$type], $this); + } + return $this->definitions[$type]; + } + // memory check missed, try cache + $this->definitions[$type] = $cache->get($this); + if ($this->definitions[$type]) { + // definition in cache, return it + return $this->definitions[$type]; + } + } elseif ( + !empty($this->definitions[$type]) && + !$this->definitions[$type]->setup + ) { + // raw requested, raw in memory, quick return + return $this->definitions[$type]; + } + // quick checks failed, let's create the object + if ($type == 'HTML') { + $this->definitions[$type] = new HTMLPurifier_HTMLDefinition(); + } elseif ($type == 'CSS') { + $this->definitions[$type] = new HTMLPurifier_CSSDefinition(); + } elseif ($type == 'URI') { + $this->definitions[$type] = new HTMLPurifier_URIDefinition(); + } else { + throw new HTMLPurifier_Exception("Definition of $type type not supported"); + } + // quick abort if raw + if ($raw) { + if (is_null($this->get($type . '.DefinitionID'))) { + // fatally error out if definition ID not set + throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID"); + } + return $this->definitions[$type]; + } + // set it up + $this->lock = $type; + $this->definitions[$type]->setup($this); + $this->lock = null; + // save in cache + $cache->set($this->definitions[$type], $this); + return $this->definitions[$type]; + } + + /** + * Loads configuration values from an array with the following structure: + * Namespace.Directive => Value + * @param $config_array Configuration associative array + */ + public function loadArray($config_array) { + if ($this->isFinalized('Cannot load directives after finalization')) return; + foreach ($config_array as $key => $value) { + $key = str_replace('_', '.', $key); + if (strpos($key, '.') !== false) { + $this->set($key, $value); + } else { + $namespace = $key; + $namespace_values = $value; + foreach ($namespace_values as $directive => $value) { + $this->set($namespace .'.'. $directive, $value); + } + } + } + } + + /** + * Returns a list of array(namespace, directive) for all directives + * that are allowed in a web-form context as per an allowed + * namespaces/directives list. + * @param $allowed List of allowed namespaces/directives + */ + public static function getAllowedDirectivesForForm($allowed, $schema = null) { + if (!$schema) { + $schema = HTMLPurifier_ConfigSchema::instance(); + } + if ($allowed !== true) { + if (is_string($allowed)) $allowed = array($allowed); + $allowed_ns = array(); + $allowed_directives = array(); + $blacklisted_directives = array(); + foreach ($allowed as $ns_or_directive) { + if (strpos($ns_or_directive, '.') !== false) { + // directive + if ($ns_or_directive[0] == '-') { + $blacklisted_directives[substr($ns_or_directive, 1)] = true; + } else { + $allowed_directives[$ns_or_directive] = true; + } + } else { + // namespace + $allowed_ns[$ns_or_directive] = true; + } + } + } + $ret = array(); + foreach ($schema->info as $key => $def) { + list($ns, $directive) = explode('.', $key, 2); + if ($allowed !== true) { + if (isset($blacklisted_directives["$ns.$directive"])) continue; + if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue; + } + if (isset($def->isAlias)) continue; + if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue; + $ret[] = array($ns, $directive); + } + return $ret; + } + + /** + * Loads configuration values from $_GET/$_POST that were posted + * via ConfigForm + * @param $array $_GET or $_POST array to import + * @param $index Index/name that the config variables are in + * @param $allowed List of allowed namespaces/directives + * @param $mq_fix Boolean whether or not to enable magic quotes fix + * @param $schema Instance of HTMLPurifier_ConfigSchema to use, if not global copy + */ + public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); + $config = HTMLPurifier_Config::create($ret, $schema); + return $config; + } + + /** + * Merges in configuration values from $_GET/$_POST to object. NOT STATIC. + * @note Same parameters as loadArrayFromForm + */ + public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); + $this->loadArray($ret); + } + + /** + * Prepares an array from a form into something usable for the more + * strict parts of HTMLPurifier_Config + */ + public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { + if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); + $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); + $ret = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $skey = "$ns.$directive"; + if (!empty($array["Null_$skey"])) { + $ret[$ns][$directive] = null; + continue; + } + if (!isset($array[$skey])) continue; + $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; + $ret[$ns][$directive] = $value; + } + return $ret; + } + + /** + * Loads configuration values from an ini file + * @param $filename Name of ini file + */ + public function loadIni($filename) { + if ($this->isFinalized('Cannot load directives after finalization')) return; + $array = parse_ini_file($filename, true); + $this->loadArray($array); + } + + /** + * Checks whether or not the configuration object is finalized. + * @param $error String error message, or false for no error + */ + public function isFinalized($error = false) { + if ($this->finalized && $error) { + $this->triggerError($error, E_USER_ERROR); + } + return $this->finalized; + } + + /** + * Finalizes configuration only if auto finalize is on and not + * already finalized + */ + public function autoFinalize() { + if ($this->autoFinalize) { + $this->finalize(); + } else { + $this->plist->squash(true); + } + } + + /** + * Finalizes a configuration object, prohibiting further change + */ + public function finalize() { + $this->finalized = true; + unset($this->parser); + } + + /** + * Produces a nicely formatted error message by supplying the + * stack frame information from two levels up and OUTSIDE of + * HTMLPurifier_Config. + */ + protected function triggerError($msg, $no) { + // determine previous stack frame + $backtrace = debug_backtrace(); + if ($this->chatty && isset($backtrace[1])) { + $frame = $backtrace[1]; + $extra = " on line {$frame['line']} in file {$frame['file']}"; + } else { + $extra = ''; + } + trigger_error($msg . $extra, $no); + } + + /** + * Returns a serialized form of the configuration object that can + * be reconstituted. + */ + public function serialize() { + $this->getDefinition('HTML'); + $this->getDefinition('CSS'); + $this->getDefinition('URI'); + return serialize($this); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema.php new file mode 100644 index 0000000000..67be5c71fd --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema.php @@ -0,0 +1,158 @@ + array( + * 'Directive' => new stdclass(), + * ) + * ) + * + * The stdclass may have the following properties: + * + * - If isAlias isn't set: + * - type: Integer type of directive, see HTMLPurifier_VarParser for definitions + * - allow_null: If set, this directive allows null values + * - aliases: If set, an associative array of value aliases to real values + * - allowed: If set, a lookup array of allowed (string) values + * - If isAlias is set: + * - namespace: Namespace this directive aliases to + * - name: Directive name this directive aliases to + * + * In certain degenerate cases, stdclass will actually be an integer. In + * that case, the value is equivalent to an stdclass with the type + * property set to the integer. If the integer is negative, type is + * equal to the absolute value of integer, and allow_null is true. + * + * This class is friendly with HTMLPurifier_Config. If you need introspection + * about the schema, you're better of using the ConfigSchema_Interchange, + * which uses more memory but has much richer information. + */ + public $info = array(); + + /** + * Application-wide singleton + */ + static protected $singleton; + + public function __construct() { + $this->defaultPlist = new HTMLPurifier_PropertyList(); + } + + /** + * Unserializes the default ConfigSchema. + */ + public static function makeFromSerial() { + return unserialize(file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser')); + } + + /** + * Retrieves an instance of the application-wide configuration definition. + */ + public static function instance($prototype = null) { + if ($prototype !== null) { + HTMLPurifier_ConfigSchema::$singleton = $prototype; + } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) { + HTMLPurifier_ConfigSchema::$singleton = HTMLPurifier_ConfigSchema::makeFromSerial(); + } + return HTMLPurifier_ConfigSchema::$singleton; + } + + /** + * Defines a directive for configuration + * @warning Will fail of directive's namespace is defined. + * @warning This method's signature is slightly different from the legacy + * define() static method! Beware! + * @param $namespace Namespace the directive is in + * @param $name Key of directive + * @param $default Default value of directive + * @param $type Allowed type of the directive. See + * HTMLPurifier_DirectiveDef::$type for allowed values + * @param $allow_null Whether or not to allow null values + */ + public function add($key, $default, $type, $allow_null) { + $obj = new stdclass(); + $obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type]; + if ($allow_null) $obj->allow_null = true; + $this->info[$key] = $obj; + $this->defaults[$key] = $default; + $this->defaultPlist->set($key, $default); + } + + /** + * Defines a directive value alias. + * + * Directive value aliases are convenient for developers because it lets + * them set a directive to several values and get the same result. + * @param $namespace Directive's namespace + * @param $name Name of Directive + * @param $aliases Hash of aliased values to the real alias + */ + public function addValueAliases($key, $aliases) { + if (!isset($this->info[$key]->aliases)) { + $this->info[$key]->aliases = array(); + } + foreach ($aliases as $alias => $real) { + $this->info[$key]->aliases[$alias] = $real; + } + } + + /** + * Defines a set of allowed values for a directive. + * @warning This is slightly different from the corresponding static + * method definition. + * @param $namespace Namespace of directive + * @param $name Name of directive + * @param $allowed Lookup array of allowed values + */ + public function addAllowedValues($key, $allowed) { + $this->info[$key]->allowed = $allowed; + } + + /** + * Defines a directive alias for backwards compatibility + * @param $namespace + * @param $name Directive that will be aliased + * @param $new_namespace + * @param $new_name Directive that the alias will be to + */ + public function addAlias($key, $new_key) { + $obj = new stdclass; + $obj->key = $new_key; + $obj->isAlias = true; + $this->info[$key] = $obj; + } + + /** + * Replaces any stdclass that only has the type property with type integer. + */ + public function postProcess() { + foreach ($this->info as $key => $v) { + if (count((array) $v) == 1) { + $this->info[$key] = $v->type; + } elseif (count((array) $v) == 2 && isset($v->allow_null)) { + $this->info[$key] = -$v->type; + } + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php new file mode 100644 index 0000000000..c05668a706 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php @@ -0,0 +1,44 @@ +directives as $d) { + $schema->add( + $d->id->key, + $d->default, + $d->type, + $d->typeAllowsNull + ); + if ($d->allowed !== null) { + $schema->addAllowedValues( + $d->id->key, + $d->allowed + ); + } + foreach ($d->aliases as $alias) { + $schema->addAlias( + $alias->key, + $d->id->key + ); + } + if ($d->valueAliases !== null) { + $schema->addValueAliases( + $d->id->key, + $d->valueAliases + ); + } + } + $schema->postProcess(); + return $schema; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/Xml.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/Xml.php new file mode 100644 index 0000000000..244561a372 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Builder/Xml.php @@ -0,0 +1,106 @@ +startElement('div'); + + $purifier = HTMLPurifier::getInstance(); + $html = $purifier->purify($html); + $this->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); + $this->writeRaw($html); + + $this->endElement(); // div + } + + protected function export($var) { + if ($var === array()) return 'array()'; + return var_export($var, true); + } + + public function build($interchange) { + // global access, only use as last resort + $this->interchange = $interchange; + + $this->setIndent(true); + $this->startDocument('1.0', 'UTF-8'); + $this->startElement('configdoc'); + $this->writeElement('title', $interchange->name); + + foreach ($interchange->directives as $directive) { + $this->buildDirective($directive); + } + + if ($this->namespace) $this->endElement(); // namespace + + $this->endElement(); // configdoc + $this->flush(); + } + + public function buildDirective($directive) { + + // Kludge, although I suppose having a notion of a "root namespace" + // certainly makes things look nicer when documentation is built. + // Depends on things being sorted. + if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) { + if ($this->namespace) $this->endElement(); // namespace + $this->namespace = $directive->id->getRootNamespace(); + $this->startElement('namespace'); + $this->writeAttribute('id', $this->namespace); + $this->writeElement('name', $this->namespace); + } + + $this->startElement('directive'); + $this->writeAttribute('id', $directive->id->toString()); + + $this->writeElement('name', $directive->id->getDirective()); + + $this->startElement('aliases'); + foreach ($directive->aliases as $alias) $this->writeElement('alias', $alias->toString()); + $this->endElement(); // aliases + + $this->startElement('constraints'); + if ($directive->version) $this->writeElement('version', $directive->version); + $this->startElement('type'); + if ($directive->typeAllowsNull) $this->writeAttribute('allow-null', 'yes'); + $this->text($directive->type); + $this->endElement(); // type + if ($directive->allowed) { + $this->startElement('allowed'); + foreach ($directive->allowed as $value => $x) $this->writeElement('value', $value); + $this->endElement(); // allowed + } + $this->writeElement('default', $this->export($directive->default)); + $this->writeAttribute('xml:space', 'preserve'); + if ($directive->external) { + $this->startElement('external'); + foreach ($directive->external as $project) $this->writeElement('project', $project); + $this->endElement(); + } + $this->endElement(); // constraints + + if ($directive->deprecatedVersion) { + $this->startElement('deprecated'); + $this->writeElement('version', $directive->deprecatedVersion); + $this->writeElement('use', $directive->deprecatedUse->toString()); + $this->endElement(); // deprecated + } + + $this->startElement('description'); + $this->writeHTMLDiv($directive->description); + $this->endElement(); // description + + $this->endElement(); // directive + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Exception.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Exception.php new file mode 100644 index 0000000000..2671516c58 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Exception.php @@ -0,0 +1,11 @@ + array(directive info) + */ + public $directives = array(); + + /** + * Adds a directive array to $directives + */ + public function addDirective($directive) { + if (isset($this->directives[$i = $directive->id->toString()])) { + throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'"); + } + $this->directives[$i] = $directive; + } + + /** + * Convenience function to perform standard validation. Throws exception + * on failed validation. + */ + public function validate() { + $validator = new HTMLPurifier_ConfigSchema_Validator(); + return $validator->validate($this); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Directive.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Directive.php new file mode 100644 index 0000000000..ac8be0d970 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Directive.php @@ -0,0 +1,77 @@ + true). + * Null if all values are allowed. + */ + public $allowed; + + /** + * List of aliases for the directive, + * e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))). + */ + public $aliases = array(); + + /** + * Hash of value aliases, e.g. array('alt' => 'real'). Null if value + * aliasing is disabled (necessary for non-scalar types). + */ + public $valueAliases; + + /** + * Version of HTML Purifier the directive was introduced, e.g. '1.3.1'. + * Null if the directive has always existed. + */ + public $version; + + /** + * ID of directive that supercedes this old directive, is an instance + * of HTMLPurifier_ConfigSchema_Interchange_Id. Null if not deprecated. + */ + public $deprecatedUse; + + /** + * Version of HTML Purifier this directive was deprecated. Null if not + * deprecated. + */ + public $deprecatedVersion; + + /** + * List of external projects this directive depends on, e.g. array('CSSTidy'). + */ + public $external = array(); + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Id.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Id.php new file mode 100644 index 0000000000..b9b3c6f5cf --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Interchange/Id.php @@ -0,0 +1,37 @@ +key = $key; + } + + /** + * @warning This is NOT magic, to ensure that people don't abuse SPL and + * cause problems for PHP 5.0 support. + */ + public function toString() { + return $this->key; + } + + public function getRootNamespace() { + return substr($this->key, 0, strpos($this->key, ".")); + } + + public function getDirective() { + return substr($this->key, strpos($this->key, ".") + 1); + } + + public static function make($id) { + return new HTMLPurifier_ConfigSchema_Interchange_Id($id); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/InterchangeBuilder.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/InterchangeBuilder.php new file mode 100644 index 0000000000..785b72ce8e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/InterchangeBuilder.php @@ -0,0 +1,180 @@ +varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native(); + } + + public static function buildFromDirectory($dir = null) { + $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); + $interchange = new HTMLPurifier_ConfigSchema_Interchange(); + return $builder->buildDir($interchange, $dir); + } + + public function buildDir($interchange, $dir = null) { + if (!$dir) $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema'; + if (file_exists($dir . '/info.ini')) { + $info = parse_ini_file($dir . '/info.ini'); + $interchange->name = $info['name']; + } + + $files = array(); + $dh = opendir($dir); + while (false !== ($file = readdir($dh))) { + if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') { + continue; + } + $files[] = $file; + } + closedir($dh); + + sort($files); + foreach ($files as $file) { + $this->buildFile($interchange, $dir . '/' . $file); + } + + return $interchange; + } + + public function buildFile($interchange, $file) { + $parser = new HTMLPurifier_StringHashParser(); + $this->build( + $interchange, + new HTMLPurifier_StringHash( $parser->parseFile($file) ) + ); + } + + /** + * Builds an interchange object based on a hash. + * @param $interchange HTMLPurifier_ConfigSchema_Interchange object to build + * @param $hash HTMLPurifier_ConfigSchema_StringHash source data + */ + public function build($interchange, $hash) { + if (!$hash instanceof HTMLPurifier_StringHash) { + $hash = new HTMLPurifier_StringHash($hash); + } + if (!isset($hash['ID'])) { + throw new HTMLPurifier_ConfigSchema_Exception('Hash does not have any ID'); + } + if (strpos($hash['ID'], '.') === false) { + if (count($hash) == 2 && isset($hash['DESCRIPTION'])) { + $hash->offsetGet('DESCRIPTION'); // prevent complaining + } else { + throw new HTMLPurifier_ConfigSchema_Exception('All directives must have a namespace'); + } + } else { + $this->buildDirective($interchange, $hash); + } + $this->_findUnused($hash); + } + + public function buildDirective($interchange, $hash) { + $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive(); + + // These are required elements: + $directive->id = $this->id($hash->offsetGet('ID')); + $id = $directive->id->toString(); // convenience + + if (isset($hash['TYPE'])) { + $type = explode('/', $hash->offsetGet('TYPE')); + if (isset($type[1])) $directive->typeAllowsNull = true; + $directive->type = $type[0]; + } else { + throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined"); + } + + if (isset($hash['DEFAULT'])) { + try { + $directive->default = $this->varParser->parse($hash->offsetGet('DEFAULT'), $directive->type, $directive->typeAllowsNull); + } catch (HTMLPurifier_VarParserException $e) { + throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'"); + } + } + + if (isset($hash['DESCRIPTION'])) { + $directive->description = $hash->offsetGet('DESCRIPTION'); + } + + if (isset($hash['ALLOWED'])) { + $directive->allowed = $this->lookup($this->evalArray($hash->offsetGet('ALLOWED'))); + } + + if (isset($hash['VALUE-ALIASES'])) { + $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES')); + } + + if (isset($hash['ALIASES'])) { + $raw_aliases = trim($hash->offsetGet('ALIASES')); + $aliases = preg_split('/\s*,\s*/', $raw_aliases); + foreach ($aliases as $alias) { + $directive->aliases[] = $this->id($alias); + } + } + + if (isset($hash['VERSION'])) { + $directive->version = $hash->offsetGet('VERSION'); + } + + if (isset($hash['DEPRECATED-USE'])) { + $directive->deprecatedUse = $this->id($hash->offsetGet('DEPRECATED-USE')); + } + + if (isset($hash['DEPRECATED-VERSION'])) { + $directive->deprecatedVersion = $hash->offsetGet('DEPRECATED-VERSION'); + } + + if (isset($hash['EXTERNAL'])) { + $directive->external = preg_split('/\s*,\s*/', trim($hash->offsetGet('EXTERNAL'))); + } + + $interchange->addDirective($directive); + } + + /** + * Evaluates an array PHP code string without array() wrapper + */ + protected function evalArray($contents) { + return eval('return array('. $contents .');'); + } + + /** + * Converts an array list into a lookup array. + */ + protected function lookup($array) { + $ret = array(); + foreach ($array as $val) $ret[$val] = true; + return $ret; + } + + /** + * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id + * object based on a string Id. + */ + protected function id($id) { + return HTMLPurifier_ConfigSchema_Interchange_Id::make($id); + } + + /** + * Triggers errors for any unused keys passed in the hash; such keys + * may indicate typos, missing values, etc. + * @param $hash Instance of ConfigSchema_StringHash to check. + */ + protected function _findUnused($hash) { + $accessed = $hash->getAccessed(); + foreach ($hash as $k => $v) { + if (!isset($accessed[$k])) { + trigger_error("String hash key '$k' not used by builder", E_USER_NOTICE); + } + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Validator.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Validator.php new file mode 100644 index 0000000000..f374f6a022 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/Validator.php @@ -0,0 +1,206 @@ +parser = new HTMLPurifier_VarParser(); + } + + /** + * Validates a fully-formed interchange object. Throws an + * HTMLPurifier_ConfigSchema_Exception if there's a problem. + */ + public function validate($interchange) { + $this->interchange = $interchange; + $this->aliases = array(); + // PHP is a bit lax with integer <=> string conversions in + // arrays, so we don't use the identical !== comparison + foreach ($interchange->directives as $i => $directive) { + $id = $directive->id->toString(); + if ($i != $id) $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'"); + $this->validateDirective($directive); + } + return true; + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object. + */ + public function validateId($id) { + $id_string = $id->toString(); + $this->context[] = "id '$id_string'"; + if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) { + // handled by InterchangeBuilder + $this->error(false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id'); + } + // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.) + // we probably should check that it has at least one namespace + $this->with($id, 'key') + ->assertNotEmpty() + ->assertIsString(); // implicit assertIsString handled by InterchangeBuilder + array_pop($this->context); + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object. + */ + public function validateDirective($d) { + $id = $d->id->toString(); + $this->context[] = "directive '$id'"; + $this->validateId($d->id); + + $this->with($d, 'description') + ->assertNotEmpty(); + + // BEGIN - handled by InterchangeBuilder + $this->with($d, 'type') + ->assertNotEmpty(); + $this->with($d, 'typeAllowsNull') + ->assertIsBool(); + try { + // This also tests validity of $d->type + $this->parser->parse($d->default, $d->type, $d->typeAllowsNull); + } catch (HTMLPurifier_VarParserException $e) { + $this->error('default', 'had error: ' . $e->getMessage()); + } + // END - handled by InterchangeBuilder + + if (!is_null($d->allowed) || !empty($d->valueAliases)) { + // allowed and valueAliases require that we be dealing with + // strings, so check for that early. + $d_int = HTMLPurifier_VarParser::$types[$d->type]; + if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) { + $this->error('type', 'must be a string type when used with allowed or value aliases'); + } + } + + $this->validateDirectiveAllowed($d); + $this->validateDirectiveValueAliases($d); + $this->validateDirectiveAliases($d); + + array_pop($this->context); + } + + /** + * Extra validation if $allowed member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + */ + public function validateDirectiveAllowed($d) { + if (is_null($d->allowed)) return; + $this->with($d, 'allowed') + ->assertNotEmpty() + ->assertIsLookup(); // handled by InterchangeBuilder + if (is_string($d->default) && !isset($d->allowed[$d->default])) { + $this->error('default', 'must be an allowed value'); + } + $this->context[] = 'allowed'; + foreach ($d->allowed as $val => $x) { + if (!is_string($val)) $this->error("value $val", 'must be a string'); + } + array_pop($this->context); + } + + /** + * Extra validation if $valueAliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + */ + public function validateDirectiveValueAliases($d) { + if (is_null($d->valueAliases)) return; + $this->with($d, 'valueAliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'valueAliases'; + foreach ($d->valueAliases as $alias => $real) { + if (!is_string($alias)) $this->error("alias $alias", 'must be a string'); + if (!is_string($real)) $this->error("alias target $real from alias '$alias'", 'must be a string'); + if ($alias === $real) { + $this->error("alias '$alias'", "must not be an alias to itself"); + } + } + if (!is_null($d->allowed)) { + foreach ($d->valueAliases as $alias => $real) { + if (isset($d->allowed[$alias])) { + $this->error("alias '$alias'", 'must not be an allowed value'); + } elseif (!isset($d->allowed[$real])) { + $this->error("alias '$alias'", 'must be an alias to an allowed value'); + } + } + } + array_pop($this->context); + } + + /** + * Extra validation if $aliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + */ + public function validateDirectiveAliases($d) { + $this->with($d, 'aliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'aliases'; + foreach ($d->aliases as $alias) { + $this->validateId($alias); + $s = $alias->toString(); + if (isset($this->interchange->directives[$s])) { + $this->error("alias '$s'", 'collides with another directive'); + } + if (isset($this->aliases[$s])) { + $other_directive = $this->aliases[$s]; + $this->error("alias '$s'", "collides with alias for directive '$other_directive'"); + } + $this->aliases[$s] = $d->id->toString(); + } + array_pop($this->context); + } + + // protected helper functions + + /** + * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom + * for validating simple member variables of objects. + */ + protected function with($obj, $member) { + return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member); + } + + /** + * Emits an error, providing helpful context. + */ + protected function error($target, $msg) { + if ($target !== false) $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext(); + else $prefix = ucfirst($this->getFormattedContext()); + throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg)); + } + + /** + * Returns a formatted context string. + */ + protected function getFormattedContext() { + return implode(' in ', array_reverse($this->context)); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/ValidatorAtom.php new file mode 100644 index 0000000000..b95aea18cc --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/ValidatorAtom.php @@ -0,0 +1,66 @@ +context = $context; + $this->obj = $obj; + $this->member = $member; + $this->contents =& $obj->$member; + } + + public function assertIsString() { + if (!is_string($this->contents)) $this->error('must be a string'); + return $this; + } + + public function assertIsBool() { + if (!is_bool($this->contents)) $this->error('must be a boolean'); + return $this; + } + + public function assertIsArray() { + if (!is_array($this->contents)) $this->error('must be an array'); + return $this; + } + + public function assertNotNull() { + if ($this->contents === null) $this->error('must not be null'); + return $this; + } + + public function assertAlnum() { + $this->assertIsString(); + if (!ctype_alnum($this->contents)) $this->error('must be alphanumeric'); + return $this; + } + + public function assertNotEmpty() { + if (empty($this->contents)) $this->error('must not be empty'); + return $this; + } + + public function assertIsLookup() { + $this->assertIsArray(); + foreach ($this->contents as $v) { + if ($v !== true) $this->error('must be a lookup array'); + } + return $this; + } + + protected function error($msg) { + throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema.ser b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema.ser new file mode 100644 index 0000000000000000000000000000000000000000..bbf12f9c3e7392aa8143727d2485f6f9ad1f97e1 GIT binary patch literal 12999 zcmeHO+in}l5#3KQw8%>U6QX2iW%@~`L@W{AAkxU@X)z>QRL8>^W-hX{hW|b1RCo0> zheOKykN^Q_V_|8ky1KgV-Bo)#IC(!f`gMAJbypYm!J6XtVV*tM{%ebnvYl zoDGf^<{_!msyzCb3_hIkWBPfc+jo$_-Z6=Llal@};8O$yOR`dS{al*i#rgEy?|tlH7mnxgDp{KIv}$pt(CjHm z?Lv@_z&RH4pOar&L?Sey1@2D=M`QQ-jpZI(7o_6JPt9|6VGDwQo>uY`R|@x+Su#t_ z_~Pi}Y;eq7`yMdLi;wrGNDrIDhG3`r0Vg6Z9#!24`58RlbV&qsANX zg)P@<@^WRfFQ4znfd(0AkO;L8FA6=S@EWMvt;gzJS6<#f{{{94u~KF`mnh+P zo5#C1tNh7auGZB{&;5KeE7!ft=eb!|HqXQrPUs1cd9@&wKKH^eB8~n>Sa^%sZkoz~ zD6e5NLRJi_XgHZTmm9Cvc~K=9)bFf^?i8TY!p^@0q0z7c$Sm%Pd~J%#s=HEa1jA@; zW_h}M18=i(qCTWY;C1pmUM;Uow&VfJ0Y3Lnj*r)3L%KI97uHls(d-SE8YYM*5qa<~ zmemJrVhRfv{KJTEoCNIV`(45vC9Xic!@MxP^X0NIWoe&G`ZBW5S0V(;UqnQVVVQh=EdL5%h$YEh$bNds1j#dB}JZRJRpSf^Vu=~cylTY)a<^GM*1B~ z@*>Hc`*X=?bpGBg0qDgrIyS4gj=w=wc?#|oa(2v}_!}0j>tdZopkn|%;zK=uEN!C8 zNNzOZZy@;f(N5ekQd94Rn7V*rac2@)u6`sD0^i-yPi>(7F46Br{cQlqEQZk%Q_ zEUgd+>Xpf=X^z~peb8?lb38h&MH$NDbW5Ilo>Mx z|1z8B3!5#;2)M7Shqq_^nc>ADl=Eb5d`=iX+H_G+x<0n6>0ZWI(_|Tp^8^_+qH~jH z=ab=hJbXluor9-<$Rs0(zev)qUfCc-94j>;W? zG|1b?rZ{k~ojy*%mgu_trHK*#ldvQxWwiDZBS z>?EqXrT{(CKl6H8&qVTKOb{~5Ev=fGuoi!1abRb4rSX|TF@`r97lFYXV(4|gsMD|% z(sV%9YBwmudQG|HgCcxPP(+UZKsrZqpkYIPYxx%jB?#19pq?N=ek%vqd{Pzlys8Ut zUlMXy_^8s!-wP8?^bHcalG4SeO~?fX|J(J|Fkh`;`H=)12916nSe&qHDa{>W-yJ~e z5yXZH{5aV&_X(^?ek{mDu)3@P#d%Rxxj~MVuaFBRTzr(cPTRz4RH`_EvCYJbq>QXf z?La+314WpGHz_d}7Ks}`Rar+urgh4~N%DXKXU447R1g7jJNp;HV*u%HP_~Ues}SfV z=L=8@?CUOsTp1*4@&&e5W?^g8gkTcBB-;_iMT}^Dpj<#{5s&H%zj3LW*a=j1TUYD4 zLgHUB9JWJ?w<2)m@ovo56oKEX8m##56I4~ySvWZi#DmDEtA1nP)Ra{ZpXcT#AJ6j) z3TUbg)V1pCa;KtSCJ@6n@sh`?f`>WQzyW`iD9=1aQ6-3jxgx-m9~yKVB+E8`HDCQ= zm^|dctv@BDo)E|27k@Ev%uov;r5wT5? zF|YcB=vl-ifU6XIZ_2!eEafP2DT2ZyGFxy@=GUATA#q#JE5CHyk?0zvcb$AO=d&_T z5oeVr&+&CF^_<24!RDu}y%|^nbYkX(sZdlpHdq!Ac8hYPunSy4<(?d@fLdp4f}Jni zP4&)Q=5Dty<-TCYO$mo|mvS8Pr@#KRNGcRvhdcSgoQeH# zC*QbjAMWH&`aE&ClZT>@6_{K@e1+!Ax7OGA8pp!$a3@FYdbpFzWBB1t?mg&mCqLZD zd1wDWzmp@Z;cmV5?`n+pI1s+f*~Vgez`Y&SmCYXTIFsNduFvhi88Zf! zFpKDW&}LKI4v5p)65j=q7M-jDdqTO@4#&p7aAUln2-v^2idG?q}u^c9NtbHfH-`~>f!+;zVOMWlbZCuY4|wY?PE5)qxO6wm#7o2{T0s|ULYf2 zyE*SEkcVa$-*zX5lzXe+y{kFz7(Ru*8&c$T)oZQLZvKA7{ot6=^O!gPtSmmwnqTe zT>Z8iod&-x0#A4AUjq*j*e^uj@$brl|C*~dQv%IGohiUUwmdfQ(H<&LKH!zYN5@=2 zBzkh%nk(3b#&ZQQbf&`}X-<2IAtX9R=A1Jb)oH4oYy_ZJ+(3nie(J6kc&88inU1)a z17fBy*>uG1;Do`Ac0wWTxOMw8s<1b(TqoRPAc;hDx;o)r?uyv%g!@3Oj5cj<7kaun z+%yGEhO&8Qmm64;Qql4dr0qtxKLWjiqHqZ9Zj>j}(d%}xcz;W}>2$lz7-n`hr5of| z%m=2olStHD?=~T%1-ID6addN9?fL%=8&J#cGx(Oj_jx+yPF#=rio||ow{CI4I`)g} zzs8tu}*1RILAKbZ9ZX6%ksWZ)^UDFpnT(sVFxZ>?Q2Cf!>RhAB5 z07a^Im`nUh)HLip0?YpxAq+|=0XV6H^A6CO#PIwfcL~boB!-V!2(AKTSc!=11;D{J z2OO|9Ls}?@qil(CSfS9ZEN-BF%t3;^iYAOXwDc<@!cb~l$#bqxO8MV2WH4=D<8)Dd z|DHDh75tlbz2p9yDF*3EnLl)GV&UB%+hH`*2NJ5mn>;zZ>GzIzu5K_kS3_S4>N^&B zr`SKh;qr=d&91+j(~Ye`6r!4J4{y8`nIdqA#1SlIbfcx=j#8>?Xu}%~d_stEoI{5; zJV^J^gSXs(J}W~TK3zhKLW$q~$VN-quV35VQLP}9<(#buqYbHDK8ArHs8pvw0>Yz_ zi9_j%^J=H3A}=}{;@MP-oa$tVKbCr^e}!tkN+R}OyAA};)H`5{Mt2l~!|We6aa)IS zXvav(epX%|Y3XE+hSHvJQAdYNw}xE2lwhwNLoObObs|FQLg!!hGtY?AL9d%*;C9T= z_`M-(PEq(bl`uWwOu+-)l#8Ac-qF!L1ES-BLk#im-G%Mw1+^qXQgGs5t(3Q;P7m;GT?|o@vRUH9+Gk)9&#Z ex0z?zkIyJIzlD6=+JDysjbHrQ5DoYJ{{26FNH2{5 literal 0 HcmV?d00001 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt new file mode 100644 index 0000000000..0517fed0a1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt @@ -0,0 +1,8 @@ +Attr.AllowedClasses +TYPE: lookup/null +VERSION: 4.0.0 +DEFAULT: null +--DESCRIPTION-- +List of allowed class values in the class attribute. By default, this is null, +which means all classes are allowed. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt new file mode 100644 index 0000000000..249edd647b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt @@ -0,0 +1,12 @@ +Attr.AllowedFrameTargets +TYPE: lookup +DEFAULT: array() +--DESCRIPTION-- +Lookup table of all allowed link frame targets. Some commonly used link +targets include _blank, _self, _parent and _top. Values should be +lowercase, as validation will be done in a case-sensitive manner despite +W3C's recommendation. XHTML 1.0 Strict does not permit the target attribute +so this directive will have no effect in that doctype. XHTML 1.1 does not +enable the Target module by default, you will have to manually enable it +(see the module documentation for more details.) +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt new file mode 100644 index 0000000000..9a8fa6a2e2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt @@ -0,0 +1,9 @@ +Attr.AllowedRel +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed forward document relationships in the rel attribute. Common +values may be nofollow or print. By default, this is empty, meaning that no +document relationships are allowed. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt new file mode 100644 index 0000000000..b017883485 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt @@ -0,0 +1,9 @@ +Attr.AllowedRev +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed reverse document relationships in the rev attribute. This +attribute is a bit of an edge-case; if you don't know what it is for, stay +away. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt new file mode 100644 index 0000000000..e774b823b1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt @@ -0,0 +1,19 @@ +Attr.ClassUseCDATA +TYPE: bool/null +DEFAULT: null +VERSION: 4.0.0 +--DESCRIPTION-- +If null, class will auto-detect the doctype and, if matching XHTML 1.1 or +XHTML 2.0, will use the restrictive NMTOKENS specification of class. Otherwise, +it will use a relaxed CDATA definition. If true, the relaxed CDATA definition +is forced; if false, the NMTOKENS definition is forced. To get behavior +of HTML Purifier prior to 4.0.0, set this directive to false. + +Some rational behind the auto-detection: +in previous versions of HTML Purifier, it was assumed that the form of +class was NMTOKENS, as specified by the XHTML Modularization (representing +XHTML 1.1 and XHTML 2.0). The DTDs for HTML 4.01 and XHTML 1.0, however +specify class as CDATA. HTML 5 effectively defines it as CDATA, but +with the additional constraint that each name should be unique (this is not +explicitly outlined in previous specifications). +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt new file mode 100644 index 0000000000..533165e175 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt @@ -0,0 +1,11 @@ +Attr.DefaultImageAlt +TYPE: string/null +DEFAULT: null +VERSION: 3.2.0 +--DESCRIPTION-- +This is the content of the alt tag of an image if the user had not +previously specified an alt attribute. This applies to all images without +a valid alt attribute, as opposed to %Attr.DefaultInvalidImageAlt, which +only applies to invalid images, and overrides in the case of an invalid image. +Default behavior with null is to use the basename of the src tag for the alt. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt new file mode 100644 index 0000000000..9eb7e38469 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt @@ -0,0 +1,9 @@ +Attr.DefaultInvalidImage +TYPE: string +DEFAULT: '' +--DESCRIPTION-- +This is the default image an img tag will be pointed to if it does not have +a valid src attribute. In future versions, we may allow the image tag to +be removed completely, but due to design issues, this is not possible right +now. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt new file mode 100644 index 0000000000..2f17bf477a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt @@ -0,0 +1,8 @@ +Attr.DefaultInvalidImageAlt +TYPE: string +DEFAULT: 'Invalid image' +--DESCRIPTION-- +This is the content of the alt tag of an invalid image if the user had not +previously specified an alt attribute. It has no effect when the image is +valid but there was no alt attribute present. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt new file mode 100644 index 0000000000..52654b53ae --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt @@ -0,0 +1,10 @@ +Attr.DefaultTextDir +TYPE: string +DEFAULT: 'ltr' +--DESCRIPTION-- +Defines the default text direction (ltr or rtl) of the document being +parsed. This generally is the same as the value of the dir attribute in +HTML, or ltr if that is not specified. +--ALLOWED-- +'ltr', 'rtl' +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt new file mode 100644 index 0000000000..6440d21032 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt @@ -0,0 +1,16 @@ +Attr.EnableID +TYPE: bool +DEFAULT: false +VERSION: 1.2.0 +--DESCRIPTION-- +Allows the ID attribute in HTML. This is disabled by default due to the +fact that without proper configuration user input can easily break the +validation of a webpage by specifying an ID that is already on the +surrounding HTML. If you don't mind throwing caution to the wind, enable +this directive, but I strongly recommend you also consider blacklisting IDs +you use (%Attr.IDBlacklist) or prefixing all user supplied IDs +(%Attr.IDPrefix). When set to true HTML Purifier reverts to the behavior of +pre-1.2.0 versions. +--ALIASES-- +HTML.EnableAttrID +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt new file mode 100644 index 0000000000..f31d226f58 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt @@ -0,0 +1,8 @@ +Attr.ForbiddenClasses +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array() +--DESCRIPTION-- +List of forbidden class values in the class attribute. By default, this is +empty, which means that no classes are forbidden. See also %Attr.AllowedClasses. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt new file mode 100644 index 0000000000..5f2b5e3d2c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt @@ -0,0 +1,5 @@ +Attr.IDBlacklist +TYPE: list +DEFAULT: array() +DESCRIPTION: Array of IDs not allowed in the document. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt new file mode 100644 index 0000000000..6f5824586e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt @@ -0,0 +1,9 @@ +Attr.IDBlacklistRegexp +TYPE: string/null +VERSION: 1.6.0 +DEFAULT: NULL +--DESCRIPTION-- +PCRE regular expression to be matched against all IDs. If the expression is +matches, the ID is rejected. Use this with care: may cause significant +degradation. ID matching is done after all other validation. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt new file mode 100644 index 0000000000..cc49d43fd0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt @@ -0,0 +1,12 @@ +Attr.IDPrefix +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +String to prefix to IDs. If you have no idea what IDs your pages may use, +you may opt to simply add a prefix to all user-submitted ID attributes so +that they are still usable, but will not conflict with core page IDs. +Example: setting the directive to 'user_' will result in a user submitted +'foo' to become 'user_foo' Be sure to set %HTML.EnableAttrID to true +before using this. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt new file mode 100644 index 0000000000..2c5924a7ad --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt @@ -0,0 +1,14 @@ +Attr.IDPrefixLocal +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +Temporary prefix for IDs used in conjunction with %Attr.IDPrefix. If you +need to allow multiple sets of user content on web page, you may need to +have a seperate prefix that changes with each iteration. This way, +seperately submitted user content displayed on the same page doesn't +clobber each other. Ideal values are unique identifiers for the content it +represents (i.e. the id of the row in the database). Be sure to add a +seperator (like an underscore) at the end. Warning: this directive will +not work unless %Attr.IDPrefix is set to a non-empty value! +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt new file mode 100644 index 0000000000..d5caa1bb97 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt @@ -0,0 +1,31 @@ +AutoFormat.AutoParagraph +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on auto-paragraphing, where double newlines are + converted in to paragraphs whenever possible. Auto-paragraphing: +

+
    +
  • Always applies to inline elements or text in the root node,
  • +
  • Applies to inline elements or text with double newlines in nodes + that allow paragraph tags,
  • +
  • Applies to double newlines in paragraph tags
  • +
+

+ p tags must be allowed for this directive to take effect. + We do not use br tags for paragraphing, as that is + semantically incorrect. +

+

+ To prevent auto-paragraphing as a content-producer, refrain from using + double-newlines except to specify a new paragraph or in contexts where + it has special meaning (whitespace usually has no meaning except in + tags like pre, so this should not be difficult.) To prevent + the paragraphing of inline text adjacent to block elements, wrap them + in div tags (the behavior is slightly different outside of + the root node.) +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt new file mode 100644 index 0000000000..2a476481af --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt @@ -0,0 +1,12 @@ +AutoFormat.Custom +TYPE: list +VERSION: 2.0.1 +DEFAULT: array() +--DESCRIPTION-- + +

+ This directive can be used to add custom auto-format injectors. + Specify an array of injector names (class name minus the prefix) + or concrete implementations. Injector class must exist. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt new file mode 100644 index 0000000000..663064a344 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt @@ -0,0 +1,11 @@ +AutoFormat.DisplayLinkURI +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ This directive turns on the in-text display of URIs in <a> tags, and disables + those links. For example, example becomes + example (http://example.com). +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt new file mode 100644 index 0000000000..3a48ba960e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt @@ -0,0 +1,12 @@ +AutoFormat.Linkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on linkification, auto-linking http, ftp and + https URLs. a tags with the href attribute + must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt new file mode 100644 index 0000000000..db58b13464 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify.DocURL +TYPE: string +VERSION: 2.0.1 +DEFAULT: '#%s' +ALIASES: AutoFormatParam.PurifierLinkifyDocURL +--DESCRIPTION-- +

+ Location of configuration documentation to link to, let %s substitute + into the configuration's namespace and directive names sans the percent + sign. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt new file mode 100644 index 0000000000..7996488be0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ Internal auto-formatter that converts configuration directives in + syntax %Namespace.Directive to links. a tags + with the href attribute must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt new file mode 100644 index 0000000000..35c393b4e6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array('td' => true, 'th' => true) +--DESCRIPTION-- +

+ When %AutoFormat.RemoveEmpty and %AutoFormat.RemoveEmpty.RemoveNbsp + are enabled, this directive defines what HTML elements should not be + removede if they have only a non-breaking space in them. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt new file mode 100644 index 0000000000..ca17eb1dc4 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt @@ -0,0 +1,15 @@ +AutoFormat.RemoveEmpty.RemoveNbsp +TYPE: bool +VERSION: 4.0.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will treat any elements that contain only + non-breaking spaces as well as regular whitespace as empty, and remove + them when %AutoForamt.RemoveEmpty is enabled. +

+

+ See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements + that don't have this behavior applied to them. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt new file mode 100644 index 0000000000..34657ba47b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt @@ -0,0 +1,46 @@ +AutoFormat.RemoveEmpty +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will attempt to remove empty elements that + contribute no semantic information to the document. The following types + of nodes will be removed: +

+
  • + Tags with no attributes and no content, and that are not empty + elements (remove <a></a> but not + <br />), and +
  • +
  • + Tags with no content, except for:
      +
    • The colgroup element, or
    • +
    • + Elements with the id or name attribute, + when those attributes are permitted on those elements. +
    • +
  • +
+

+ Please be very careful when using this functionality; while it may not + seem that empty elements contain useful information, they can alter the + layout of a document given appropriate styling. This directive is most + useful when you are processing machine-generated HTML, please avoid using + it on regular user HTML. +

+

+ Elements that contain only whitespace will be treated as empty. Non-breaking + spaces, however, do not count as whitespace. See + %AutoFormat.RemoveEmpty.RemoveNbsp for alternate behavior. +

+

+ This algorithm is not perfect; you may still notice some empty tags, + particularly if a node had elements, but those elements were later removed + because they were not permitted in that context, or tags that, after + being auto-closed by another tag, where empty. This is for safety reasons + to prevent clever code from breaking validation. The general rule of thumb: + if a tag looked empty on the way in, it will get removed; if HTML Purifier + made it empty, it will stay. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt new file mode 100644 index 0000000000..b324608f76 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt @@ -0,0 +1,8 @@ +CSS.AllowImportant +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not !important cascade modifiers should +be allowed in user CSS. If false, !important will stripped. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt new file mode 100644 index 0000000000..748be0eec8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt @@ -0,0 +1,11 @@ +CSS.AllowTricky +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not to allow "tricky" CSS properties and +values. Tricky CSS properties/values can drastically modify page layout or +be used for deceptive practices but do not directly constitute a security risk. +For example, display:none; is considered a tricky property that +will only be allowed if this directive is set to true. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt new file mode 100644 index 0000000000..460112ebe0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt @@ -0,0 +1,18 @@ +CSS.AllowedProperties +TYPE: lookup/null +VERSION: 3.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's style attributes set is unsatisfactory for your needs, + you can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add an attribute that HTML Purifier never + supported in the first place. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt new file mode 100644 index 0000000000..5cb7dda3ba --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt @@ -0,0 +1,11 @@ +CSS.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt new file mode 100644 index 0000000000..7a3291470c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt @@ -0,0 +1,16 @@ +CSS.MaxImgLength +TYPE: string/null +DEFAULT: '1200px' +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This parameter sets the maximum allowed length on img tags, + effectively the width and height properties. + Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %HTML.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the CSS max is a number with + a unit). +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt new file mode 100644 index 0000000000..148eedb8be --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt @@ -0,0 +1,10 @@ +CSS.Proprietary +TYPE: bool +VERSION: 3.0.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Whether or not to allow safe, proprietary CSS values. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt new file mode 100644 index 0000000000..c486724c88 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt @@ -0,0 +1,14 @@ +Cache.DefinitionImpl +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: 'Serializer' +--DESCRIPTION-- + +This directive defines which method to use when caching definitions, +the complex data-type that makes HTML Purifier tick. Set to null +to disable caching (not recommended, as you will see a definite +performance degradation). + +--ALIASES-- +Core.DefinitionCache +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt new file mode 100644 index 0000000000..54036507d6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt @@ -0,0 +1,13 @@ +Cache.SerializerPath +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Absolute path with no trailing slash to store serialized definitions in. + Default is within the + HTML Purifier library inside DefinitionCache/Serializer. This + path must be writable by the webserver. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt new file mode 100644 index 0000000000..568cbf3b32 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt @@ -0,0 +1,18 @@ +Core.AggressivelyFixLt +TYPE: bool +VERSION: 2.1.0 +DEFAULT: true +--DESCRIPTION-- +

+ This directive enables aggressive pre-filter fixes HTML Purifier can + perform in order to ensure that open angled-brackets do not get killed + during parsing stage. Enabling this will result in two preg_replace_callback + calls and at least two preg_replace calls for every HTML document parsed; + if your users make very well-formed HTML, you can set this directive false. + This has no effect when DirectLex is used. +

+

+ Notice: This directive's default turned from false to true + in HTML Purifier 3.2.0. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt new file mode 100644 index 0000000000..d7317911fa --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt @@ -0,0 +1,12 @@ +Core.CollectErrors +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- + +Whether or not to collect errors found while filtering the document. This +is a useful way to give feedback to your users. Warning: +Currently this feature is very patchy and experimental, with lots of +possible error messages not yet implemented. It will not cause any +problems, but it may not help your users either. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt new file mode 100644 index 0000000000..08b381d34c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt @@ -0,0 +1,28 @@ +Core.ColorKeywords +TYPE: hash +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'maroon' => '#800000', + 'red' => '#FF0000', + 'orange' => '#FFA500', + 'yellow' => '#FFFF00', + 'olive' => '#808000', + 'purple' => '#800080', + 'fuchsia' => '#FF00FF', + 'white' => '#FFFFFF', + 'lime' => '#00FF00', + 'green' => '#008000', + 'navy' => '#000080', + 'blue' => '#0000FF', + 'aqua' => '#00FFFF', + 'teal' => '#008080', + 'black' => '#000000', + 'silver' => '#C0C0C0', + 'gray' => '#808080', +) +--DESCRIPTION-- + +Lookup array of color names to six digit hexadecimal number corresponding +to color, with preceding hash mark. Used when parsing colors. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt new file mode 100644 index 0000000000..64b114fce2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt @@ -0,0 +1,14 @@ +Core.ConvertDocumentToFragment +TYPE: bool +DEFAULT: true +--DESCRIPTION-- + +This parameter determines whether or not the filter should convert +input that is a full document with html and body tags to a fragment +of just the contents of a body tag. This parameter is simply something +HTML Purifier can do during an edge-case: for most inputs, this +processing is not necessary. + +--ALIASES-- +Core.AcceptFullDocuments +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt new file mode 100644 index 0000000000..36f16e07ea --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt @@ -0,0 +1,17 @@ +Core.DirectLexLineNumberSyncInterval +TYPE: int +VERSION: 2.0.0 +DEFAULT: 0 +--DESCRIPTION-- + +

+ Specifies the number of tokens the DirectLex line number tracking + implementations should process before attempting to resyncronize the + current line count by manually counting all previous new-lines. When + at 0, this functionality is disabled. Lower values will decrease + performance, and this is only strictly necessary if the counting + algorithm is buggy (in which case you should report it as a bug). + This has no effect when %Core.MaintainLineNumbers is disabled or DirectLex is + not being used. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt new file mode 100644 index 0000000000..8bfb47c3ac --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt @@ -0,0 +1,15 @@ +Core.Encoding +TYPE: istring +DEFAULT: 'utf-8' +--DESCRIPTION-- +If for some reason you are unable to convert all webpages to UTF-8, you can +use this directive as a stop-gap compatibility change to let HTML Purifier +deal with non UTF-8 input. This technique has notable deficiencies: +absolutely no characters outside of the selected character encoding will be +preserved, not even the ones that have been ampersand escaped (this is due +to a UTF-8 specific feature that automatically resolves all +entities), making it pretty useless for anything except the most I18N-blind +applications, although %Core.EscapeNonASCIICharacters offers fixes this +trouble with another tradeoff. This directive only accepts ISO-8859-1 if +iconv is not enabled. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt new file mode 100644 index 0000000000..4d5b5055cd --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt @@ -0,0 +1,10 @@ +Core.EscapeInvalidChildren +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, a child is found that is not allowed in the context of the +parent element will be transformed into text as if it were ASCII. When +false, that element and all internal tags will be dropped, though text will +be preserved. There is no option for dropping the element but preserving +child nodes. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt new file mode 100644 index 0000000000..a7a5b249bb --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt @@ -0,0 +1,7 @@ +Core.EscapeInvalidTags +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, invalid tags will be written back to the document as plain text. +Otherwise, they are silently dropped. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt new file mode 100644 index 0000000000..abb499948a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt @@ -0,0 +1,13 @@ +Core.EscapeNonASCIICharacters +TYPE: bool +VERSION: 1.4.0 +DEFAULT: false +--DESCRIPTION-- +This directive overcomes a deficiency in %Core.Encoding by blindly +converting all non-ASCII characters into decimal numeric entities before +converting it to its native encoding. This means that even characters that +can be expressed in the non-UTF-8 encoding will be entity-ized, which can +be a real downer for encodings like Big5. It also assumes that the ASCII +repetoire is available, although this is the case for almost all encodings. +Anyway, use UTF-8! +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt new file mode 100644 index 0000000000..915391edb7 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt @@ -0,0 +1,19 @@ +Core.HiddenElements +TYPE: lookup +--DEFAULT-- +array ( + 'script' => true, + 'style' => true, +) +--DESCRIPTION-- + +

+ This directive is a lookup array of elements which should have their + contents removed when they are not allowed by the HTML definition. + For example, the contents of a script tag are not + normally shown in a document, so if script tags are to be removed, + their contents should be removed to. This is opposed to a b + tag, which defines some presentational changes but does not hide its + contents. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Language.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Language.txt new file mode 100644 index 0000000000..233fca14f8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.Language.txt @@ -0,0 +1,10 @@ +Core.Language +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'en' +--DESCRIPTION-- + +ISO 639 language code for localizable things in HTML Purifier to use, +which is mainly error reporting. There is currently only an English (en) +translation, so this directive is currently useless. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt new file mode 100644 index 0000000000..8983e2cca9 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt @@ -0,0 +1,34 @@ +Core.LexerImpl +TYPE: mixed/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This parameter determines what lexer implementation can be used. The + valid values are: +

+
+
null
+
+ Recommended, the lexer implementation will be auto-detected based on + your PHP-version and configuration. +
+
string lexer identifier
+
+ This is a slim way of manually overridding the implementation. + Currently recognized values are: DOMLex (the default PHP5 +implementation) + and DirectLex (the default PHP4 implementation). Only use this if + you know what you are doing: usually, the auto-detection will + manage things for cases you aren't even aware of. +
+
object lexer instance
+
+ Super-advanced: you can specify your own, custom, implementation that + implements the interface defined by HTMLPurifier_Lexer. + I may remove this option simply because I don't expect anyone + to use it. +
+
+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt new file mode 100644 index 0000000000..eb841a7597 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt @@ -0,0 +1,16 @@ +Core.MaintainLineNumbers +TYPE: bool/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If true, HTML Purifier will add line number information to all tokens. + This is useful when error reporting is turned on, but can result in + significant performance degradation and should not be used when + unnecessary. This directive must be used with the DirectLex lexer, + as the DOMLex lexer does not (yet) support this functionality. + If the value is null, an appropriate value will be selected based + on other configuration. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt new file mode 100644 index 0000000000..4070c2a0de --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt @@ -0,0 +1,12 @@ +Core.RemoveInvalidImg +TYPE: bool +DEFAULT: true +VERSION: 1.3.0 +--DESCRIPTION-- + +

+ This directive enables pre-emptive URI checking in img + tags, as the attribute validation strategy is not authorized to + remove elements from the document. Revert to pre-1.3.0 behavior by setting to false. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt new file mode 100644 index 0000000000..a4cd966df8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt @@ -0,0 +1,12 @@ +Core.RemoveScriptContents +TYPE: bool/null +DEFAULT: NULL +VERSION: 2.0.0 +DEPRECATED-VERSION: 2.1.0 +DEPRECATED-USE: Core.HiddenElements +--DESCRIPTION-- +

+ This directive enables HTML Purifier to remove not only script tags + but all of their contents. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt new file mode 100644 index 0000000000..3db50ef204 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt @@ -0,0 +1,11 @@ +Filter.Custom +TYPE: list +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This directive can be used to add custom filters; it is nearly the + equivalent of the now deprecated HTMLPurifier->addFilter() + method. Specify an array of concrete implementations. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt new file mode 100644 index 0000000000..16829bcda0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt @@ -0,0 +1,14 @@ +Filter.ExtractStyleBlocks.Escaping +TYPE: bool +VERSION: 3.0.0 +DEFAULT: true +ALIASES: Filter.ExtractStyleBlocksEscaping, FilterParam.ExtractStyleBlocksEscaping +--DESCRIPTION-- + +

+ Whether or not to escape the dangerous characters <, > and & + as \3C, \3E and \26, respectively. This is can be safely set to false + if the contents of StyleBlocks will be placed in an external stylesheet, + where there is no risk of it being interpreted as HTML. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt new file mode 100644 index 0000000000..7f95f54d12 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt @@ -0,0 +1,29 @@ +Filter.ExtractStyleBlocks.Scope +TYPE: string/null +VERSION: 3.0.0 +DEFAULT: NULL +ALIASES: Filter.ExtractStyleBlocksScope, FilterParam.ExtractStyleBlocksScope +--DESCRIPTION-- + +

+ If you would like users to be able to define external stylesheets, but + only allow them to specify CSS declarations for a specific node and + prevent them from fiddling with other elements, use this directive. + It accepts any valid CSS selector, and will prepend this to any + CSS declaration extracted from the document. For example, if this + directive is set to #user-content and a user uses the + selector a:hover, the final selector will be + #user-content a:hover. +

+

+ The comma shorthand may be used; consider the above example, with + #user-content, #user-content2, the final selector will + be #user-content a:hover, #user-content2 a:hover. +

+

+ Warning: It is possible for users to bypass this measure + using a naughty + selector. This is a bug in CSS Tidy 1.3, not HTML + Purifier, and I am working to get it fixed. Until then, HTML Purifier + performs a basic check to prevent this. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt new file mode 100644 index 0000000000..6c231b2d7f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt @@ -0,0 +1,16 @@ +Filter.ExtractStyleBlocks.TidyImpl +TYPE: mixed/null +VERSION: 3.1.0 +DEFAULT: NULL +ALIASES: FilterParam.ExtractStyleBlocksTidyImpl +--DESCRIPTION-- +

+ If left NULL, HTML Purifier will attempt to instantiate a csstidy + class to use for internal cleaning. This will usually be good enough. +

+

+ However, for trusted user input, you can set this to false to + disable cleaning. In addition, you can supply your own concrete implementation + of Tidy's interface to use, although I don't know why you'd want to do that. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt new file mode 100644 index 0000000000..078d087417 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt @@ -0,0 +1,74 @@ +Filter.ExtractStyleBlocks +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +EXTERNAL: CSSTidy +--DESCRIPTION-- +

+ This directive turns on the style block extraction filter, which removes + style blocks from input HTML, cleans them up with CSSTidy, + and places them in the StyleBlocks context variable, for further + use by you, usually to be placed in an external stylesheet, or a + style block in the head of your document. +

+

+ Sample usage: +

+
';
+?>
+
+
+
+  Filter.ExtractStyleBlocks
+body {color:#F00;} Some text';
+
+    $config = HTMLPurifier_Config::createDefault();
+    $config->set('Filter', 'ExtractStyleBlocks', true);
+    $purifier = new HTMLPurifier($config);
+
+    $html = $purifier->purify($dirty);
+
+    // This implementation writes the stylesheets to the styles/ directory.
+    // You can also echo the styles inside the document, but it's a bit
+    // more difficult to make sure they get interpreted properly by
+    // browsers; try the usual CSS armoring techniques.
+    $styles = $purifier->context->get('StyleBlocks');
+    $dir = 'styles/';
+    if (!is_dir($dir)) mkdir($dir);
+    $hash = sha1($_GET['html']);
+    foreach ($styles as $i => $style) {
+        file_put_contents($name = $dir . $hash . "_$i");
+        echo '';
+    }
+?>
+
+
+  
+ +
+ + +]]>
+

+ Warning: It is possible for a user to mount an + imagecrash attack using this CSS. Counter-measures are difficult; + it is not simply enough to limit the range of CSS lengths (using + relative lengths with many nesting levels allows for large values + to be attained without actually specifying them in the stylesheet), + and the flexible nature of selectors makes it difficult to selectively + disable lengths on image tags (HTML Purifier, however, does disable + CSS width and height in inline styling). There are probably two effective + counter measures: an explicit width and height set to auto in all + images in your document (unlikely) or the disabling of width and + height (somewhat reasonable). Whether or not these measures should be + used is left to the reader. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt new file mode 100644 index 0000000000..7fa6536b2c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt @@ -0,0 +1,11 @@ +Filter.YouTube +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ This directive enables YouTube video embedding in HTML Purifier. Check + this document + on embedding videos for more information on what this filter does. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt new file mode 100644 index 0000000000..3e231d2d16 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt @@ -0,0 +1,22 @@ +HTML.Allowed +TYPE: itext/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This is a convenience directive that rolls the functionality of + %HTML.AllowedElements and %HTML.AllowedAttributes into one directive. + Specify elements and attributes that are allowed using: + element1[attr1|attr2],element2.... You can also use + newlines instead of commas to separate elements. +

+

+ Warning: + All of the constraints on the component directives are still enforced. + The syntax is a subset of TinyMCE's valid_elements + whitelist: directly copy-pasting it here will probably result in + broken whitelists. If %HTML.AllowedElements or %HTML.AllowedAttributes + are set, this directive has no effect. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt new file mode 100644 index 0000000000..fcf093f17d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt @@ -0,0 +1,19 @@ +HTML.AllowedAttributes +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's attribute set is unsatisfactory, overload it! + The syntax is "tag.attr" or "*.attr" for the global attributes + (style, id, class, dir, lang, xml:lang). +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. For + example, %HTML.EnableAttrID will take precedence over *.id in this + directive. You must set that directive to true before you can use + IDs at all. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt new file mode 100644 index 0000000000..888d558196 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt @@ -0,0 +1,18 @@ +HTML.AllowedElements +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ If HTML Purifier's tag set is unsatisfactory for your needs, you + can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add a tag that HTML Purifier never + supported in the first place (like embed, form or head). If you + change this, you probably also want to change %HTML.AllowedAttributes. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt new file mode 100644 index 0000000000..5a59a55c08 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt @@ -0,0 +1,20 @@ +HTML.AllowedModules +TYPE: lookup/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ A doctype comes with a set of usual modules to use. Without having + to mucking about with the doctypes, you can quickly activate or + disable these modules by specifying which modules you wish to allow + with this directive. This is most useful for unit testing specific + modules, although end users may find it useful for their own ends. +

+

+ If you specify a module that does not exist, the manager will silently + fail to use it, so be careful! User-defined modules are not affected + by this directive. Modules defined in %HTML.CoreModules are not + affected by this directive. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt new file mode 100644 index 0000000000..151fb7b826 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt @@ -0,0 +1,11 @@ +HTML.Attr.Name.UseCDATA +TYPE: bool +DEFAULT: false +VERSION: 4.0.0 +--DESCRIPTION-- +The W3C specification DTD defines the name attribute to be CDATA, not ID, due +to limitations of DTD. In certain documents, this relaxed behavior is desired, +whether it is to specify duplicate names, or to specify names that would be +illegal IDs (for example, names that begin with a digit.) Set this configuration +directive to true to use the relaxed parsing rules. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt new file mode 100644 index 0000000000..45ae469ec9 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt @@ -0,0 +1,18 @@ +HTML.BlockWrapper +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'p' +--DESCRIPTION-- + +

+ String name of element to wrap inline elements that are inside a block + context. This only occurs in the children of blockquote in strict mode. +

+

+ Example: by default value, + <blockquote>Foo</blockquote> would become + <blockquote><p>Foo</p></blockquote>. + The <p> tags can be replaced with whatever you desire, + as long as it is a block level element. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt new file mode 100644 index 0000000000..5246188795 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt @@ -0,0 +1,23 @@ +HTML.CoreModules +TYPE: lookup +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'Structure' => true, + 'Text' => true, + 'Hypertext' => true, + 'List' => true, + 'NonXMLCommonAttributes' => true, + 'XMLCommonAttributes' => true, + 'CommonAttributes' => true, +) +--DESCRIPTION-- + +

+ Certain modularized doctypes (XHTML, namely), have certain modules + that must be included for the doctype to be an conforming document + type: put those modules here. By default, XHTML's core modules + are used. You can set this to a blank array to disable core module + protection, but this is not recommended. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt new file mode 100644 index 0000000000..a64e3d7c36 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt @@ -0,0 +1,9 @@ +HTML.CustomDoctype +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +A custom doctype for power-users who defined there own document +type. This directive only applies when %HTML.Doctype is blank. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt new file mode 100644 index 0000000000..103db754a2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt @@ -0,0 +1,33 @@ +HTML.DefinitionID +TYPE: string/null +DEFAULT: NULL +VERSION: 2.0.0 +--DESCRIPTION-- + +

+ Unique identifier for a custom-built HTML definition. If you edit + the raw version of the HTMLDefinition, introducing changes that the + configuration object does not reflect, you must specify this variable. + If you change your custom edits, you should change this directive, or + clear your cache. Example: +

+
+$config = HTMLPurifier_Config::createDefault();
+$config->set('HTML', 'DefinitionID', '1');
+$def = $config->getHTMLDefinition();
+$def->addAttribute('a', 'tabindex', 'Number');
+
+

+ In the above example, the configuration is still at the defaults, but + using the advanced API, an extra attribute has been added. The + configuration object normally has no way of knowing that this change + has taken place, so it needs an extra directive: %HTML.DefinitionID. + If someone else attempts to use the default configuration, these two + pieces of code will not clobber each other in the cache, since one has + an extra directive attached to it. +

+

+ You must specify a value to this directive to use the + advanced API features. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt new file mode 100644 index 0000000000..229ae0267a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt @@ -0,0 +1,16 @@ +HTML.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition specified in + %HTML.DefinitionID. This serves the same purpose: uniquely identifying + your custom definition, but this one does so in a chronological + context: revision 3 is more up-to-date then revision 2. Thus, when + this gets incremented, the cache handling is smart enough to clean + up any older revisions of your definition as well as flush the + cache. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt new file mode 100644 index 0000000000..9dab497f2f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt @@ -0,0 +1,11 @@ +HTML.Doctype +TYPE: string/null +DEFAULT: NULL +--DESCRIPTION-- +Doctype to use during filtering. Technically speaking this is not actually +a doctype (as it does not identify a corresponding DTD), but we are using +this name for sake of simplicity. When non-blank, this will override any +older directives like %HTML.XHTML or %HTML.Strict. +--ALLOWED-- +'HTML 4.01 Transitional', 'HTML 4.01 Strict', 'XHTML 1.0 Transitional', 'XHTML 1.0 Strict', 'XHTML 1.1' +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt new file mode 100644 index 0000000000..57358f9bad --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt @@ -0,0 +1,21 @@ +HTML.ForbiddenAttributes +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ While this directive is similar to %HTML.AllowedAttributes, for + forwards-compatibility with XML, this attribute has a different syntax. Instead of + tag.attr, use tag@attr. To disallow href + attributes in a tags, set this directive to + a@href. You can also disallow an attribute globally with + attr or *@attr (either syntax is fine; the latter + is provided for consistency with %HTML.AllowedAttributes). +

+

+ Warning: This directive complements %HTML.ForbiddenElements, + accordingly, check + out that directive for a discussion of why you + should think twice before using this directive. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt new file mode 100644 index 0000000000..93a53e14fb --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt @@ -0,0 +1,20 @@ +HTML.ForbiddenElements +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This was, perhaps, the most requested feature ever in HTML + Purifier. Please don't abuse it! This is the logical inverse of + %HTML.AllowedElements, and it will override that directive, or any + other directive. +

+

+ If possible, %HTML.Allowed is recommended over this directive, because it + can sometimes be difficult to tell whether or not you've forbidden all of + the behavior you would like to disallow. If you forbid img + with the expectation of preventing images on your site, you'll be in for + a nasty surprise when people start using the background-image + CSS property. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt new file mode 100644 index 0000000000..e424c386ec --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt @@ -0,0 +1,14 @@ +HTML.MaxImgLength +TYPE: int/null +DEFAULT: 1200 +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This directive controls the maximum number of pixels in the width and + height attributes in img tags. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %CSS.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the HTML max is an integer). +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt new file mode 100644 index 0000000000..62e8e160c7 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt @@ -0,0 +1,12 @@ +HTML.Parent +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'div' +--DESCRIPTION-- + +

+ String name of element that HTML fragment passed to library will be + inserted in. An interesting variation would be using span as the + parent element, meaning that only inline tags would be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt new file mode 100644 index 0000000000..dfb720496d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt @@ -0,0 +1,12 @@ +HTML.Proprietary +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to allow proprietary elements and attributes in your + documents, as per HTMLPurifier_HTMLModule_Proprietary. + Warning: This can cause your documents to stop + validating! +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt new file mode 100644 index 0000000000..f635a68548 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt @@ -0,0 +1,14 @@ +HTML.SafeEmbed +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit embed tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to embed tags. Embed is a proprietary + element and will cause your website to stop validating. You probably want + to enable this with %HTML.SafeObject. + Highly experimental. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt new file mode 100644 index 0000000000..32967b88fb --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt @@ -0,0 +1,14 @@ +HTML.SafeObject +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit object tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to object tags. You may also want to + enable %HTML.SafeEmbed for maximum interoperability with Internet Explorer, + although embed tags will cause your website to stop validating. + Highly experimental. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt new file mode 100644 index 0000000000..a8b1de56be --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt @@ -0,0 +1,9 @@ +HTML.Strict +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not to use Transitional (loose) or Strict rulesets. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt new file mode 100644 index 0000000000..b4c271b7fa --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt @@ -0,0 +1,8 @@ +HTML.TidyAdd +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to add to the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt new file mode 100644 index 0000000000..4186ccd0d1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt @@ -0,0 +1,24 @@ +HTML.TidyLevel +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'medium' +--DESCRIPTION-- + +

General level of cleanliness the Tidy module should enforce. +There are four allowed values:

+
+
none
+
No extra tidying should be done
+
light
+
Only fix elements that would be discarded otherwise due to + lack of support in doctype
+
medium
+
Enforce best practices
+
heavy
+
Transform all deprecated elements and attributes to standards + compliant equivalents
+
+ +--ALLOWED-- +'none', 'light', 'medium', 'heavy' +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt new file mode 100644 index 0000000000..996762bd1d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt @@ -0,0 +1,8 @@ +HTML.TidyRemove +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to remove from the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt new file mode 100644 index 0000000000..89133b1a38 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt @@ -0,0 +1,8 @@ +HTML.Trusted +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user input is trusted or not. If the input is +trusted, a more expansive set of allowed tags and attributes will be used. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt new file mode 100644 index 0000000000..2a47e384f4 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt @@ -0,0 +1,11 @@ +HTML.XHTML +TYPE: bool +DEFAULT: true +VERSION: 1.1.0 +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not output is XHTML 1.0 or HTML 4.01 flavor. +--ALIASES-- +Core.XHTML +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt new file mode 100644 index 0000000000..08921fde70 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt @@ -0,0 +1,10 @@ +Output.CommentScriptContents +TYPE: bool +VERSION: 2.0.0 +DEFAULT: true +--DESCRIPTION-- +Determines whether or not HTML Purifier should attempt to fix up the +contents of script tags for legacy browsers with comments. +--ALIASES-- +Core.CommentScriptContents +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt new file mode 100644 index 0000000000..79f8ad82cf --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt @@ -0,0 +1,13 @@ +Output.Newline +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Newline string to format final output with. If left null, HTML Purifier + will auto-detect the default newline type of the system and use that; + you can manually override it here. Remember, \r\n is Windows, \r + is Mac, and \n is Unix. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt new file mode 100644 index 0000000000..232b02362a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt @@ -0,0 +1,14 @@ +Output.SortAttr +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ If true, HTML Purifier will sort attributes by name before writing them back + to the document, converting a tag like: <el b="" a="" c="" /> + to <el a="" b="" c="" />. This is a workaround for + a bug in FCKeditor which causes it to swap attributes order, adding noise + to text diffs. If you're not seeing this bug, chances are, you don't need + this directive. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt new file mode 100644 index 0000000000..06bab00a0a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt @@ -0,0 +1,25 @@ +Output.TidyFormat +TYPE: bool +VERSION: 1.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Determines whether or not to run Tidy on the final output for pretty + formatting reasons, such as indentation and wrap. +

+

+ This can greatly improve readability for editors who are hand-editing + the HTML, but is by no means necessary as HTML Purifier has already + fixed all major errors the HTML may have had. Tidy is a non-default + extension, and this directive will silently fail if Tidy is not + available. +

+

+ If you are looking to make the overall look of your page's source + better, I recommend running Tidy on the entire page rather than just + user-content (after all, the indentation relative to the containing + blocks will be incorrect). +

+--ALIASES-- +Core.TidyFormat +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt new file mode 100644 index 0000000000..071bc0295d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt @@ -0,0 +1,7 @@ +Test.ForceNoIconv +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When set to true, HTMLPurifier_Encoder will act as if iconv does not exist +and use only pure PHP implementations. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt new file mode 100644 index 0000000000..98fdfe9222 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt @@ -0,0 +1,15 @@ +URI.AllowedSchemes +TYPE: lookup +--DEFAULT-- +array ( + 'http' => true, + 'https' => true, + 'mailto' => true, + 'ftp' => true, + 'nntp' => true, + 'news' => true, +) +--DESCRIPTION-- +Whitelist that defines the schemes that a URI is allowed to have. This +prevents XSS attacks from using pseudo-schemes like javascript or mocha. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Base.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Base.txt new file mode 100644 index 0000000000..876f0680cf --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Base.txt @@ -0,0 +1,17 @@ +URI.Base +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ The base URI is the URI of the document this purified HTML will be + inserted into. This information is important if HTML Purifier needs + to calculate absolute URIs from relative URIs, such as when %URI.MakeAbsolute + is on. You may use a non-absolute URI for this value, but behavior + may vary (%URI.MakeAbsolute deals nicely with both absolute and + relative paths, but forwards-compatibility is not guaranteed). + Warning: If set, the scheme on this URI + overrides the one specified by %URI.DefaultScheme. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt new file mode 100644 index 0000000000..728e378cbe --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt @@ -0,0 +1,10 @@ +URI.DefaultScheme +TYPE: string +DEFAULT: 'http' +--DESCRIPTION-- + +

+ Defines through what scheme the output will be served, in order to + select the proper object validator when no scheme information is present. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt new file mode 100644 index 0000000000..f05312ba86 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt @@ -0,0 +1,11 @@ +URI.DefinitionID +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Unique identifier for a custom-built URI definition. If you want + to add custom URIFilters, you must specify this value. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt new file mode 100644 index 0000000000..80cfea93f7 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt @@ -0,0 +1,11 @@ +URI.DefinitionRev +TYPE: int +VERSION: 2.1.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt new file mode 100644 index 0000000000..71ce025a2d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt @@ -0,0 +1,14 @@ +URI.Disable +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Disables all URIs in all forms. Not sure why you'd want to do that + (after all, the Internet's founded on the notion of a hyperlink). +

+ +--ALIASES-- +Attr.DisableURI +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt new file mode 100644 index 0000000000..13c122c8ce --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt @@ -0,0 +1,11 @@ +URI.DisableExternal +TYPE: bool +VERSION: 1.2.0 +DEFAULT: false +--DESCRIPTION-- +Disables links to external websites. This is a highly effective anti-spam +and anti-pagerank-leech measure, but comes at a hefty price: nolinks or +images outside of your domain will be allowed. Non-linkified URIs will +still be preserved. If you want to be able to link to subdomains or use +absolute URIs, specify %URI.Host for your website. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt new file mode 100644 index 0000000000..abcc1efd61 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt @@ -0,0 +1,13 @@ +URI.DisableExternalResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- +Disables the embedding of external resources, preventing users from +embedding things like images from other hosts. This prevents access +tracking (good for email viewers), bandwidth leeching, cross-site request +forging, goatse.cx posting, and other nasties, but also results in a loss +of end-user functionality (they can't directly post a pic they posted from +Flickr anymore). Use it if you don't have a robust user-content moderation +team. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt new file mode 100644 index 0000000000..51e6ea91f7 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt @@ -0,0 +1,12 @@ +URI.DisableResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Disables embedding resources, essentially meaning no pictures. You can + still link to them though. See %URI.DisableExternalResources for why + this might be a good idea. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Host.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Host.txt new file mode 100644 index 0000000000..ee83b121de --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Host.txt @@ -0,0 +1,19 @@ +URI.Host +TYPE: string/null +VERSION: 1.2.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Defines the domain name of the server, so we can determine whether or + an absolute URI is from your website or not. Not strictly necessary, + as users should be using relative URIs to reference resources on your + website. It will, however, let you use absolute URIs to link to + subdomains of the domain you post here: i.e. example.com will allow + sub.example.com. However, higher up domains will still be excluded: + if you set %URI.Host to sub.example.com, example.com will be blocked. + Note: This directive overrides %URI.Base because + a given page may be on a sub-domain, but you wish HTML Purifier to be + more relaxed and allow some of the parent domains too. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt new file mode 100644 index 0000000000..0b6df7625d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt @@ -0,0 +1,9 @@ +URI.HostBlacklist +TYPE: list +VERSION: 1.3.0 +DEFAULT: array() +--DESCRIPTION-- +List of strings that are forbidden in the host of any URI. Use it to kill +domain names of spam, etc. Note that it will catch anything in the domain, +so moo.com will catch moo.com.example.com. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt new file mode 100644 index 0000000000..4214900a59 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt @@ -0,0 +1,13 @@ +URI.MakeAbsolute +TYPE: bool +VERSION: 2.1.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Converts all URIs into absolute forms. This is useful when the HTML + being filtered assumes a specific base path, but will actually be + viewed in a different context (and setting an alternate base URI is + not possible). %URI.Base must be set for this directive to work. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt new file mode 100644 index 0000000000..58c81dcc44 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt @@ -0,0 +1,83 @@ +URI.Munge +TYPE: string/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Munges all browsable (usually http, https and ftp) + absolute URIs into another URI, usually a URI redirection service. + This directive accepts a URI, formatted with a %s where + the url-encoded original URI should be inserted (sample: + http://www.google.com/url?q=%s). +

+

+ Uses for this directive: +

+
    +
  • + Prevent PageRank leaks, while being fairly transparent + to users (you may also want to add some client side JavaScript to + override the text in the statusbar). Notice: + Many security experts believe that this form of protection does not deter spam-bots. +
  • +
  • + Redirect users to a splash page telling them they are leaving your + website. While this is poor usability practice, it is often mandated + in corporate environments. +
  • +
+

+ Prior to HTML Purifier 3.1.1, this directive also enabled the munging + of browsable external resources, which could break things if your redirection + script was a splash page or used meta tags. To revert to + previous behavior, please use %URI.MungeResources. +

+

+ You may want to also use %URI.MungeSecretKey along with this directive + in order to enforce what URIs your redirector script allows. Open + redirector scripts can be a security risk and negatively affect the + reputation of your domain name. +

+

+ Starting with HTML Purifier 3.1.1, there is also these substitutions: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescriptionExample <a href="">
%r1 - The URI embeds a resource
(blank) - The URI is merely a link
%nThe name of the tag this URI came froma
%mThe name of the attribute this URI came fromhref
%pThe name of the CSS property this URI came from, or blank if irrelevant
+

+ Admittedly, these letters are somewhat arbitrary; the only stipulation + was that they couldn't be a through f. r is for resource (I would have preferred + e, but you take what you can get), n is for name, m + was picked because it came after n (and I couldn't use a), p is for + property. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt new file mode 100644 index 0000000000..6fce0fdc37 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt @@ -0,0 +1,17 @@ +URI.MungeResources +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ If true, any URI munging directives like %URI.Munge + will also apply to embedded resources, such as <img src="">. + Be careful enabling this directive if you have a redirector script + that does not use the Location HTTP header; all of your images + and other embedded resources will break. +

+

+ Warning: It is strongly advised you use this in conjunction + %URI.MungeSecretKey to mitigate the security risk of an open redirector. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt new file mode 100644 index 0000000000..0d00f62ea8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt @@ -0,0 +1,30 @@ +URI.MungeSecretKey +TYPE: string/null +VERSION: 3.1.1 +DEFAULT: NULL +--DESCRIPTION-- +

+ This directive enables secure checksum generation along with %URI.Munge. + It should be set to a secure key that is not shared with anyone else. + The checksum can be placed in the URI using %t. Use of this checksum + affords an additional level of protection by allowing a redirector + to check if a URI has passed through HTML Purifier with this line: +

+ +
$checksum === sha1($secret_key . ':' . $url)
+ +

+ If the output is TRUE, the redirector script should accept the URI. +

+ +

+ Please note that it would still be possible for an attacker to procure + secure hashes en-mass by abusing your website's Preview feature or the + like, but this service affords an additional level of protection + that should be combined with website blacklisting. +

+ +

+ Remember this has no effect if %URI.Munge is not on. +

+--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt new file mode 100644 index 0000000000..23331a4e79 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt @@ -0,0 +1,9 @@ +URI.OverrideAllowedSchemes +TYPE: bool +DEFAULT: true +--DESCRIPTION-- +If this is set to true (which it is by default), you can override +%URI.AllowedSchemes by simply registering a HTMLPurifier_URIScheme to the +registry. If false, you will also have to update that directive in order +to add more schemes. +--# vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/info.ini b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/info.ini new file mode 100644 index 0000000000..5de4505e1b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/info.ini @@ -0,0 +1,3 @@ +name = "HTML Purifier" + +; vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ContentSets.php b/extlib/HTMLPurifier/HTMLPurifier/ContentSets.php new file mode 100644 index 0000000000..3b6e96f5f5 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ContentSets.php @@ -0,0 +1,155 @@ + true) indexed by name. + * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets + */ + public $lookup = array(); + + /** + * Synchronized list of defined content sets (keys of info) + */ + protected $keys = array(); + /** + * Synchronized list of defined content values (values of info) + */ + protected $values = array(); + + /** + * Merges in module's content sets, expands identifiers in the content + * sets and populates the keys, values and lookup member variables. + * @param $modules List of HTMLPurifier_HTMLModule + */ + public function __construct($modules) { + if (!is_array($modules)) $modules = array($modules); + // populate content_sets based on module hints + // sorry, no way of overloading + foreach ($modules as $module_i => $module) { + foreach ($module->content_sets as $key => $value) { + $temp = $this->convertToLookup($value); + if (isset($this->lookup[$key])) { + // add it into the existing content set + $this->lookup[$key] = array_merge($this->lookup[$key], $temp); + } else { + $this->lookup[$key] = $temp; + } + } + } + $old_lookup = false; + while ($old_lookup !== $this->lookup) { + $old_lookup = $this->lookup; + foreach ($this->lookup as $i => $set) { + $add = array(); + foreach ($set as $element => $x) { + if (isset($this->lookup[$element])) { + $add += $this->lookup[$element]; + unset($this->lookup[$i][$element]); + } + } + $this->lookup[$i] += $add; + } + } + + foreach ($this->lookup as $key => $lookup) { + $this->info[$key] = implode(' | ', array_keys($lookup)); + } + $this->keys = array_keys($this->info); + $this->values = array_values($this->info); + } + + /** + * Accepts a definition; generates and assigns a ChildDef for it + * @param $def HTMLPurifier_ElementDef reference + * @param $module Module that defined the ElementDef + */ + public function generateChildDef(&$def, $module) { + if (!empty($def->child)) return; // already done! + $content_model = $def->content_model; + if (is_string($content_model)) { + // Assume that $this->keys is alphanumeric + $def->content_model = preg_replace_callback( + '/\b(' . implode('|', $this->keys) . ')\b/', + array($this, 'generateChildDefCallback'), + $content_model + ); + //$def->content_model = str_replace( + // $this->keys, $this->values, $content_model); + } + $def->child = $this->getChildDef($def, $module); + } + + public function generateChildDefCallback($matches) { + return $this->info[$matches[0]]; + } + + /** + * Instantiates a ChildDef based on content_model and content_model_type + * member variables in HTMLPurifier_ElementDef + * @note This will also defer to modules for custom HTMLPurifier_ChildDef + * subclasses that need content set expansion + * @param $def HTMLPurifier_ElementDef to have ChildDef extracted + * @return HTMLPurifier_ChildDef corresponding to ElementDef + */ + public function getChildDef($def, $module) { + $value = $def->content_model; + if (is_object($value)) { + trigger_error( + 'Literal object child definitions should be stored in '. + 'ElementDef->child not ElementDef->content_model', + E_USER_NOTICE + ); + return $value; + } + switch ($def->content_model_type) { + case 'required': + return new HTMLPurifier_ChildDef_Required($value); + case 'optional': + return new HTMLPurifier_ChildDef_Optional($value); + case 'empty': + return new HTMLPurifier_ChildDef_Empty(); + case 'custom': + return new HTMLPurifier_ChildDef_Custom($value); + } + // defer to its module + $return = false; + if ($module->defines_child_def) { // save a func call + $return = $module->getChildDef($def); + } + if ($return !== false) return $return; + // error-out + trigger_error( + 'Could not determine which ChildDef class to instantiate', + E_USER_ERROR + ); + return false; + } + + /** + * Converts a string list of elements separated by pipes into + * a lookup array. + * @param $string List of elements + * @return Lookup array of elements + */ + protected function convertToLookup($string) { + $array = explode('|', str_replace(' ', '', $string)); + $ret = array(); + foreach ($array as $i => $k) { + $ret[$k] = true; + } + return $ret; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Context.php b/extlib/HTMLPurifier/HTMLPurifier/Context.php new file mode 100644 index 0000000000..9ddf0c5476 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Context.php @@ -0,0 +1,82 @@ +_storage[$name])) { + trigger_error("Name $name produces collision, cannot re-register", + E_USER_ERROR); + return; + } + $this->_storage[$name] =& $ref; + } + + /** + * Retrieves a variable reference from the context. + * @param $name String name + * @param $ignore_error Boolean whether or not to ignore error + */ + public function &get($name, $ignore_error = false) { + if (!isset($this->_storage[$name])) { + if (!$ignore_error) { + trigger_error("Attempted to retrieve non-existent variable $name", + E_USER_ERROR); + } + $var = null; // so we can return by reference + return $var; + } + return $this->_storage[$name]; + } + + /** + * Destorys a variable in the context. + * @param $name String name + */ + public function destroy($name) { + if (!isset($this->_storage[$name])) { + trigger_error("Attempted to destroy non-existent variable $name", + E_USER_ERROR); + return; + } + unset($this->_storage[$name]); + } + + /** + * Checks whether or not the variable exists. + * @param $name String name + */ + public function exists($name) { + return isset($this->_storage[$name]); + } + + /** + * Loads a series of variables from an associative array + * @param $context_array Assoc array of variables to load + */ + public function loadArray($context_array) { + foreach ($context_array as $key => $discard) { + $this->register($key, $context_array[$key]); + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Definition.php b/extlib/HTMLPurifier/HTMLPurifier/Definition.php new file mode 100644 index 0000000000..a7408c9749 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Definition.php @@ -0,0 +1,39 @@ +setup) return; + $this->setup = true; + $this->doSetup($config); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache.php b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache.php new file mode 100644 index 0000000000..c6e1e388c6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache.php @@ -0,0 +1,108 @@ +type = $type; + } + + /** + * Generates a unique identifier for a particular configuration + * @param Instance of HTMLPurifier_Config + */ + public function generateKey($config) { + return $config->version . ',' . // possibly replace with function calls + $config->getBatchSerial($this->type) . ',' . + $config->get($this->type . '.DefinitionRev'); + } + + /** + * Tests whether or not a key is old with respect to the configuration's + * version and revision number. + * @param $key Key to test + * @param $config Instance of HTMLPurifier_Config to test against + */ + public function isOld($key, $config) { + if (substr_count($key, ',') < 2) return true; + list($version, $hash, $revision) = explode(',', $key, 3); + $compare = version_compare($version, $config->version); + // version mismatch, is always old + if ($compare != 0) return true; + // versions match, ids match, check revision number + if ( + $hash == $config->getBatchSerial($this->type) && + $revision < $config->get($this->type . '.DefinitionRev') + ) return true; + return false; + } + + /** + * Checks if a definition's type jives with the cache's type + * @note Throws an error on failure + * @param $def Definition object to check + * @return Boolean true if good, false if not + */ + public function checkDefType($def) { + if ($def->type !== $this->type) { + trigger_error("Cannot use definition of type {$def->type} in cache for {$this->type}"); + return false; + } + return true; + } + + /** + * Adds a definition object to the cache + */ + abstract public function add($def, $config); + + /** + * Unconditionally saves a definition object to the cache + */ + abstract public function set($def, $config); + + /** + * Replace an object in the cache + */ + abstract public function replace($def, $config); + + /** + * Retrieves a definition object from the cache + */ + abstract public function get($config); + + /** + * Removes a definition object to the cache + */ + abstract public function remove($config); + + /** + * Clears all objects from cache + */ + abstract public function flush($config); + + /** + * Clears all expired (older version or revision) objects from cache + * @note Be carefuly implementing this method as flush. Flush must + * not interfere with other Definition types, and cleanup() + * should not be repeatedly called by userland code. + */ + abstract public function cleanup($config); + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator.php b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator.php new file mode 100644 index 0000000000..b0fb6d0cd6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator.php @@ -0,0 +1,62 @@ +copy(); + // reference is necessary for mocks in PHP 4 + $decorator->cache =& $cache; + $decorator->type = $cache->type; + return $decorator; + } + + /** + * Cross-compatible clone substitute + */ + public function copy() { + return new HTMLPurifier_DefinitionCache_Decorator(); + } + + public function add($def, $config) { + return $this->cache->add($def, $config); + } + + public function set($def, $config) { + return $this->cache->set($def, $config); + } + + public function replace($def, $config) { + return $this->cache->replace($def, $config); + } + + public function get($config) { + return $this->cache->get($config); + } + + public function remove($config) { + return $this->cache->remove($config); + } + + public function flush($config) { + return $this->cache->flush($config); + } + + public function cleanup($config) { + return $this->cache->cleanup($config); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php new file mode 100644 index 0000000000..d4cc35c4bc --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php @@ -0,0 +1,43 @@ +definitions[$this->generateKey($config)] = $def; + return $status; + } + + public function set($def, $config) { + $status = parent::set($def, $config); + if ($status) $this->definitions[$this->generateKey($config)] = $def; + return $status; + } + + public function replace($def, $config) { + $status = parent::replace($def, $config); + if ($status) $this->definitions[$this->generateKey($config)] = $def; + return $status; + } + + public function get($config) { + $key = $this->generateKey($config); + if (isset($this->definitions[$key])) return $this->definitions[$key]; + $this->definitions[$key] = parent::get($config); + return $this->definitions[$key]; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in new file mode 100644 index 0000000000..21a8fcfda2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in @@ -0,0 +1,47 @@ +checkDefType($def)) return; + $file = $this->generateFilePath($config); + if (file_exists($file)) return false; + if (!$this->_prepareDir($config)) return false; + return $this->_write($file, serialize($def)); + } + + public function set($def, $config) { + if (!$this->checkDefType($def)) return; + $file = $this->generateFilePath($config); + if (!$this->_prepareDir($config)) return false; + return $this->_write($file, serialize($def)); + } + + public function replace($def, $config) { + if (!$this->checkDefType($def)) return; + $file = $this->generateFilePath($config); + if (!file_exists($file)) return false; + if (!$this->_prepareDir($config)) return false; + return $this->_write($file, serialize($def)); + } + + public function get($config) { + $file = $this->generateFilePath($config); + if (!file_exists($file)) return false; + return unserialize(file_get_contents($file)); + } + + public function remove($config) { + $file = $this->generateFilePath($config); + if (!file_exists($file)) return false; + return unlink($file); + } + + public function flush($config) { + if (!$this->_prepareDir($config)) return false; + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) continue; + if ($filename[0] === '.') continue; + unlink($dir . '/' . $filename); + } + } + + public function cleanup($config) { + if (!$this->_prepareDir($config)) return false; + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) continue; + if ($filename[0] === '.') continue; + $key = substr($filename, 0, strlen($filename) - 4); + if ($this->isOld($key, $config)) unlink($dir . '/' . $filename); + } + } + + /** + * Generates the file path to the serial file corresponding to + * the configuration and definition name + * @todo Make protected + */ + public function generateFilePath($config) { + $key = $this->generateKey($config); + return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; + } + + /** + * Generates the path to the directory contain this cache's serial files + * @note No trailing slash + * @todo Make protected + */ + public function generateDirectoryPath($config) { + $base = $this->generateBaseDirectoryPath($config); + return $base . '/' . $this->type; + } + + /** + * Generates path to base directory that contains all definition type + * serials + * @todo Make protected + */ + public function generateBaseDirectoryPath($config) { + $base = $config->get('Cache.SerializerPath'); + $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; + return $base; + } + + /** + * Convenience wrapper function for file_put_contents + * @param $file File name to write to + * @param $data Data to write into file + * @return Number of bytes written if success, or false if failure. + */ + private function _write($file, $data) { + return file_put_contents($file, $data); + } + + /** + * Prepares the directory that this type stores the serials in + * @return True if successful + */ + private function _prepareDir($config) { + $directory = $this->generateDirectoryPath($config); + if (!is_dir($directory)) { + $base = $this->generateBaseDirectoryPath($config); + if (!is_dir($base)) { + trigger_error('Base directory '.$base.' does not exist, + please create or change using %Cache.SerializerPath', + E_USER_WARNING); + return false; + } elseif (!$this->_testPermissions($base)) { + return false; + } + $old = umask(0022); // disable group and world writes + mkdir($directory); + umask($old); + } elseif (!$this->_testPermissions($directory)) { + return false; + } + return true; + } + + /** + * Tests permissions on a directory and throws out friendly + * error messages and attempts to chmod it itself if possible + */ + private function _testPermissions($dir) { + // early abort, if it is writable, everything is hunky-dory + if (is_writable($dir)) return true; + if (!is_dir($dir)) { + // generally, you'll want to handle this beforehand + // so a more specific error message can be given + trigger_error('Directory '.$dir.' does not exist', + E_USER_WARNING); + return false; + } + if (function_exists('posix_getuid')) { + // POSIX system, we can give more specific advice + if (fileowner($dir) === posix_getuid()) { + // we can chmod it ourselves + chmod($dir, 0755); + return true; + } elseif (filegroup($dir) === posix_getgid()) { + $chmod = '775'; + } else { + // PHP's probably running as nobody, so we'll + // need to give global permissions + $chmod = '777'; + } + trigger_error('Directory '.$dir.' not writable, '. + 'please chmod to ' . $chmod, + E_USER_WARNING); + } else { + // generic error message + trigger_error('Directory '.$dir.' not writable, '. + 'please alter file permissions', + E_USER_WARNING); + } + return false; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Serializer/README b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Serializer/README new file mode 100755 index 0000000000..2e35c1c3d0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCache/Serializer/README @@ -0,0 +1,3 @@ +This is a dummy file to prevent Git from ignoring this empty directory. + + vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/DefinitionCacheFactory.php b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCacheFactory.php new file mode 100644 index 0000000000..a6ead62818 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/DefinitionCacheFactory.php @@ -0,0 +1,91 @@ + array()); + protected $implementations = array(); + protected $decorators = array(); + + /** + * Initialize default decorators + */ + public function setup() { + $this->addDecorator('Cleanup'); + } + + /** + * Retrieves an instance of global definition cache factory. + */ + public static function instance($prototype = null) { + static $instance; + if ($prototype !== null) { + $instance = $prototype; + } elseif ($instance === null || $prototype === true) { + $instance = new HTMLPurifier_DefinitionCacheFactory(); + $instance->setup(); + } + return $instance; + } + + /** + * Registers a new definition cache object + * @param $short Short name of cache object, for reference + * @param $long Full class name of cache object, for construction + */ + public function register($short, $long) { + $this->implementations[$short] = $long; + } + + /** + * Factory method that creates a cache object based on configuration + * @param $name Name of definitions handled by cache + * @param $config Instance of HTMLPurifier_Config + */ + public function create($type, $config) { + $method = $config->get('Cache.DefinitionImpl'); + if ($method === null) { + return new HTMLPurifier_DefinitionCache_Null($type); + } + if (!empty($this->caches[$method][$type])) { + return $this->caches[$method][$type]; + } + if ( + isset($this->implementations[$method]) && + class_exists($class = $this->implementations[$method], false) + ) { + $cache = new $class($type); + } else { + if ($method != 'Serializer') { + trigger_error("Unrecognized DefinitionCache $method, using Serializer instead", E_USER_WARNING); + } + $cache = new HTMLPurifier_DefinitionCache_Serializer($type); + } + foreach ($this->decorators as $decorator) { + $new_cache = $decorator->decorate($cache); + // prevent infinite recursion in PHP 4 + unset($cache); + $cache = $new_cache; + } + $this->caches[$method][$type] = $cache; + return $this->caches[$method][$type]; + } + + /** + * Registers a decorator to add to all new cache objects + * @param + */ + public function addDecorator($decorator) { + if (is_string($decorator)) { + $class = "HTMLPurifier_DefinitionCache_Decorator_$decorator"; + $decorator = new $class; + } + $this->decorators[$decorator->name] = $decorator; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Doctype.php b/extlib/HTMLPurifier/HTMLPurifier/Doctype.php new file mode 100644 index 0000000000..1e3c574c06 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Doctype.php @@ -0,0 +1,60 @@ +renderDoctype. + * If structure changes, please update that function. + */ +class HTMLPurifier_Doctype +{ + /** + * Full name of doctype + */ + public $name; + + /** + * List of standard modules (string identifiers or literal objects) + * that this doctype uses + */ + public $modules = array(); + + /** + * List of modules to use for tidying up code + */ + public $tidyModules = array(); + + /** + * Is the language derived from XML (i.e. XHTML)? + */ + public $xml = true; + + /** + * List of aliases for this doctype + */ + public $aliases = array(); + + /** + * Public DTD identifier + */ + public $dtdPublic; + + /** + * System DTD identifier + */ + public $dtdSystem; + + public function __construct($name = null, $xml = true, $modules = array(), + $tidyModules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null + ) { + $this->name = $name; + $this->xml = $xml; + $this->modules = $modules; + $this->tidyModules = $tidyModules; + $this->aliases = $aliases; + $this->dtdPublic = $dtd_public; + $this->dtdSystem = $dtd_system; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/DoctypeRegistry.php b/extlib/HTMLPurifier/HTMLPurifier/DoctypeRegistry.php new file mode 100644 index 0000000000..86049e9391 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/DoctypeRegistry.php @@ -0,0 +1,103 @@ +doctypes[$doctype->name] = $doctype; + $name = $doctype->name; + // hookup aliases + foreach ($doctype->aliases as $alias) { + if (isset($this->doctypes[$alias])) continue; + $this->aliases[$alias] = $name; + } + // remove old aliases + if (isset($this->aliases[$name])) unset($this->aliases[$name]); + return $doctype; + } + + /** + * Retrieves reference to a doctype of a certain name + * @note This function resolves aliases + * @note When possible, use the more fully-featured make() + * @param $doctype Name of doctype + * @return Editable doctype object + */ + public function get($doctype) { + if (isset($this->aliases[$doctype])) $doctype = $this->aliases[$doctype]; + if (!isset($this->doctypes[$doctype])) { + trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR); + $anon = new HTMLPurifier_Doctype($doctype); + return $anon; + } + return $this->doctypes[$doctype]; + } + + /** + * Creates a doctype based on a configuration object, + * will perform initialization on the doctype + * @note Use this function to get a copy of doctype that config + * can hold on to (this is necessary in order to tell + * Generator whether or not the current document is XML + * based or not). + */ + public function make($config) { + return clone $this->get($this->getDoctypeFromConfig($config)); + } + + /** + * Retrieves the doctype from the configuration object + */ + public function getDoctypeFromConfig($config) { + // recommended test + $doctype = $config->get('HTML.Doctype'); + if (!empty($doctype)) return $doctype; + $doctype = $config->get('HTML.CustomDoctype'); + if (!empty($doctype)) return $doctype; + // backwards-compatibility + if ($config->get('HTML.XHTML')) { + $doctype = 'XHTML 1.0'; + } else { + $doctype = 'HTML 4.01'; + } + if ($config->get('HTML.Strict')) { + $doctype .= ' Strict'; + } else { + $doctype .= ' Transitional'; + } + return $doctype; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ElementDef.php b/extlib/HTMLPurifier/HTMLPurifier/ElementDef.php new file mode 100644 index 0000000000..aede2c3bb4 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ElementDef.php @@ -0,0 +1,176 @@ +setup(), this array may also + * contain an array at index 0 that indicates which attribute + * collections to load into the full array. It may also + * contain string indentifiers in lieu of HTMLPurifier_AttrDef, + * see HTMLPurifier_AttrTypes on how they are expanded during + * HTMLPurifier_HTMLDefinition->setup() processing. + */ + public $attr = array(); + + /** + * Indexed list of tag's HTMLPurifier_AttrTransform to be done before validation + */ + public $attr_transform_pre = array(); + + /** + * Indexed list of tag's HTMLPurifier_AttrTransform to be done after validation + */ + public $attr_transform_post = array(); + + /** + * HTMLPurifier_ChildDef of this tag. + */ + public $child; + + /** + * Abstract string representation of internal ChildDef rules. See + * HTMLPurifier_ContentSets for how this is parsed and then transformed + * into an HTMLPurifier_ChildDef. + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + */ + public $content_model; + + /** + * Value of $child->type, used to determine which ChildDef to use, + * used in combination with $content_model. + * @warning This must be lowercase + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + */ + public $content_model_type; + + + + /** + * Does the element have a content model (#PCDATA | Inline)*? This + * is important for chameleon ins and del processing in + * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't + * have to worry about this one. + */ + public $descendants_are_inline = false; + + /** + * List of the names of required attributes this element has. Dynamically + * populated by HTMLPurifier_HTMLDefinition::getElement + */ + public $required_attr = array(); + + /** + * Lookup table of tags excluded from all descendants of this tag. + * @note SGML permits exclusions for all descendants, but this is + * not possible with DTDs or XML Schemas. W3C has elected to + * use complicated compositions of content_models to simulate + * exclusion for children, but we go the simpler, SGML-style + * route of flat-out exclusions, which correctly apply to + * all descendants and not just children. Note that the XHTML + * Modularization Abstract Modules are blithely unaware of such + * distinctions. + */ + public $excludes = array(); + + /** + * This tag is explicitly auto-closed by the following tags. + */ + public $autoclose = array(); + + /** + * Whether or not this is a formatting element affected by the + * "Active Formatting Elements" algorithm. + */ + public $formatting; + + /** + * Low-level factory constructor for creating new standalone element defs + */ + public static function create($content_model, $content_model_type, $attr) { + $def = new HTMLPurifier_ElementDef(); + $def->content_model = $content_model; + $def->content_model_type = $content_model_type; + $def->attr = $attr; + return $def; + } + + /** + * Merges the values of another element definition into this one. + * Values from the new element def take precedence if a value is + * not mergeable. + */ + public function mergeIn($def) { + + // later keys takes precedence + foreach($def->attr as $k => $v) { + if ($k === 0) { + // merge in the includes + // sorry, no way to override an include + foreach ($v as $v2) { + $this->attr[0][] = $v2; + } + continue; + } + if ($v === false) { + if (isset($this->attr[$k])) unset($this->attr[$k]); + continue; + } + $this->attr[$k] = $v; + } + $this->_mergeAssocArray($this->attr_transform_pre, $def->attr_transform_pre); + $this->_mergeAssocArray($this->attr_transform_post, $def->attr_transform_post); + $this->_mergeAssocArray($this->excludes, $def->excludes); + + if(!empty($def->content_model)) { + $this->content_model = + str_replace("#SUPER", $this->content_model, $def->content_model); + $this->child = false; + } + if(!empty($def->content_model_type)) { + $this->content_model_type = $def->content_model_type; + $this->child = false; + } + if(!is_null($def->child)) $this->child = $def->child; + if(!is_null($def->formatting)) $this->formatting = $def->formatting; + if($def->descendants_are_inline) $this->descendants_are_inline = $def->descendants_are_inline; + + } + + /** + * Merges one array into another, removes values which equal false + * @param $a1 Array by reference that is merged into + * @param $a2 Array that merges into $a1 + */ + private function _mergeAssocArray(&$a1, $a2) { + foreach ($a2 as $k => $v) { + if ($v === false) { + if (isset($a1[$k])) unset($a1[$k]); + continue; + } + $a1[$k] = $v; + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Encoder.php b/extlib/HTMLPurifier/HTMLPurifier/Encoder.php new file mode 100644 index 0000000000..2b3140caaf --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Encoder.php @@ -0,0 +1,426 @@ + under the + * LGPL license. Notes on what changed are inside, but in general, + * the original code transformed UTF-8 text into an array of integer + * Unicode codepoints. Understandably, transforming that back to + * a string would be somewhat expensive, so the function was modded to + * directly operate on the string. However, this discourages code + * reuse, and the logic enumerated here would be useful for any + * function that needs to be able to understand UTF-8 characters. + * As of right now, only smart lossless character encoding converters + * would need that, and I'm probably not going to implement them. + * Once again, PHP 6 should solve all our problems. + */ + public static function cleanUTF8($str, $force_php = false) { + + // UTF-8 validity is checked since PHP 4.3.5 + // This is an optimization: if the string is already valid UTF-8, no + // need to do PHP stuff. 99% of the time, this will be the case. + // The regexp matches the XML char production, as well as well as excluding + // non-SGML codepoints U+007F to U+009F + if (preg_match('/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du', $str)) { + return $str; + } + + $mState = 0; // cached expected number of octets after the current octet + // until the beginning of the next UTF8 character sequence + $mUcs4 = 0; // cached Unicode character + $mBytes = 1; // cached expected number of octets in the current sequence + + // original code involved an $out that was an array of Unicode + // codepoints. Instead of having to convert back into UTF-8, we've + // decided to directly append valid UTF-8 characters onto a string + // $out once they're done. $char accumulates raw bytes, while $mUcs4 + // turns into the Unicode code point, so there's some redundancy. + + $out = ''; + $char = ''; + + $len = strlen($str); + for($i = 0; $i < $len; $i++) { + $in = ord($str{$i}); + $char .= $str[$i]; // append byte to char + if (0 == $mState) { + // When mState is zero we expect either a US-ASCII character + // or a multi-octet sequence. + if (0 == (0x80 & ($in))) { + // US-ASCII, pass straight through. + if (($in <= 31 || $in == 127) && + !($in == 9 || $in == 13 || $in == 10) // save \r\t\n + ) { + // control characters, remove + } else { + $out .= $char; + } + // reset + $char = ''; + $mBytes = 1; + } elseif (0xC0 == (0xE0 & ($in))) { + // First octet of 2 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x1F) << 6; + $mState = 1; + $mBytes = 2; + } elseif (0xE0 == (0xF0 & ($in))) { + // First octet of 3 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x0F) << 12; + $mState = 2; + $mBytes = 3; + } elseif (0xF0 == (0xF8 & ($in))) { + // First octet of 4 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x07) << 18; + $mState = 3; + $mBytes = 4; + } elseif (0xF8 == (0xFC & ($in))) { + // First octet of 5 octet sequence. + // + // This is illegal because the encoded codepoint must be + // either: + // (a) not the shortest form or + // (b) outside the Unicode range of 0-0x10FFFF. + // Rather than trying to resynchronize, we will carry on + // until the end of the sequence and let the later error + // handling code catch it. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x03) << 24; + $mState = 4; + $mBytes = 5; + } elseif (0xFC == (0xFE & ($in))) { + // First octet of 6 octet sequence, see comments for 5 + // octet sequence. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 1) << 30; + $mState = 5; + $mBytes = 6; + } else { + // Current octet is neither in the US-ASCII range nor a + // legal first octet of a multi-octet sequence. + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // When mState is non-zero, we expect a continuation of the + // multi-octet sequence + if (0x80 == (0xC0 & ($in))) { + // Legal continuation. + $shift = ($mState - 1) * 6; + $tmp = $in; + $tmp = ($tmp & 0x0000003F) << $shift; + $mUcs4 |= $tmp; + + if (0 == --$mState) { + // End of the multi-octet sequence. mUcs4 now contains + // the final Unicode codepoint to be output + + // Check for illegal sequences and codepoints. + + // From Unicode 3.1, non-shortest form is illegal + if (((2 == $mBytes) && ($mUcs4 < 0x0080)) || + ((3 == $mBytes) && ($mUcs4 < 0x0800)) || + ((4 == $mBytes) && ($mUcs4 < 0x10000)) || + (4 < $mBytes) || + // From Unicode 3.2, surrogate characters = illegal + (($mUcs4 & 0xFFFFF800) == 0xD800) || + // Codepoints outside the Unicode range are illegal + ($mUcs4 > 0x10FFFF) + ) { + + } elseif (0xFEFF != $mUcs4 && // omit BOM + // check for valid Char unicode codepoints + ( + 0x9 == $mUcs4 || + 0xA == $mUcs4 || + 0xD == $mUcs4 || + (0x20 <= $mUcs4 && 0x7E >= $mUcs4) || + // 7F-9F is not strictly prohibited by XML, + // but it is non-SGML, and thus we don't allow it + (0xA0 <= $mUcs4 && 0xD7FF >= $mUcs4) || + (0x10000 <= $mUcs4 && 0x10FFFF >= $mUcs4) + ) + ) { + $out .= $char; + } + // initialize UTF8 cache (reset) + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // ((0xC0 & (*in) != 0x80) && (mState != 0)) + // Incomplete multi-octet sequence. + // used to result in complete fail, but we'll reset + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char =''; + } + } + } + return $out; + } + + /** + * Translates a Unicode codepoint into its corresponding UTF-8 character. + * @note Based on Feyd's function at + * , + * which is in public domain. + * @note While we're going to do code point parsing anyway, a good + * optimization would be to refuse to translate code points that + * are non-SGML characters. However, this could lead to duplication. + * @note This is very similar to the unichr function in + * maintenance/generate-entity-file.php (although this is superior, + * due to its sanity checks). + */ + + // +----------+----------+----------+----------+ + // | 33222222 | 22221111 | 111111 | | + // | 10987654 | 32109876 | 54321098 | 76543210 | bit + // +----------+----------+----------+----------+ + // | | | | 0xxxxxxx | 1 byte 0x00000000..0x0000007F + // | | | 110yyyyy | 10xxxxxx | 2 byte 0x00000080..0x000007FF + // | | 1110zzzz | 10yyyyyy | 10xxxxxx | 3 byte 0x00000800..0x0000FFFF + // | 11110www | 10wwzzzz | 10yyyyyy | 10xxxxxx | 4 byte 0x00010000..0x0010FFFF + // +----------+----------+----------+----------+ + // | 00000000 | 00011111 | 11111111 | 11111111 | Theoretical upper limit of legal scalars: 2097151 (0x001FFFFF) + // | 00000000 | 00010000 | 11111111 | 11111111 | Defined upper limit of legal scalar codes + // +----------+----------+----------+----------+ + + public static function unichr($code) { + if($code > 1114111 or $code < 0 or + ($code >= 55296 and $code <= 57343) ) { + // bits are set outside the "valid" range as defined + // by UNICODE 4.1.0 + return ''; + } + + $x = $y = $z = $w = 0; + if ($code < 128) { + // regular ASCII character + $x = $code; + } else { + // set up bits for UTF-8 + $x = ($code & 63) | 128; + if ($code < 2048) { + $y = (($code & 2047) >> 6) | 192; + } else { + $y = (($code & 4032) >> 6) | 128; + if($code < 65536) { + $z = (($code >> 12) & 15) | 224; + } else { + $z = (($code >> 12) & 63) | 128; + $w = (($code >> 18) & 7) | 240; + } + } + } + // set up the actual character + $ret = ''; + if($w) $ret .= chr($w); + if($z) $ret .= chr($z); + if($y) $ret .= chr($y); + $ret .= chr($x); + + return $ret; + } + + /** + * Converts a string to UTF-8 based on configuration. + */ + public static function convertToUTF8($str, $config, $context) { + $encoding = $config->get('Core.Encoding'); + if ($encoding === 'utf-8') return $str; + static $iconv = null; + if ($iconv === null) $iconv = function_exists('iconv'); + set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler')); + if ($iconv && !$config->get('Test.ForceNoIconv')) { + $str = iconv($encoding, 'utf-8//IGNORE', $str); + if ($str === false) { + // $encoding is not a valid encoding + restore_error_handler(); + trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR); + return ''; + } + // If the string is bjorked by Shift_JIS or a similar encoding + // that doesn't support all of ASCII, convert the naughty + // characters to their true byte-wise ASCII/UTF-8 equivalents. + $str = strtr($str, HTMLPurifier_Encoder::testEncodingSupportsASCII($encoding)); + restore_error_handler(); + return $str; + } elseif ($encoding === 'iso-8859-1') { + $str = utf8_encode($str); + restore_error_handler(); + return $str; + } + trigger_error('Encoding not supported, please install iconv', E_USER_ERROR); + } + + /** + * Converts a string from UTF-8 based on configuration. + * @note Currently, this is a lossy conversion, with unexpressable + * characters being omitted. + */ + public static function convertFromUTF8($str, $config, $context) { + $encoding = $config->get('Core.Encoding'); + if ($encoding === 'utf-8') return $str; + static $iconv = null; + if ($iconv === null) $iconv = function_exists('iconv'); + if ($escape = $config->get('Core.EscapeNonASCIICharacters')) { + $str = HTMLPurifier_Encoder::convertToASCIIDumbLossless($str); + } + set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler')); + if ($iconv && !$config->get('Test.ForceNoIconv')) { + // Undo our previous fix in convertToUTF8, otherwise iconv will barf + $ascii_fix = HTMLPurifier_Encoder::testEncodingSupportsASCII($encoding); + if (!$escape && !empty($ascii_fix)) { + $clear_fix = array(); + foreach ($ascii_fix as $utf8 => $native) $clear_fix[$utf8] = ''; + $str = strtr($str, $clear_fix); + } + $str = strtr($str, array_flip($ascii_fix)); + // Normal stuff + $str = iconv('utf-8', $encoding . '//IGNORE', $str); + restore_error_handler(); + return $str; + } elseif ($encoding === 'iso-8859-1') { + $str = utf8_decode($str); + restore_error_handler(); + return $str; + } + trigger_error('Encoding not supported', E_USER_ERROR); + } + + /** + * Lossless (character-wise) conversion of HTML to ASCII + * @param $str UTF-8 string to be converted to ASCII + * @returns ASCII encoded string with non-ASCII character entity-ized + * @warning Adapted from MediaWiki, claiming fair use: this is a common + * algorithm. If you disagree with this license fudgery, + * implement it yourself. + * @note Uses decimal numeric entities since they are best supported. + * @note This is a DUMB function: it has no concept of keeping + * character entities that the projected character encoding + * can allow. We could possibly implement a smart version + * but that would require it to also know which Unicode + * codepoints the charset supported (not an easy task). + * @note Sort of with cleanUTF8() but it assumes that $str is + * well-formed UTF-8 + */ + public static function convertToASCIIDumbLossless($str) { + $bytesleft = 0; + $result = ''; + $working = 0; + $len = strlen($str); + for( $i = 0; $i < $len; $i++ ) { + $bytevalue = ord( $str[$i] ); + if( $bytevalue <= 0x7F ) { //0xxx xxxx + $result .= chr( $bytevalue ); + $bytesleft = 0; + } elseif( $bytevalue <= 0xBF ) { //10xx xxxx + $working = $working << 6; + $working += ($bytevalue & 0x3F); + $bytesleft--; + if( $bytesleft <= 0 ) { + $result .= "&#" . $working . ";"; + } + } elseif( $bytevalue <= 0xDF ) { //110x xxxx + $working = $bytevalue & 0x1F; + $bytesleft = 1; + } elseif( $bytevalue <= 0xEF ) { //1110 xxxx + $working = $bytevalue & 0x0F; + $bytesleft = 2; + } else { //1111 0xxx + $working = $bytevalue & 0x07; + $bytesleft = 3; + } + } + return $result; + } + + /** + * This expensive function tests whether or not a given character + * encoding supports ASCII. 7/8-bit encodings like Shift_JIS will + * fail this test, and require special processing. Variable width + * encodings shouldn't ever fail. + * + * @param string $encoding Encoding name to test, as per iconv format + * @param bool $bypass Whether or not to bypass the precompiled arrays. + * @return Array of UTF-8 characters to their corresponding ASCII, + * which can be used to "undo" any overzealous iconv action. + */ + public static function testEncodingSupportsASCII($encoding, $bypass = false) { + static $encodings = array(); + if (!$bypass) { + if (isset($encodings[$encoding])) return $encodings[$encoding]; + $lenc = strtolower($encoding); + switch ($lenc) { + case 'shift_jis': + return array("\xC2\xA5" => '\\', "\xE2\x80\xBE" => '~'); + case 'johab': + return array("\xE2\x82\xA9" => '\\'); + } + if (strpos($lenc, 'iso-8859-') === 0) return array(); + } + $ret = array(); + set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler')); + if (iconv('UTF-8', $encoding, 'a') === false) return false; + for ($i = 0x20; $i <= 0x7E; $i++) { // all printable ASCII chars + $c = chr($i); // UTF-8 char + $r = iconv('UTF-8', "$encoding//IGNORE", $c); // initial conversion + if ( + $r === '' || + // This line is needed for iconv implementations that do not + // omit characters that do not exist in the target character set + ($r === $c && iconv($encoding, 'UTF-8//IGNORE', $r) !== $c) + ) { + // Reverse engineer: what's the UTF-8 equiv of this byte + // sequence? This assumes that there's no variable width + // encoding that doesn't support ASCII. + $ret[iconv($encoding, 'UTF-8//IGNORE', $c)] = $c; + } + } + restore_error_handler(); + $encodings[$encoding] = $ret; + return $ret; + } + + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/EntityLookup.php b/extlib/HTMLPurifier/HTMLPurifier/EntityLookup.php new file mode 100644 index 0000000000..b4dfce94c3 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/EntityLookup.php @@ -0,0 +1,44 @@ +table = unserialize(file_get_contents($file)); + } + + /** + * Retrieves sole instance of the object. + * @param Optional prototype of custom lookup table to overload with. + */ + public static function instance($prototype = false) { + // no references, since PHP doesn't copy unless modified + static $instance = null; + if ($prototype) { + $instance = $prototype; + } elseif (!$instance) { + $instance = new HTMLPurifier_EntityLookup(); + $instance->setup(); + } + return $instance; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/EntityLookup/entities.ser b/extlib/HTMLPurifier/HTMLPurifier/EntityLookup/entities.ser new file mode 100644 index 0000000000..f2b8b8f2db --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/EntityLookup/entities.ser @@ -0,0 +1 @@ +a:246:{s:4:"nbsp";s:2:" ";s:5:"iexcl";s:2:"¡";s:4:"cent";s:2:"¢";s:5:"pound";s:2:"£";s:6:"curren";s:2:"¤";s:3:"yen";s:2:"¥";s:6:"brvbar";s:2:"¦";s:4:"sect";s:2:"§";s:3:"uml";s:2:"¨";s:4:"copy";s:2:"©";s:4:"ordf";s:2:"ª";s:5:"laquo";s:2:"«";s:3:"not";s:2:"¬";s:3:"shy";s:2:"­";s:3:"reg";s:2:"®";s:4:"macr";s:2:"¯";s:3:"deg";s:2:"°";s:6:"plusmn";s:2:"±";s:5:"acute";s:2:"´";s:5:"micro";s:2:"µ";s:4:"para";s:2:"¶";s:6:"middot";s:2:"·";s:5:"cedil";s:2:"¸";s:4:"ordm";s:2:"º";s:5:"raquo";s:2:"»";s:6:"iquest";s:2:"¿";s:6:"Agrave";s:2:"À";s:6:"Aacute";s:2:"Á";s:5:"Acirc";s:2:"Â";s:6:"Atilde";s:2:"Ã";s:4:"Auml";s:2:"Ä";s:5:"Aring";s:2:"Å";s:5:"AElig";s:2:"Æ";s:6:"Ccedil";s:2:"Ç";s:6:"Egrave";s:2:"È";s:6:"Eacute";s:2:"É";s:5:"Ecirc";s:2:"Ê";s:4:"Euml";s:2:"Ë";s:6:"Igrave";s:2:"Ì";s:6:"Iacute";s:2:"Í";s:5:"Icirc";s:2:"Î";s:4:"Iuml";s:2:"Ï";s:3:"ETH";s:2:"Ð";s:6:"Ntilde";s:2:"Ñ";s:6:"Ograve";s:2:"Ò";s:6:"Oacute";s:2:"Ó";s:5:"Ocirc";s:2:"Ô";s:6:"Otilde";s:2:"Õ";s:4:"Ouml";s:2:"Ö";s:5:"times";s:2:"×";s:6:"Oslash";s:2:"Ø";s:6:"Ugrave";s:2:"Ù";s:6:"Uacute";s:2:"Ú";s:5:"Ucirc";s:2:"Û";s:4:"Uuml";s:2:"Ü";s:6:"Yacute";s:2:"Ý";s:5:"THORN";s:2:"Þ";s:5:"szlig";s:2:"ß";s:6:"agrave";s:2:"à";s:6:"aacute";s:2:"á";s:5:"acirc";s:2:"â";s:6:"atilde";s:2:"ã";s:4:"auml";s:2:"ä";s:5:"aring";s:2:"å";s:5:"aelig";s:2:"æ";s:6:"ccedil";s:2:"ç";s:6:"egrave";s:2:"è";s:6:"eacute";s:2:"é";s:5:"ecirc";s:2:"ê";s:4:"euml";s:2:"ë";s:6:"igrave";s:2:"ì";s:6:"iacute";s:2:"í";s:5:"icirc";s:2:"î";s:4:"iuml";s:2:"ï";s:3:"eth";s:2:"ð";s:6:"ntilde";s:2:"ñ";s:6:"ograve";s:2:"ò";s:6:"oacute";s:2:"ó";s:5:"ocirc";s:2:"ô";s:6:"otilde";s:2:"õ";s:4:"ouml";s:2:"ö";s:6:"divide";s:2:"÷";s:6:"oslash";s:2:"ø";s:6:"ugrave";s:2:"ù";s:6:"uacute";s:2:"ú";s:5:"ucirc";s:2:"û";s:4:"uuml";s:2:"ü";s:6:"yacute";s:2:"ý";s:5:"thorn";s:2:"þ";s:4:"yuml";s:2:"ÿ";s:4:"quot";s:1:""";s:3:"amp";s:1:"&";s:2:"lt";s:1:"<";s:2:"gt";s:1:">";s:4:"apos";s:1:"'";s:5:"OElig";s:2:"Œ";s:5:"oelig";s:2:"œ";s:6:"Scaron";s:2:"Š";s:6:"scaron";s:2:"š";s:4:"Yuml";s:2:"Ÿ";s:4:"circ";s:2:"ˆ";s:5:"tilde";s:2:"˜";s:4:"ensp";s:3:" ";s:4:"emsp";s:3:" ";s:6:"thinsp";s:3:" ";s:4:"zwnj";s:3:"‌";s:3:"zwj";s:3:"‍";s:3:"lrm";s:3:"‎";s:3:"rlm";s:3:"‏";s:5:"ndash";s:3:"–";s:5:"mdash";s:3:"—";s:5:"lsquo";s:3:"‘";s:5:"rsquo";s:3:"’";s:5:"sbquo";s:3:"‚";s:5:"ldquo";s:3:"“";s:5:"rdquo";s:3:"”";s:5:"bdquo";s:3:"„";s:6:"dagger";s:3:"†";s:6:"Dagger";s:3:"‡";s:6:"permil";s:3:"‰";s:6:"lsaquo";s:3:"‹";s:6:"rsaquo";s:3:"›";s:4:"euro";s:3:"€";s:4:"fnof";s:2:"ƒ";s:5:"Alpha";s:2:"Α";s:4:"Beta";s:2:"Β";s:5:"Gamma";s:2:"Γ";s:5:"Delta";s:2:"Δ";s:7:"Epsilon";s:2:"Ε";s:4:"Zeta";s:2:"Ζ";s:3:"Eta";s:2:"Η";s:5:"Theta";s:2:"Θ";s:4:"Iota";s:2:"Ι";s:5:"Kappa";s:2:"Κ";s:6:"Lambda";s:2:"Λ";s:2:"Mu";s:2:"Μ";s:2:"Nu";s:2:"Ν";s:2:"Xi";s:2:"Ξ";s:7:"Omicron";s:2:"Ο";s:2:"Pi";s:2:"Π";s:3:"Rho";s:2:"Ρ";s:5:"Sigma";s:2:"Σ";s:3:"Tau";s:2:"Τ";s:7:"Upsilon";s:2:"Υ";s:3:"Phi";s:2:"Φ";s:3:"Chi";s:2:"Χ";s:3:"Psi";s:2:"Ψ";s:5:"Omega";s:2:"Ω";s:5:"alpha";s:2:"α";s:4:"beta";s:2:"β";s:5:"gamma";s:2:"γ";s:5:"delta";s:2:"δ";s:7:"epsilon";s:2:"ε";s:4:"zeta";s:2:"ζ";s:3:"eta";s:2:"η";s:5:"theta";s:2:"θ";s:4:"iota";s:2:"ι";s:5:"kappa";s:2:"κ";s:6:"lambda";s:2:"λ";s:2:"mu";s:2:"μ";s:2:"nu";s:2:"ν";s:2:"xi";s:2:"ξ";s:7:"omicron";s:2:"ο";s:2:"pi";s:2:"π";s:3:"rho";s:2:"ρ";s:6:"sigmaf";s:2:"ς";s:5:"sigma";s:2:"σ";s:3:"tau";s:2:"τ";s:7:"upsilon";s:2:"υ";s:3:"phi";s:2:"φ";s:3:"chi";s:2:"χ";s:3:"psi";s:2:"ψ";s:5:"omega";s:2:"ω";s:8:"thetasym";s:2:"ϑ";s:5:"upsih";s:2:"ϒ";s:3:"piv";s:2:"ϖ";s:4:"bull";s:3:"•";s:6:"hellip";s:3:"…";s:5:"prime";s:3:"′";s:5:"Prime";s:3:"″";s:5:"oline";s:3:"‾";s:5:"frasl";s:3:"⁄";s:6:"weierp";s:3:"℘";s:5:"image";s:3:"ℑ";s:4:"real";s:3:"ℜ";s:5:"trade";s:3:"™";s:7:"alefsym";s:3:"ℵ";s:4:"larr";s:3:"←";s:4:"uarr";s:3:"↑";s:4:"rarr";s:3:"→";s:4:"darr";s:3:"↓";s:4:"harr";s:3:"↔";s:5:"crarr";s:3:"↵";s:4:"lArr";s:3:"⇐";s:4:"uArr";s:3:"⇑";s:4:"rArr";s:3:"⇒";s:4:"dArr";s:3:"⇓";s:4:"hArr";s:3:"⇔";s:6:"forall";s:3:"∀";s:4:"part";s:3:"∂";s:5:"exist";s:3:"∃";s:5:"empty";s:3:"∅";s:5:"nabla";s:3:"∇";s:4:"isin";s:3:"∈";s:5:"notin";s:3:"∉";s:2:"ni";s:3:"∋";s:4:"prod";s:3:"∏";s:3:"sum";s:3:"∑";s:5:"minus";s:3:"−";s:6:"lowast";s:3:"∗";s:5:"radic";s:3:"√";s:4:"prop";s:3:"∝";s:5:"infin";s:3:"∞";s:3:"ang";s:3:"∠";s:3:"and";s:3:"∧";s:2:"or";s:3:"∨";s:3:"cap";s:3:"∩";s:3:"cup";s:3:"∪";s:3:"int";s:3:"∫";s:3:"sim";s:3:"∼";s:4:"cong";s:3:"≅";s:5:"asymp";s:3:"≈";s:2:"ne";s:3:"≠";s:5:"equiv";s:3:"≡";s:2:"le";s:3:"≤";s:2:"ge";s:3:"≥";s:3:"sub";s:3:"⊂";s:3:"sup";s:3:"⊃";s:4:"nsub";s:3:"⊄";s:4:"sube";s:3:"⊆";s:4:"supe";s:3:"⊇";s:5:"oplus";s:3:"⊕";s:6:"otimes";s:3:"⊗";s:4:"perp";s:3:"⊥";s:4:"sdot";s:3:"⋅";s:5:"lceil";s:3:"⌈";s:5:"rceil";s:3:"⌉";s:6:"lfloor";s:3:"⌊";s:6:"rfloor";s:3:"⌋";s:4:"lang";s:3:"〈";s:4:"rang";s:3:"〉";s:3:"loz";s:3:"◊";s:6:"spades";s:3:"♠";s:5:"clubs";s:3:"♣";s:6:"hearts";s:3:"♥";s:5:"diams";s:3:"♦";} \ No newline at end of file diff --git a/extlib/HTMLPurifier/HTMLPurifier/EntityParser.php b/extlib/HTMLPurifier/HTMLPurifier/EntityParser.php new file mode 100644 index 0000000000..8c384472dc --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/EntityParser.php @@ -0,0 +1,144 @@ + '"', + 38 => '&', + 39 => "'", + 60 => '<', + 62 => '>' + ); + + /** + * Stripped entity names to decimal conversion table for special entities. + */ + protected $_special_ent2dec = + array( + 'quot' => 34, + 'amp' => 38, + 'lt' => 60, + 'gt' => 62 + ); + + /** + * Substitutes non-special entities with their parsed equivalents. Since + * running this whenever you have parsed character is t3h 5uck, we run + * it before everything else. + * + * @param $string String to have non-special entities parsed. + * @returns Parsed string. + */ + public function substituteNonSpecialEntities($string) { + // it will try to detect missing semicolons, but don't rely on it + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'nonSpecialEntityCallback'), + $string + ); + } + + /** + * Callback function for substituteNonSpecialEntities() that does the work. + * + * @param $matches PCRE matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @returns Replacement string. + */ + + protected function nonSpecialEntityCallback($matches) { + // replaces all but big five + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $code = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + + // abort for special characters + if (isset($this->_special_dec2str[$code])) return $entity; + + return HTMLPurifier_Encoder::unichr($code); + } else { + if (isset($this->_special_ent2dec[$matches[3]])) return $entity; + if (!$this->_entity_lookup) { + $this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); + } + if (isset($this->_entity_lookup->table[$matches[3]])) { + return $this->_entity_lookup->table[$matches[3]]; + } else { + return $entity; + } + } + } + + /** + * Substitutes only special entities with their parsed equivalents. + * + * @notice We try to avoid calling this function because otherwise, it + * would have to be called a lot (for every parsed section). + * + * @param $string String to have non-special entities parsed. + * @returns Parsed string. + */ + public function substituteSpecialEntities($string) { + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'specialEntityCallback'), + $string); + } + + /** + * Callback function for substituteSpecialEntities() that does the work. + * + * This callback has same syntax as nonSpecialEntityCallback(). + * + * @param $matches PCRE-style matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @returns Replacement string. + */ + protected function specialEntityCallback($matches) { + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $int = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + return isset($this->_special_dec2str[$int]) ? + $this->_special_dec2str[$int] : + $entity; + } else { + return isset($this->_special_ent2dec[$matches[3]]) ? + $this->_special_ent2dec[$matches[3]] : + $entity; + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ErrorCollector.php b/extlib/HTMLPurifier/HTMLPurifier/ErrorCollector.php new file mode 100644 index 0000000000..6713eaf773 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ErrorCollector.php @@ -0,0 +1,209 @@ +locale =& $context->get('Locale'); + $this->context = $context; + $this->_current =& $this->_stacks[0]; + $this->errors =& $this->_stacks[0]; + } + + /** + * Sends an error message to the collector for later use + * @param $severity int Error severity, PHP error style (don't use E_USER_) + * @param $msg string Error message text + * @param $subst1 string First substitution for $msg + * @param $subst2 string ... + */ + public function send($severity, $msg) { + + $args = array(); + if (func_num_args() > 2) { + $args = func_get_args(); + array_shift($args); + unset($args[0]); + } + + $token = $this->context->get('CurrentToken', true); + $line = $token ? $token->line : $this->context->get('CurrentLine', true); + $col = $token ? $token->col : $this->context->get('CurrentCol', true); + $attr = $this->context->get('CurrentAttr', true); + + // perform special substitutions, also add custom parameters + $subst = array(); + if (!is_null($token)) { + $args['CurrentToken'] = $token; + } + if (!is_null($attr)) { + $subst['$CurrentAttr.Name'] = $attr; + if (isset($token->attr[$attr])) $subst['$CurrentAttr.Value'] = $token->attr[$attr]; + } + + if (empty($args)) { + $msg = $this->locale->getMessage($msg); + } else { + $msg = $this->locale->formatMessage($msg, $args); + } + + if (!empty($subst)) $msg = strtr($msg, $subst); + + // (numerically indexed) + $error = array( + self::LINENO => $line, + self::SEVERITY => $severity, + self::MESSAGE => $msg, + self::CHILDREN => array() + ); + $this->_current[] = $error; + + + // NEW CODE BELOW ... + + $struct = null; + // Top-level errors are either: + // TOKEN type, if $value is set appropriately, or + // "syntax" type, if $value is null + $new_struct = new HTMLPurifier_ErrorStruct(); + $new_struct->type = HTMLPurifier_ErrorStruct::TOKEN; + if ($token) $new_struct->value = clone $token; + if (is_int($line) && is_int($col)) { + if (isset($this->lines[$line][$col])) { + $struct = $this->lines[$line][$col]; + } else { + $struct = $this->lines[$line][$col] = $new_struct; + } + // These ksorts may present a performance problem + ksort($this->lines[$line], SORT_NUMERIC); + } else { + if (isset($this->lines[-1])) { + $struct = $this->lines[-1]; + } else { + $struct = $this->lines[-1] = $new_struct; + } + } + ksort($this->lines, SORT_NUMERIC); + + // Now, check if we need to operate on a lower structure + if (!empty($attr)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr); + if (!$struct->value) { + $struct->value = array($attr, 'PUT VALUE HERE'); + } + } + if (!empty($cssprop)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop); + if (!$struct->value) { + // if we tokenize CSS this might be a little more difficult to do + $struct->value = array($cssprop, 'PUT VALUE HERE'); + } + } + + // Ok, structs are all setup, now time to register the error + $struct->addError($severity, $msg); + } + + /** + * Retrieves raw error data for custom formatter to use + * @param List of arrays in format of array(line of error, + * error severity, error message, + * recursive sub-errors array) + */ + public function getRaw() { + return $this->errors; + } + + /** + * Default HTML formatting implementation for error messages + * @param $config Configuration array, vital for HTML output nature + * @param $errors Errors array to display; used for recursion. + */ + public function getHTMLFormatted($config, $errors = null) { + $ret = array(); + + $this->generator = new HTMLPurifier_Generator($config, $this->context); + if ($errors === null) $errors = $this->errors; + + // 'At line' message needs to be removed + + // generation code for new structure goes here. It needs to be recursive. + foreach ($this->lines as $line => $col_array) { + if ($line == -1) continue; + foreach ($col_array as $col => $struct) { + $this->_renderStruct($ret, $struct, $line, $col); + } + } + if (isset($this->lines[-1])) { + $this->_renderStruct($ret, $this->lines[-1]); + } + + if (empty($errors)) { + return '

' . $this->locale->getMessage('ErrorCollector: No errors') . '

'; + } else { + return '
  • ' . implode('
  • ', $ret) . '
'; + } + + } + + private function _renderStruct(&$ret, $struct, $line = null, $col = null) { + $stack = array($struct); + $context_stack = array(array()); + while ($current = array_pop($stack)) { + $context = array_pop($context_stack); + foreach ($current->errors as $error) { + list($severity, $msg) = $error; + $string = ''; + $string .= '
'; + // W3C uses an icon to indicate the severity of the error. + $error = $this->locale->getErrorName($severity); + $string .= "$error "; + if (!is_null($line) && !is_null($col)) { + $string .= "Line $line, Column $col: "; + } else { + $string .= 'End of Document: '; + } + $string .= '' . $this->generator->escape($msg) . ' '; + $string .= '
'; + // Here, have a marker for the character on the column appropriate. + // Be sure to clip extremely long lines. + //$string .= '
';
+                //$string .= '';
+                //$string .= '
'; + $ret[] = $string; + } + foreach ($current->children as $type => $array) { + $context[] = $current; + $stack = array_merge($stack, array_reverse($array, true)); + for ($i = count($array); $i > 0; $i--) { + $context_stack[] = $context; + } + } + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/ErrorStruct.php b/extlib/HTMLPurifier/HTMLPurifier/ErrorStruct.php new file mode 100644 index 0000000000..9bc8996ec1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/ErrorStruct.php @@ -0,0 +1,60 @@ +children[$type][$id])) { + $this->children[$type][$id] = new HTMLPurifier_ErrorStruct(); + $this->children[$type][$id]->type = $type; + } + return $this->children[$type][$id]; + } + + public function addError($severity, $message) { + $this->errors[] = array($severity, $message); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Exception.php b/extlib/HTMLPurifier/HTMLPurifier/Exception.php new file mode 100644 index 0000000000..be85b4c560 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Exception.php @@ -0,0 +1,12 @@ +preFilter, + * 2->preFilter, 3->preFilter, purify, 3->postFilter, 2->postFilter, + * 1->postFilter. + * + * @note Methods are not declared abstract as it is perfectly legitimate + * for an implementation not to want anything to happen on a step + */ + +class HTMLPurifier_Filter +{ + + /** + * Name of the filter for identification purposes + */ + public $name; + + /** + * Pre-processor function, handles HTML before HTML Purifier + */ + public function preFilter($html, $config, $context) { + return $html; + } + + /** + * Post-processor function, handles HTML after HTML Purifier + */ + public function postFilter($html, $config, $context) { + return $html; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php b/extlib/HTMLPurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php new file mode 100644 index 0000000000..bbf78a6630 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -0,0 +1,135 @@ + blocks from input HTML, cleans them up + * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks') + * so they can be used elsewhere in the document. + * + * @note + * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for + * sample usage. + * + * @note + * This filter can also be used on stylesheets not included in the + * document--something purists would probably prefer. Just directly + * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS() + */ +class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter +{ + + public $name = 'ExtractStyleBlocks'; + private $_styleMatches = array(); + private $_tidy; + + public function __construct() { + $this->_tidy = new csstidy(); + } + + /** + * Save the contents of CSS blocks to style matches + * @param $matches preg_replace style $matches array + */ + protected function styleCallback($matches) { + $this->_styleMatches[] = $matches[1]; + } + + /** + * Removes inline #isU', array($this, 'styleCallback'), $html); + $style_blocks = $this->_styleMatches; + $this->_styleMatches = array(); // reset + $context->register('StyleBlocks', $style_blocks); // $context must not be reused + if ($this->_tidy) { + foreach ($style_blocks as &$style) { + $style = $this->cleanCSS($style, $config, $context); + } + } + return $html; + } + + /** + * Takes CSS (the stuff found in in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Filter/YouTube.php b/extlib/HTMLPurifier/HTMLPurifier/Filter/YouTube.php new file mode 100644 index 0000000000..aca972f6c5 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Filter/YouTube.php @@ -0,0 +1,39 @@ +]+>.+?'. + 'http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?#s'; + $pre_replace = '\1'; + return preg_replace($pre_regex, $pre_replace, $html); + } + + public function postFilter($html, $config, $context) { + $post_regex = '#([A-Za-z0-9\-_]+)#'; + return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); + } + + protected function armorUrl($url) { + return str_replace('--', '--', $url); + } + + protected function postFilterCallback($matches) { + $url = $this->armorUrl($matches[1]); + return ''. + ''. + ''. + ''; + + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Generator.php b/extlib/HTMLPurifier/HTMLPurifier/Generator.php new file mode 100644 index 0000000000..24bd8a54ed --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Generator.php @@ -0,0 +1,183 @@ + tags + */ + private $_scriptFix = false; + + /** + * Cache of HTMLDefinition during HTML output to determine whether or + * not attributes should be minimized. + */ + private $_def; + + /** + * Cache of %Output.SortAttr + */ + private $_sortAttr; + + /** + * Configuration for the generator + */ + protected $config; + + /** + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + */ + public function __construct($config, $context) { + $this->config = $config; + $this->_scriptFix = $config->get('Output.CommentScriptContents'); + $this->_sortAttr = $config->get('Output.SortAttr'); + $this->_def = $config->getHTMLDefinition(); + $this->_xhtml = $this->_def->doctype->xml; + } + + /** + * Generates HTML from an array of tokens. + * @param $tokens Array of HTMLPurifier_Token + * @param $config HTMLPurifier_Config object + * @return Generated HTML + */ + public function generateFromTokens($tokens) { + if (!$tokens) return ''; + + // Basic algorithm + $html = ''; + for ($i = 0, $size = count($tokens); $i < $size; $i++) { + if ($this->_scriptFix && $tokens[$i]->name === 'script' + && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) { + // script special case + // the contents of the script block must be ONE token + // for this to work. + $html .= $this->generateFromToken($tokens[$i++]); + $html .= $this->generateScriptFromToken($tokens[$i++]); + } + $html .= $this->generateFromToken($tokens[$i]); + } + + // Tidy cleanup + if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) { + $tidy = new Tidy; + $tidy->parseString($html, array( + 'indent'=> true, + 'output-xhtml' => $this->_xhtml, + 'show-body-only' => true, + 'indent-spaces' => 2, + 'wrap' => 68, + ), 'utf8'); + $tidy->cleanRepair(); + $html = (string) $tidy; // explicit cast necessary + } + + // Normalize newlines to system defined value + $nl = $this->config->get('Output.Newline'); + if ($nl === null) $nl = PHP_EOL; + if ($nl !== "\n") $html = str_replace("\n", $nl, $html); + return $html; + } + + /** + * Generates HTML from a single token. + * @param $token HTMLPurifier_Token object. + * @return Generated HTML + */ + public function generateFromToken($token) { + if (!$token instanceof HTMLPurifier_Token) { + trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING); + return ''; + + } elseif ($token instanceof HTMLPurifier_Token_Start) { + $attr = $this->generateAttributes($token->attr, $token->name); + return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_End) { + return 'name . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + $attr = $this->generateAttributes($token->attr, $token->name); + return '<' . $token->name . ($attr ? ' ' : '') . $attr . + ( $this->_xhtml ? ' /': '' ) //
v.
+ . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Text) { + return $this->escape($token->data, ENT_NOQUOTES); + + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + return ''; + } else { + return ''; + + } + } + + /** + * Special case processor for the contents of script tags + * @warning This runs into problems if there's already a literal + * --> somewhere inside the script contents. + */ + public function generateScriptFromToken($token) { + if (!$token instanceof HTMLPurifier_Token_Text) return $this->generateFromToken($token); + // Thanks + $data = preg_replace('#//\s*$#', '', $token->data); + return ''; + } + + /** + * Generates attribute declarations from attribute array. + * @note This does not include the leading or trailing space. + * @param $assoc_array_of_attributes Attribute array + * @param $element Name of element attributes are for, used to check + * attribute minimization. + * @return Generate HTML fragment for insertion. + */ + public function generateAttributes($assoc_array_of_attributes, $element = false) { + $html = ''; + if ($this->_sortAttr) ksort($assoc_array_of_attributes); + foreach ($assoc_array_of_attributes as $key => $value) { + if (!$this->_xhtml) { + // Remove namespaced attributes + if (strpos($key, ':') !== false) continue; + // Check if we should minimize the attribute: val="val" -> val + if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) { + $html .= $key . ' '; + continue; + } + } + $html .= $key.'="'.$this->escape($value).'" '; + } + return rtrim($html); + } + + /** + * Escapes raw text data. + * @todo This really ought to be protected, but until we have a facility + * for properly generating HTML here w/o using tokens, it stays + * public. + * @param $string String data to escape for HTML. + * @param $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is + * permissible for non-attribute output. + * @return String escaped data. + */ + public function escape($string, $quote = ENT_COMPAT) { + return htmlspecialchars($string, $quote, 'UTF-8'); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLDefinition.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLDefinition.php new file mode 100644 index 0000000000..c99ac11eb2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLDefinition.php @@ -0,0 +1,420 @@ +getAnonymousModule(); + if (!isset($module->info[$element_name])) { + $element = $module->addBlankElement($element_name); + } else { + $element = $module->info[$element_name]; + } + $element->attr[$attr_name] = $def; + } + + /** + * Adds a custom element to your HTML definition + * @note See HTMLPurifier_HTMLModule::addElement for detailed + * parameter and return value descriptions. + */ + public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array()) { + $module = $this->getAnonymousModule(); + // assume that if the user is calling this, the element + // is safe. This may not be a good idea + $element = $module->addElement($element_name, $type, $contents, $attr_collections, $attributes); + return $element; + } + + /** + * Adds a blank element to your HTML definition, for overriding + * existing behavior + * @note See HTMLPurifier_HTMLModule::addBlankElement for detailed + * parameter and return value descriptions. + */ + public function addBlankElement($element_name) { + $module = $this->getAnonymousModule(); + $element = $module->addBlankElement($element_name); + return $element; + } + + /** + * Retrieves a reference to the anonymous module, so you can + * bust out advanced features without having to make your own + * module. + */ + public function getAnonymousModule() { + if (!$this->_anonModule) { + $this->_anonModule = new HTMLPurifier_HTMLModule(); + $this->_anonModule->name = 'Anonymous'; + } + return $this->_anonModule; + } + + private $_anonModule; + + + // PUBLIC BUT INTERNAL VARIABLES -------------------------------------- + + public $type = 'HTML'; + public $manager; /**< Instance of HTMLPurifier_HTMLModuleManager */ + + /** + * Performs low-cost, preliminary initialization. + */ + public function __construct() { + $this->manager = new HTMLPurifier_HTMLModuleManager(); + } + + protected function doSetup($config) { + $this->processModules($config); + $this->setupConfigStuff($config); + unset($this->manager); + + // cleanup some of the element definitions + foreach ($this->info as $k => $v) { + unset($this->info[$k]->content_model); + unset($this->info[$k]->content_model_type); + } + } + + /** + * Extract out the information from the manager + */ + protected function processModules($config) { + + if ($this->_anonModule) { + // for user specific changes + // this is late-loaded so we don't have to deal with PHP4 + // reference wonky-ness + $this->manager->addModule($this->_anonModule); + unset($this->_anonModule); + } + + $this->manager->setup($config); + $this->doctype = $this->manager->doctype; + + foreach ($this->manager->modules as $module) { + foreach($module->info_tag_transform as $k => $v) { + if ($v === false) unset($this->info_tag_transform[$k]); + else $this->info_tag_transform[$k] = $v; + } + foreach($module->info_attr_transform_pre as $k => $v) { + if ($v === false) unset($this->info_attr_transform_pre[$k]); + else $this->info_attr_transform_pre[$k] = $v; + } + foreach($module->info_attr_transform_post as $k => $v) { + if ($v === false) unset($this->info_attr_transform_post[$k]); + else $this->info_attr_transform_post[$k] = $v; + } + foreach ($module->info_injector as $k => $v) { + if ($v === false) unset($this->info_injector[$k]); + else $this->info_injector[$k] = $v; + } + } + + $this->info = $this->manager->getElements(); + $this->info_content_sets = $this->manager->contentSets->lookup; + + } + + /** + * Sets up stuff based on config. We need a better way of doing this. + */ + protected function setupConfigStuff($config) { + + $block_wrapper = $config->get('HTML.BlockWrapper'); + if (isset($this->info_content_sets['Block'][$block_wrapper])) { + $this->info_block_wrapper = $block_wrapper; + } else { + trigger_error('Cannot use non-block element as block wrapper', + E_USER_ERROR); + } + + $parent = $config->get('HTML.Parent'); + $def = $this->manager->getElement($parent, true); + if ($def) { + $this->info_parent = $parent; + $this->info_parent_def = $def; + } else { + trigger_error('Cannot use unrecognized element as parent', + E_USER_ERROR); + $this->info_parent_def = $this->manager->getElement($this->info_parent, true); + } + + // support template text + $support = "(for information on implementing this, see the ". + "support forums) "; + + // setup allowed elements ----------------------------------------- + + $allowed_elements = $config->get('HTML.AllowedElements'); + $allowed_attributes = $config->get('HTML.AllowedAttributes'); // retrieve early + + if (!is_array($allowed_elements) && !is_array($allowed_attributes)) { + $allowed = $config->get('HTML.Allowed'); + if (is_string($allowed)) { + list($allowed_elements, $allowed_attributes) = $this->parseTinyMCEAllowedList($allowed); + } + } + + if (is_array($allowed_elements)) { + foreach ($this->info as $name => $d) { + if(!isset($allowed_elements[$name])) unset($this->info[$name]); + unset($allowed_elements[$name]); + } + // emit errors + foreach ($allowed_elements as $element => $d) { + $element = htmlspecialchars($element); // PHP doesn't escape errors, be careful! + trigger_error("Element '$element' is not supported $support", E_USER_WARNING); + } + } + + // setup allowed attributes --------------------------------------- + + $allowed_attributes_mutable = $allowed_attributes; // by copy! + if (is_array($allowed_attributes)) { + + // This actually doesn't do anything, since we went away from + // global attributes. It's possible that userland code uses + // it, but HTMLModuleManager doesn't! + foreach ($this->info_global_attr as $attr => $x) { + $keys = array($attr, "*@$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) unset($this->info_global_attr[$attr]); + } + + foreach ($this->info as $tag => $info) { + foreach ($info->attr as $attr => $x) { + $keys = array("$tag@$attr", $attr, "*@$attr", "$tag.$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) unset($this->info[$tag]->attr[$attr]); + } + } + // emit errors + foreach ($allowed_attributes_mutable as $elattr => $d) { + $bits = preg_split('/[.@]/', $elattr, 2); + $c = count($bits); + switch ($c) { + case 2: + if ($bits[0] !== '*') { + $element = htmlspecialchars($bits[0]); + $attribute = htmlspecialchars($bits[1]); + if (!isset($this->info[$element])) { + trigger_error("Cannot allow attribute '$attribute' if element '$element' is not allowed/supported $support"); + } else { + trigger_error("Attribute '$attribute' in element '$element' not supported $support", + E_USER_WARNING); + } + break; + } + // otherwise fall through + case 1: + $attribute = htmlspecialchars($bits[0]); + trigger_error("Global attribute '$attribute' is not ". + "supported in any elements $support", + E_USER_WARNING); + break; + } + } + + } + + // setup forbidden elements --------------------------------------- + + $forbidden_elements = $config->get('HTML.ForbiddenElements'); + $forbidden_attributes = $config->get('HTML.ForbiddenAttributes'); + + foreach ($this->info as $tag => $info) { + if (isset($forbidden_elements[$tag])) { + unset($this->info[$tag]); + continue; + } + foreach ($info->attr as $attr => $x) { + if ( + isset($forbidden_attributes["$tag@$attr"]) || + isset($forbidden_attributes["*@$attr"]) || + isset($forbidden_attributes[$attr]) + ) { + unset($this->info[$tag]->attr[$attr]); + continue; + } // this segment might get removed eventually + elseif (isset($forbidden_attributes["$tag.$attr"])) { + // $tag.$attr are not user supplied, so no worries! + trigger_error("Error with $tag.$attr: tag.attr syntax not supported for HTML.ForbiddenAttributes; use tag@attr instead", E_USER_WARNING); + } + } + } + foreach ($forbidden_attributes as $key => $v) { + if (strlen($key) < 2) continue; + if ($key[0] != '*') continue; + if ($key[1] == '.') { + trigger_error("Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", E_USER_WARNING); + } + } + + // setup injectors ----------------------------------------------------- + foreach ($this->info_injector as $i => $injector) { + if ($injector->checkNeeded($config) !== false) { + // remove injector that does not have it's required + // elements/attributes present, and is thus not needed. + unset($this->info_injector[$i]); + } + } + } + + /** + * Parses a TinyMCE-flavored Allowed Elements and Attributes list into + * separate lists for processing. Format is element[attr1|attr2],element2... + * @warning Although it's largely drawn from TinyMCE's implementation, + * it is different, and you'll probably have to modify your lists + * @param $list String list to parse + * @param array($allowed_elements, $allowed_attributes) + * @todo Give this its own class, probably static interface + */ + public function parseTinyMCEAllowedList($list) { + + $list = str_replace(array(' ', "\t"), '', $list); + + $elements = array(); + $attributes = array(); + + $chunks = preg_split('/(,|[\n\r]+)/', $list); + foreach ($chunks as $chunk) { + if (empty($chunk)) continue; + // remove TinyMCE element control characters + if (!strpos($chunk, '[')) { + $element = $chunk; + $attr = false; + } else { + list($element, $attr) = explode('[', $chunk); + } + if ($element !== '*') $elements[$element] = true; + if (!$attr) continue; + $attr = substr($attr, 0, strlen($attr) - 1); // remove trailing ] + $attr = explode('|', $attr); + foreach ($attr as $key) { + $attributes["$element.$key"] = true; + } + } + + return array($elements, $attributes); + + } + + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule.php new file mode 100644 index 0000000000..072cf68084 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule.php @@ -0,0 +1,244 @@ +info, since the object's data is only info, + * with extra behavior associated with it. + */ + public $attr_collections = array(); + + /** + * Associative array of deprecated tag name to HTMLPurifier_TagTransform + */ + public $info_tag_transform = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed before validation. + */ + public $info_attr_transform_pre = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed after validation. + */ + public $info_attr_transform_post = array(); + + /** + * List of HTMLPurifier_Injector to be performed during well-formedness fixing. + * An injector will only be invoked if all of it's pre-requisites are met; + * if an injector fails setup, there will be no error; it will simply be + * silently disabled. + */ + public $info_injector = array(); + + /** + * Boolean flag that indicates whether or not getChildDef is implemented. + * For optimization reasons: may save a call to a function. Be sure + * to set it if you do implement getChildDef(), otherwise it will have + * no effect! + */ + public $defines_child_def = false; + + /** + * Boolean flag whether or not this module is safe. If it is not safe, all + * of its members are unsafe. Modules are safe by default (this might be + * slightly dangerous, but it doesn't make much sense to force HTML Purifier, + * which is based off of safe HTML, to explicitly say, "This is safe," even + * though there are modules which are "unsafe") + * + * @note Previously, safety could be applied at an element level granularity. + * We've removed this ability, so in order to add "unsafe" elements + * or attributes, a dedicated module with this property set to false + * must be used. + */ + public $safe = true; + + /** + * Retrieves a proper HTMLPurifier_ChildDef subclass based on + * content_model and content_model_type member variables of + * the HTMLPurifier_ElementDef class. There is a similar function + * in HTMLPurifier_HTMLDefinition. + * @param $def HTMLPurifier_ElementDef instance + * @return HTMLPurifier_ChildDef subclass + */ + public function getChildDef($def) {return false;} + + // -- Convenience ----------------------------------------------------- + + /** + * Convenience function that sets up a new element + * @param $element Name of element to add + * @param $type What content set should element be registered to? + * Set as false to skip this step. + * @param $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @param $attr_includes What attribute collections to register to + * element? + * @param $attr What unique attributes does the element define? + * @note See ElementDef for in-depth descriptions of these parameters. + * @return Created element definition object, so you + * can set advanced parameters + */ + public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) { + $this->elements[] = $element; + // parse content_model + list($content_model_type, $content_model) = $this->parseContents($contents); + // merge in attribute inclusions + $this->mergeInAttrIncludes($attr, $attr_includes); + // add element to content sets + if ($type) $this->addElementToContentSet($element, $type); + // create element + $this->info[$element] = HTMLPurifier_ElementDef::create( + $content_model, $content_model_type, $attr + ); + // literal object $contents means direct child manipulation + if (!is_string($contents)) $this->info[$element]->child = $contents; + return $this->info[$element]; + } + + /** + * Convenience function that creates a totally blank, non-standalone + * element. + * @param $element Name of element to create + * @return Created element + */ + public function addBlankElement($element) { + if (!isset($this->info[$element])) { + $this->elements[] = $element; + $this->info[$element] = new HTMLPurifier_ElementDef(); + $this->info[$element]->standalone = false; + } else { + trigger_error("Definition for $element already exists in module, cannot redefine"); + } + return $this->info[$element]; + } + + /** + * Convenience function that registers an element to a content set + * @param Element to register + * @param Name content set (warning: case sensitive, usually upper-case + * first letter) + */ + public function addElementToContentSet($element, $type) { + if (!isset($this->content_sets[$type])) $this->content_sets[$type] = ''; + else $this->content_sets[$type] .= ' | '; + $this->content_sets[$type] .= $element; + } + + /** + * Convenience function that transforms single-string contents + * into separate content model and content model type + * @param $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @note If contents is an object, an array of two nulls will be + * returned, and the callee needs to take the original $contents + * and use it directly. + */ + public function parseContents($contents) { + if (!is_string($contents)) return array(null, null); // defer + switch ($contents) { + // check for shorthand content model forms + case 'Empty': + return array('empty', ''); + case 'Inline': + return array('optional', 'Inline | #PCDATA'); + case 'Flow': + return array('optional', 'Flow | #PCDATA'); + } + list($content_model_type, $content_model) = explode(':', $contents); + $content_model_type = strtolower(trim($content_model_type)); + $content_model = trim($content_model); + return array($content_model_type, $content_model); + } + + /** + * Convenience function that merges a list of attribute includes into + * an attribute array. + * @param $attr Reference to attr array to modify + * @param $attr_includes Array of includes / string include to merge in + */ + public function mergeInAttrIncludes(&$attr, $attr_includes) { + if (!is_array($attr_includes)) { + if (empty($attr_includes)) $attr_includes = array(); + else $attr_includes = array($attr_includes); + } + $attr[0] = $attr_includes; + } + + /** + * Convenience function that generates a lookup table with boolean + * true as value. + * @param $list List of values to turn into a lookup + * @note You can also pass an arbitrary number of arguments in + * place of the regular argument + * @return Lookup array equivalent of list + */ + public function makeLookup($list) { + if (is_string($list)) $list = func_get_args(); + $ret = array(); + foreach ($list as $value) { + if (is_null($value)) continue; + $ret[$value] = true; + } + return $ret; + } + + /** + * Lazy load construction of the module after determining whether + * or not it's needed, and also when a finalized configuration object + * is available. + * @param $config Instance of HTMLPurifier_Config + */ + public function setup($config) {} + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php new file mode 100644 index 0000000000..3d66f1b4e1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php @@ -0,0 +1,31 @@ + array('dir' => false) + ); + + public function setup($config) { + $bdo = $this->addElement( + 'bdo', 'Inline', 'Inline', array('Core', 'Lang'), + array( + 'dir' => 'Enum#ltr,rtl', // required + // The Abstract Module specification has the attribute + // inclusions wrong for bdo: bdo allows Lang + ) + ); + $bdo->attr_transform_post['required-dir'] = new HTMLPurifier_AttrTransform_BdoDir(); + + $this->attr_collections['I18N']['dir'] = 'Enum#ltr,rtl'; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/CommonAttributes.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/CommonAttributes.php new file mode 100644 index 0000000000..7c15da84fc --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/CommonAttributes.php @@ -0,0 +1,26 @@ + array( + 0 => array('Style'), + // 'xml:space' => false, + 'class' => 'Class', + 'id' => 'ID', + 'title' => 'CDATA', + ), + 'Lang' => array(), + 'I18N' => array( + 0 => array('Lang'), // proprietary, for xml:lang/lang + ), + 'Common' => array( + 0 => array('Core', 'I18N') + ) + ); + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Edit.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Edit.php new file mode 100644 index 0000000000..ff93690555 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Edit.php @@ -0,0 +1,38 @@ + 'URI', + // 'datetime' => 'Datetime', // not implemented + ); + $this->addElement('del', 'Inline', $contents, 'Common', $attr); + $this->addElement('ins', 'Inline', $contents, 'Common', $attr); + } + + // HTML 4.01 specifies that ins/del must not contain block + // elements when used in an inline context, chameleon is + // a complicated workaround to acheive this effect + + // Inline context ! Block context (exclamation mark is + // separator, see getChildDef for parsing) + + public $defines_child_def = true; + public function getChildDef($def) { + if ($def->content_model_type != 'chameleon') return false; + $value = explode('!', $def->content_model); + return new HTMLPurifier_ChildDef_Chameleon($value[0], $value[1]); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Forms.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Forms.php new file mode 100644 index 0000000000..44c22f6f8b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Forms.php @@ -0,0 +1,118 @@ + 'Form', + 'Inline' => 'Formctrl', + ); + + public function setup($config) { + $form = $this->addElement('form', 'Form', + 'Required: Heading | List | Block | fieldset', 'Common', array( + 'accept' => 'ContentTypes', + 'accept-charset' => 'Charsets', + 'action*' => 'URI', + 'method' => 'Enum#get,post', + // really ContentType, but these two are the only ones used today + 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data', + )); + $form->excludes = array('form' => true); + + $input = $this->addElement('input', 'Formctrl', 'Empty', 'Common', array( + 'accept' => 'ContentTypes', + 'accesskey' => 'Character', + 'alt' => 'Text', + 'checked' => 'Bool#checked', + 'disabled' => 'Bool#disabled', + 'maxlength' => 'Number', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'size' => 'Number', + 'src' => 'URI#embeds', + 'tabindex' => 'Number', + 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image', + 'value' => 'CDATA', + )); + $input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input(); + + $this->addElement('select', 'Formctrl', 'Required: optgroup | option', 'Common', array( + 'disabled' => 'Bool#disabled', + 'multiple' => 'Bool#multiple', + 'name' => 'CDATA', + 'size' => 'Number', + 'tabindex' => 'Number', + )); + + $this->addElement('option', false, 'Optional: #PCDATA', 'Common', array( + 'disabled' => 'Bool#disabled', + 'label' => 'Text', + 'selected' => 'Bool#selected', + 'value' => 'CDATA', + )); + // It's illegal for there to be more than one selected, but not + // be multiple. Also, no selected means undefined behavior. This might + // be difficult to implement; perhaps an injector, or a context variable. + + $textarea = $this->addElement('textarea', 'Formctrl', 'Optional: #PCDATA', 'Common', array( + 'accesskey' => 'Character', + 'cols*' => 'Number', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'rows*' => 'Number', + 'tabindex' => 'Number', + )); + $textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea(); + + $button = $this->addElement('button', 'Formctrl', 'Optional: #PCDATA | Heading | List | Block | Inline', 'Common', array( + 'accesskey' => 'Character', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'tabindex' => 'Number', + 'type' => 'Enum#button,submit,reset', + 'value' => 'CDATA', + )); + + // For exclusions, ideally we'd specify content sets, not literal elements + $button->excludes = $this->makeLookup( + 'form', 'fieldset', // Form + 'input', 'select', 'textarea', 'label', 'button', // Formctrl + 'a' // as per HTML 4.01 spec, this is omitted by modularization + ); + + // Extra exclusion: img usemap="" is not permitted within this element. + // We'll omit this for now, since we don't have any good way of + // indicating it yet. + + // This is HIGHLY user-unfriendly; we need a custom child-def for this + $this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common'); + + $label = $this->addElement('label', 'Formctrl', 'Optional: #PCDATA | Inline', 'Common', array( + 'accesskey' => 'Character', + // 'for' => 'IDREF', // IDREF not implemented, cannot allow + )); + $label->excludes = array('label' => true); + + $this->addElement('legend', false, 'Optional: #PCDATA | Inline', 'Common', array( + 'accesskey' => 'Character', + )); + + $this->addElement('optgroup', false, 'Required: option', 'Common', array( + 'disabled' => 'Bool#disabled', + 'label*' => 'Text', + )); + + // Don't forget an injector for . This one's a little complex + // because it maps to multiple elements. + + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Hypertext.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Hypertext.php new file mode 100644 index 0000000000..d7e9bdd27e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Hypertext.php @@ -0,0 +1,31 @@ +addElement( + 'a', 'Inline', 'Inline', 'Common', + array( + // 'accesskey' => 'Character', + // 'charset' => 'Charset', + 'href' => 'URI', + // 'hreflang' => 'LanguageCode', + 'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'), + 'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'), + // 'tabindex' => 'Number', + // 'type' => 'ContentType', + ) + ); + $a->formatting = true; + $a->excludes = array('a' => true); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Image.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Image.php new file mode 100644 index 0000000000..948d435bcd --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Image.php @@ -0,0 +1,40 @@ +get('HTML.MaxImgLength'); + $img = $this->addElement( + 'img', 'Inline', 'Empty', 'Common', + array( + 'alt*' => 'Text', + // According to the spec, it's Length, but percents can + // be abused, so we allow only Pixels. + 'height' => 'Pixels#' . $max, + 'width' => 'Pixels#' . $max, + 'longdesc' => 'URI', + 'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded + ) + ); + if ($max === null || $config->get('HTML.Trusted')) { + $img->attr['height'] = + $img->attr['width'] = 'Length'; + } + + // kind of strange, but splitting things up would be inefficient + $img->attr_transform_pre[] = + $img->attr_transform_post[] = + new HTMLPurifier_AttrTransform_ImgRequired(); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Legacy.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Legacy.php new file mode 100644 index 0000000000..df33927ba6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Legacy.php @@ -0,0 +1,143 @@ +addElement('basefont', 'Inline', 'Empty', false, array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + 'id' => 'ID' + )); + $this->addElement('center', 'Block', 'Flow', 'Common'); + $this->addElement('dir', 'Block', 'Required: li', 'Common', array( + 'compact' => 'Bool#compact' + )); + $this->addElement('font', 'Inline', 'Inline', array('Core', 'I18N'), array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + )); + $this->addElement('menu', 'Block', 'Required: li', 'Common', array( + 'compact' => 'Bool#compact' + )); + + $s = $this->addElement('s', 'Inline', 'Inline', 'Common'); + $s->formatting = true; + + $strike = $this->addElement('strike', 'Inline', 'Inline', 'Common'); + $strike->formatting = true; + + $u = $this->addElement('u', 'Inline', 'Inline', 'Common'); + $u->formatting = true; + + // setup modifications to old elements + + $align = 'Enum#left,right,center,justify'; + + $address = $this->addBlankElement('address'); + $address->content_model = 'Inline | #PCDATA | p'; + $address->content_model_type = 'optional'; + $address->child = false; + + $blockquote = $this->addBlankElement('blockquote'); + $blockquote->content_model = 'Flow | #PCDATA'; + $blockquote->content_model_type = 'optional'; + $blockquote->child = false; + + $br = $this->addBlankElement('br'); + $br->attr['clear'] = 'Enum#left,all,right,none'; + + $caption = $this->addBlankElement('caption'); + $caption->attr['align'] = 'Enum#top,bottom,left,right'; + + $div = $this->addBlankElement('div'); + $div->attr['align'] = $align; + + $dl = $this->addBlankElement('dl'); + $dl->attr['compact'] = 'Bool#compact'; + + for ($i = 1; $i <= 6; $i++) { + $h = $this->addBlankElement("h$i"); + $h->attr['align'] = $align; + } + + $hr = $this->addBlankElement('hr'); + $hr->attr['align'] = $align; + $hr->attr['noshade'] = 'Bool#noshade'; + $hr->attr['size'] = 'Pixels'; + $hr->attr['width'] = 'Length'; + + $img = $this->addBlankElement('img'); + $img->attr['align'] = 'Enum#top,middle,bottom,left,right'; + $img->attr['border'] = 'Pixels'; + $img->attr['hspace'] = 'Pixels'; + $img->attr['vspace'] = 'Pixels'; + + // figure out this integer business + + $li = $this->addBlankElement('li'); + $li->attr['value'] = new HTMLPurifier_AttrDef_Integer(); + $li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle'; + + $ol = $this->addBlankElement('ol'); + $ol->attr['compact'] = 'Bool#compact'; + $ol->attr['start'] = new HTMLPurifier_AttrDef_Integer(); + $ol->attr['type'] = 'Enum#s:1,i,I,a,A'; + + $p = $this->addBlankElement('p'); + $p->attr['align'] = $align; + + $pre = $this->addBlankElement('pre'); + $pre->attr['width'] = 'Number'; + + // script omitted + + $table = $this->addBlankElement('table'); + $table->attr['align'] = 'Enum#left,center,right'; + $table->attr['bgcolor'] = 'Color'; + + $tr = $this->addBlankElement('tr'); + $tr->attr['bgcolor'] = 'Color'; + + $th = $this->addBlankElement('th'); + $th->attr['bgcolor'] = 'Color'; + $th->attr['height'] = 'Length'; + $th->attr['nowrap'] = 'Bool#nowrap'; + $th->attr['width'] = 'Length'; + + $td = $this->addBlankElement('td'); + $td->attr['bgcolor'] = 'Color'; + $td->attr['height'] = 'Length'; + $td->attr['nowrap'] = 'Bool#nowrap'; + $td->attr['width'] = 'Length'; + + $ul = $this->addBlankElement('ul'); + $ul->attr['compact'] = 'Bool#compact'; + $ul->attr['type'] = 'Enum#square,disc,circle'; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/List.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/List.php new file mode 100644 index 0000000000..1d15f27293 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/List.php @@ -0,0 +1,35 @@ + 'List'); + + public function setup($config) { + $this->addElement('ol', 'List', 'Required: li', 'Common'); + $this->addElement('ul', 'List', 'Required: li', 'Common'); + $this->addElement('dl', 'List', 'Required: dt | dd', 'Common'); + + $this->addElement('li', false, 'Flow', 'Common'); + + $this->addElement('dd', false, 'Flow', 'Common'); + $this->addElement('dt', false, 'Inline', 'Common'); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php new file mode 100644 index 0000000000..05694b4504 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php @@ -0,0 +1,21 @@ +addBlankElement($name); + $element->attr['name'] = 'CDATA'; + if (!$config->get('HTML.Attr.Name.UseCDATA')) { + $element->attr_transform_post['NameSync'] = new HTMLPurifier_AttrTransform_NameSync(); + } + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php new file mode 100644 index 0000000000..5f1b14abb8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php @@ -0,0 +1,14 @@ + array( + 'lang' => 'LanguageCode', + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Object.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Object.php new file mode 100644 index 0000000000..193c1011f8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Object.php @@ -0,0 +1,47 @@ + to cater to legacy browsers: this + * module does not allow this sort of behavior + */ +class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule +{ + + public $name = 'Object'; + public $safe = false; + + public function setup($config) { + + $this->addElement('object', 'Inline', 'Optional: #PCDATA | Flow | param', 'Common', + array( + 'archive' => 'URI', + 'classid' => 'URI', + 'codebase' => 'URI', + 'codetype' => 'Text', + 'data' => 'URI', + 'declare' => 'Bool#declare', + 'height' => 'Length', + 'name' => 'CDATA', + 'standby' => 'Text', + 'tabindex' => 'Number', + 'type' => 'ContentType', + 'width' => 'Length' + ) + ); + + $this->addElement('param', false, 'Empty', false, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'type' => 'Text', + 'value' => 'Text', + 'valuetype' => 'Enum#data,ref,object' + ) + ); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Presentation.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Presentation.php new file mode 100644 index 0000000000..8ff0b5ed78 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Presentation.php @@ -0,0 +1,36 @@ +addElement('hr', 'Block', 'Empty', 'Common'); + $this->addElement('sub', 'Inline', 'Inline', 'Common'); + $this->addElement('sup', 'Inline', 'Inline', 'Common'); + $b = $this->addElement('b', 'Inline', 'Inline', 'Common'); + $b->formatting = true; + $big = $this->addElement('big', 'Inline', 'Inline', 'Common'); + $big->formatting = true; + $i = $this->addElement('i', 'Inline', 'Inline', 'Common'); + $i->formatting = true; + $small = $this->addElement('small', 'Inline', 'Inline', 'Common'); + $small->formatting = true; + $tt = $this->addElement('tt', 'Inline', 'Inline', 'Common'); + $tt->formatting = true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Proprietary.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Proprietary.php new file mode 100644 index 0000000000..dd36a3de0e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Proprietary.php @@ -0,0 +1,33 @@ +addElement('marquee', 'Inline', 'Flow', 'Common', + array( + 'direction' => 'Enum#left,right,up,down', + 'behavior' => 'Enum#alternate', + 'width' => 'Length', + 'height' => 'Length', + 'scrolldelay' => 'Number', + 'scrollamount' => 'Number', + 'loop' => 'Number', + 'bgcolor' => 'Color', + 'hspace' => 'Pixels', + 'vspace' => 'Pixels', + ) + ); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Ruby.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Ruby.php new file mode 100644 index 0000000000..b26a0a30a0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Ruby.php @@ -0,0 +1,27 @@ +addElement('ruby', 'Inline', + 'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))', + 'Common'); + $this->addElement('rbc', false, 'Required: rb', 'Common'); + $this->addElement('rtc', false, 'Required: rt', 'Common'); + $rb = $this->addElement('rb', false, 'Inline', 'Common'); + $rb->excludes = array('ruby' => true); + $rt = $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number')); + $rt->excludes = array('ruby' => true); + $this->addElement('rp', false, 'Optional: #PCDATA', 'Common'); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeEmbed.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeEmbed.php new file mode 100644 index 0000000000..8fc03cb1c7 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeEmbed.php @@ -0,0 +1,33 @@ +get('HTML.MaxImgLength'); + $embed = $this->addElement( + 'embed', 'Inline', 'Empty', 'Common', + array( + 'src*' => 'URI#embedded', + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'allowscriptaccess' => 'Enum#never', + 'allownetworking' => 'Enum#internal', + 'wmode' => 'Enum#window', + 'name' => 'ID', + ) + ); + $embed->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeEmbed(); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeObject.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeObject.php new file mode 100644 index 0000000000..33bac00cf2 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/SafeObject.php @@ -0,0 +1,50 @@ +get('HTML.MaxImgLength'); + $object = $this->addElement( + 'object', + 'Inline', + 'Optional: param | Flow | #PCDATA', + 'Common', + array( + // While technically not required by the spec, we're forcing + // it to this value. + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'data' => 'URI#embedded' + ) + ); + $object->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeObject(); + + $param = $this->addElement('param', false, 'Empty', false, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'value' => 'Text' + ) + ); + $param->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeParam(); + $this->info_injector[] = 'SafeObject'; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php new file mode 100644 index 0000000000..cecdea6c30 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php @@ -0,0 +1,54 @@ + 'script | noscript', 'Inline' => 'script | noscript'); + public $safe = false; + + public function setup($config) { + // TODO: create custom child-definition for noscript that + // auto-wraps stray #PCDATA in a similar manner to + // blockquote's custom definition (we would use it but + // blockquote's contents are optional while noscript's contents + // are required) + + // TODO: convert this to new syntax, main problem is getting + // both content sets working + + // In theory, this could be safe, but I don't see any reason to + // allow it. + $this->info['noscript'] = new HTMLPurifier_ElementDef(); + $this->info['noscript']->attr = array( 0 => array('Common') ); + $this->info['noscript']->content_model = 'Heading | List | Block'; + $this->info['noscript']->content_model_type = 'required'; + + $this->info['script'] = new HTMLPurifier_ElementDef(); + $this->info['script']->attr = array( + 'defer' => new HTMLPurifier_AttrDef_Enum(array('defer')), + 'src' => new HTMLPurifier_AttrDef_URI(true), + 'type' => new HTMLPurifier_AttrDef_Enum(array('text/javascript')) + ); + $this->info['script']->content_model = '#PCDATA'; + $this->info['script']->content_model_type = 'optional'; + $this->info['script']->attr_transform_pre['type'] = + $this->info['script']->attr_transform_post['type'] = + new HTMLPurifier_AttrTransform_ScriptRequired(); + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/StyleAttribute.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/StyleAttribute.php new file mode 100644 index 0000000000..eb78464cc0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/StyleAttribute.php @@ -0,0 +1,24 @@ + array('style' => false), // see constructor + 'Core' => array(0 => array('Style')) + ); + + public function setup($config) { + $this->attr_collections['Style']['style'] = new HTMLPurifier_AttrDef_CSS(); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tables.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tables.php new file mode 100644 index 0000000000..f314ced3f8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tables.php @@ -0,0 +1,66 @@ +addElement('caption', false, 'Inline', 'Common'); + + $this->addElement('table', 'Block', + new HTMLPurifier_ChildDef_Table(), 'Common', + array( + 'border' => 'Pixels', + 'cellpadding' => 'Length', + 'cellspacing' => 'Length', + 'frame' => 'Enum#void,above,below,hsides,lhs,rhs,vsides,box,border', + 'rules' => 'Enum#none,groups,rows,cols,all', + 'summary' => 'Text', + 'width' => 'Length' + ) + ); + + // common attributes + $cell_align = array( + 'align' => 'Enum#left,center,right,justify,char', + 'charoff' => 'Length', + 'valign' => 'Enum#top,middle,bottom,baseline', + ); + + $cell_t = array_merge( + array( + 'abbr' => 'Text', + 'colspan' => 'Number', + 'rowspan' => 'Number', + ), + $cell_align + ); + $this->addElement('td', false, 'Flow', 'Common', $cell_t); + $this->addElement('th', false, 'Flow', 'Common', $cell_t); + + $this->addElement('tr', false, 'Required: td | th', 'Common', $cell_align); + + $cell_col = array_merge( + array( + 'span' => 'Number', + 'width' => 'MultiLength', + ), + $cell_align + ); + $this->addElement('col', false, 'Empty', 'Common', $cell_col); + $this->addElement('colgroup', false, 'Optional: col', 'Common', $cell_col); + + $this->addElement('tbody', false, 'Required: tr', 'Common', $cell_align); + $this->addElement('thead', false, 'Required: tr', 'Common', $cell_align); + $this->addElement('tfoot', false, 'Required: tr', 'Common', $cell_align); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Target.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Target.php new file mode 100644 index 0000000000..2b844ecc45 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Target.php @@ -0,0 +1,23 @@ +addBlankElement($name); + $e->attr = array( + 'target' => new HTMLPurifier_AttrDef_HTML_FrameTarget() + ); + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Text.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Text.php new file mode 100644 index 0000000000..ae77c71886 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Text.php @@ -0,0 +1,71 @@ + 'Heading | Block | Inline' + ); + + public function setup($config) { + + // Inline Phrasal ------------------------------------------------- + $this->addElement('abbr', 'Inline', 'Inline', 'Common'); + $this->addElement('acronym', 'Inline', 'Inline', 'Common'); + $this->addElement('cite', 'Inline', 'Inline', 'Common'); + $this->addElement('dfn', 'Inline', 'Inline', 'Common'); + $this->addElement('kbd', 'Inline', 'Inline', 'Common'); + $this->addElement('q', 'Inline', 'Inline', 'Common', array('cite' => 'URI')); + $this->addElement('samp', 'Inline', 'Inline', 'Common'); + $this->addElement('var', 'Inline', 'Inline', 'Common'); + + $em = $this->addElement('em', 'Inline', 'Inline', 'Common'); + $em->formatting = true; + + $strong = $this->addElement('strong', 'Inline', 'Inline', 'Common'); + $strong->formatting = true; + + $code = $this->addElement('code', 'Inline', 'Inline', 'Common'); + $code->formatting = true; + + // Inline Structural ---------------------------------------------- + $this->addElement('span', 'Inline', 'Inline', 'Common'); + $this->addElement('br', 'Inline', 'Empty', 'Core'); + + // Block Phrasal -------------------------------------------------- + $this->addElement('address', 'Block', 'Inline', 'Common'); + $this->addElement('blockquote', 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI') ); + $pre = $this->addElement('pre', 'Block', 'Inline', 'Common'); + $pre->excludes = $this->makeLookup( + 'img', 'big', 'small', 'object', 'applet', 'font', 'basefont' ); + $this->addElement('h1', 'Heading', 'Inline', 'Common'); + $this->addElement('h2', 'Heading', 'Inline', 'Common'); + $this->addElement('h3', 'Heading', 'Inline', 'Common'); + $this->addElement('h4', 'Heading', 'Inline', 'Common'); + $this->addElement('h5', 'Heading', 'Inline', 'Common'); + $this->addElement('h6', 'Heading', 'Inline', 'Common'); + + // Block Structural ----------------------------------------------- + $p = $this->addElement('p', 'Block', 'Inline', 'Common'); + $p->autoclose = array_flip(array("address", "blockquote", "center", "dir", "div", "dl", "fieldset", "ol", "p", "ul")); + + $this->addElement('div', 'Block', 'Flow', 'Common'); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy.php new file mode 100644 index 0000000000..21783f18eb --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy.php @@ -0,0 +1,207 @@ + 'none', 'light', 'medium', 'heavy'); + + /** + * Default level to place all fixes in. Disabled by default + */ + public $defaultLevel = null; + + /** + * Lists of fixes used by getFixesForLevel(). Format is: + * HTMLModule_Tidy->fixesForLevel[$level] = array('fix-1', 'fix-2'); + */ + public $fixesForLevel = array( + 'light' => array(), + 'medium' => array(), + 'heavy' => array() + ); + + /** + * Lazy load constructs the module by determining the necessary + * fixes to create and then delegating to the populate() function. + * @todo Wildcard matching and error reporting when an added or + * subtracted fix has no effect. + */ + public function setup($config) { + + // create fixes, initialize fixesForLevel + $fixes = $this->makeFixes(); + $this->makeFixesForLevel($fixes); + + // figure out which fixes to use + $level = $config->get('HTML.TidyLevel'); + $fixes_lookup = $this->getFixesForLevel($level); + + // get custom fix declarations: these need namespace processing + $add_fixes = $config->get('HTML.TidyAdd'); + $remove_fixes = $config->get('HTML.TidyRemove'); + + foreach ($fixes as $name => $fix) { + // needs to be refactored a little to implement globbing + if ( + isset($remove_fixes[$name]) || + (!isset($add_fixes[$name]) && !isset($fixes_lookup[$name])) + ) { + unset($fixes[$name]); + } + } + + // populate this module with necessary fixes + $this->populate($fixes); + + } + + /** + * Retrieves all fixes per a level, returning fixes for that specific + * level as well as all levels below it. + * @param $level String level identifier, see $levels for valid values + * @return Lookup up table of fixes + */ + public function getFixesForLevel($level) { + if ($level == $this->levels[0]) { + return array(); + } + $activated_levels = array(); + for ($i = 1, $c = count($this->levels); $i < $c; $i++) { + $activated_levels[] = $this->levels[$i]; + if ($this->levels[$i] == $level) break; + } + if ($i == $c) { + trigger_error( + 'Tidy level ' . htmlspecialchars($level) . ' not recognized', + E_USER_WARNING + ); + return array(); + } + $ret = array(); + foreach ($activated_levels as $level) { + foreach ($this->fixesForLevel[$level] as $fix) { + $ret[$fix] = true; + } + } + return $ret; + } + + /** + * Dynamically populates the $fixesForLevel member variable using + * the fixes array. It may be custom overloaded, used in conjunction + * with $defaultLevel, or not used at all. + */ + public function makeFixesForLevel($fixes) { + if (!isset($this->defaultLevel)) return; + if (!isset($this->fixesForLevel[$this->defaultLevel])) { + trigger_error( + 'Default level ' . $this->defaultLevel . ' does not exist', + E_USER_ERROR + ); + return; + } + $this->fixesForLevel[$this->defaultLevel] = array_keys($fixes); + } + + /** + * Populates the module with transforms and other special-case code + * based on a list of fixes passed to it + * @param $lookup Lookup table of fixes to activate + */ + public function populate($fixes) { + foreach ($fixes as $name => $fix) { + // determine what the fix is for + list($type, $params) = $this->getFixType($name); + switch ($type) { + case 'attr_transform_pre': + case 'attr_transform_post': + $attr = $params['attr']; + if (isset($params['element'])) { + $element = $params['element']; + if (empty($this->info[$element])) { + $e = $this->addBlankElement($element); + } else { + $e = $this->info[$element]; + } + } else { + $type = "info_$type"; + $e = $this; + } + // PHP does some weird parsing when I do + // $e->$type[$attr], so I have to assign a ref. + $f =& $e->$type; + $f[$attr] = $fix; + break; + case 'tag_transform': + $this->info_tag_transform[$params['element']] = $fix; + break; + case 'child': + case 'content_model_type': + $element = $params['element']; + if (empty($this->info[$element])) { + $e = $this->addBlankElement($element); + } else { + $e = $this->info[$element]; + } + $e->$type = $fix; + break; + default: + trigger_error("Fix type $type not supported", E_USER_ERROR); + break; + } + } + } + + /** + * Parses a fix name and determines what kind of fix it is, as well + * as other information defined by the fix + * @param $name String name of fix + * @return array(string $fix_type, array $fix_parameters) + * @note $fix_parameters is type dependant, see populate() for usage + * of these parameters + */ + public function getFixType($name) { + // parse it + $property = $attr = null; + if (strpos($name, '#') !== false) list($name, $property) = explode('#', $name); + if (strpos($name, '@') !== false) list($name, $attr) = explode('@', $name); + + // figure out the parameters + $params = array(); + if ($name !== '') $params['element'] = $name; + if (!is_null($attr)) $params['attr'] = $attr; + + // special case: attribute transform + if (!is_null($attr)) { + if (is_null($property)) $property = 'pre'; + $type = 'attr_transform_' . $property; + return array($type, $params); + } + + // special case: tag transform + if (is_null($property)) { + return array('tag_transform', $params); + } + + return array($property, $params); + + } + + /** + * Defines all fixes the module will perform in a compact + * associative array of fix name to fix implementation. + */ + public function makeFixes() {} + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Name.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Name.php new file mode 100644 index 0000000000..61ff85ce2f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Name.php @@ -0,0 +1,24 @@ +content_model_type != 'strictblockquote') return parent::getChildDef($def); + return new HTMLPurifier_ChildDef_StrictBlockquote($def->content_model); + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Transitional.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Transitional.php new file mode 100644 index 0000000000..9960b1dd10 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Transitional.php @@ -0,0 +1,9 @@ + 'text-align:left;', + 'right' => 'text-align:right;', + 'top' => 'caption-side:top;', + 'bottom' => 'caption-side:bottom;' // not supported by IE + )); + + // @align for img ------------------------------------------------- + $r['img@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS('align', array( + 'left' => 'float:left;', + 'right' => 'float:right;', + 'top' => 'vertical-align:top;', + 'middle' => 'vertical-align:middle;', + 'bottom' => 'vertical-align:baseline;', + )); + + // @align for table ----------------------------------------------- + $r['table@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS('align', array( + 'left' => 'float:left;', + 'center' => 'margin-left:auto;margin-right:auto;', + 'right' => 'float:right;' + )); + + // @align for hr ----------------------------------------------- + $r['hr@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS('align', array( + // we use both text-align and margin because these work + // for different browsers (IE and Firefox, respectively) + // and the melange makes for a pretty cross-compatible + // solution + 'left' => 'margin-left:0;margin-right:auto;text-align:left;', + 'center' => 'margin-left:auto;margin-right:auto;text-align:center;', + 'right' => 'margin-left:auto;margin-right:0;text-align:right;' + )); + + // @align for h1, h2, h3, h4, h5, h6, p, div ---------------------- + // {{{ + $align_lookup = array(); + $align_values = array('left', 'right', 'center', 'justify'); + foreach ($align_values as $v) $align_lookup[$v] = "text-align:$v;"; + // }}} + $r['h1@align'] = + $r['h2@align'] = + $r['h3@align'] = + $r['h4@align'] = + $r['h5@align'] = + $r['h6@align'] = + $r['p@align'] = + $r['div@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS('align', $align_lookup); + + // @bgcolor for table, tr, td, th --------------------------------- + $r['table@bgcolor'] = + $r['td@bgcolor'] = + $r['th@bgcolor'] = + new HTMLPurifier_AttrTransform_BgColor(); + + // @border for img ------------------------------------------------ + $r['img@border'] = new HTMLPurifier_AttrTransform_Border(); + + // @clear for br -------------------------------------------------- + $r['br@clear'] = + new HTMLPurifier_AttrTransform_EnumToCSS('clear', array( + 'left' => 'clear:left;', + 'right' => 'clear:right;', + 'all' => 'clear:both;', + 'none' => 'clear:none;', + )); + + // @height for td, th --------------------------------------------- + $r['td@height'] = + $r['th@height'] = + new HTMLPurifier_AttrTransform_Length('height'); + + // @hspace for img ------------------------------------------------ + $r['img@hspace'] = new HTMLPurifier_AttrTransform_ImgSpace('hspace'); + + // @noshade for hr ------------------------------------------------ + // this transformation is not precise but often good enough. + // different browsers use different styles to designate noshade + $r['hr@noshade'] = + new HTMLPurifier_AttrTransform_BoolToCSS( + 'noshade', + 'color:#808080;background-color:#808080;border:0;' + ); + + // @nowrap for td, th --------------------------------------------- + $r['td@nowrap'] = + $r['th@nowrap'] = + new HTMLPurifier_AttrTransform_BoolToCSS( + 'nowrap', + 'white-space:nowrap;' + ); + + // @size for hr -------------------------------------------------- + $r['hr@size'] = new HTMLPurifier_AttrTransform_Length('size', 'height'); + + // @type for li, ol, ul ------------------------------------------- + // {{{ + $ul_types = array( + 'disc' => 'list-style-type:disc;', + 'square' => 'list-style-type:square;', + 'circle' => 'list-style-type:circle;' + ); + $ol_types = array( + '1' => 'list-style-type:decimal;', + 'i' => 'list-style-type:lower-roman;', + 'I' => 'list-style-type:upper-roman;', + 'a' => 'list-style-type:lower-alpha;', + 'A' => 'list-style-type:upper-alpha;' + ); + $li_types = $ul_types + $ol_types; + // }}} + + $r['ul@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $ul_types); + $r['ol@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $ol_types, true); + $r['li@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $li_types, true); + + // @vspace for img ------------------------------------------------ + $r['img@vspace'] = new HTMLPurifier_AttrTransform_ImgSpace('vspace'); + + // @width for hr, td, th ------------------------------------------ + $r['td@width'] = + $r['th@width'] = + $r['hr@width'] = new HTMLPurifier_AttrTransform_Length('width'); + + return $r; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/XMLCommonAttributes.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/XMLCommonAttributes.php new file mode 100644 index 0000000000..9c0e031984 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModule/XMLCommonAttributes.php @@ -0,0 +1,14 @@ + array( + 'xml:lang' => 'LanguageCode', + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php b/extlib/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php new file mode 100644 index 0000000000..f5c4a1d2cb --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php @@ -0,0 +1,403 @@ +attrTypes = new HTMLPurifier_AttrTypes(); + $this->doctypes = new HTMLPurifier_DoctypeRegistry(); + + // setup basic modules + $common = array( + 'CommonAttributes', 'Text', 'Hypertext', 'List', + 'Presentation', 'Edit', 'Bdo', 'Tables', 'Image', + 'StyleAttribute', + // Unsafe: + 'Scripting', 'Object', 'Forms', + // Sorta legacy, but present in strict: + 'Name', + ); + $transitional = array('Legacy', 'Target'); + $xml = array('XMLCommonAttributes'); + $non_xml = array('NonXMLCommonAttributes'); + + // setup basic doctypes + $this->doctypes->register( + 'HTML 4.01 Transitional', false, + array_merge($common, $transitional, $non_xml), + array('Tidy_Transitional', 'Tidy_Proprietary'), + array(), + '-//W3C//DTD HTML 4.01 Transitional//EN', + 'http://www.w3.org/TR/html4/loose.dtd' + ); + + $this->doctypes->register( + 'HTML 4.01 Strict', false, + array_merge($common, $non_xml), + array('Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'), + array(), + '-//W3C//DTD HTML 4.01//EN', + 'http://www.w3.org/TR/html4/strict.dtd' + ); + + $this->doctypes->register( + 'XHTML 1.0 Transitional', true, + array_merge($common, $transitional, $xml, $non_xml), + array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Name'), + array(), + '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' + ); + + $this->doctypes->register( + 'XHTML 1.0 Strict', true, + array_merge($common, $xml, $non_xml), + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'), + array(), + '-//W3C//DTD XHTML 1.0 Strict//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd' + ); + + $this->doctypes->register( + 'XHTML 1.1', true, + array_merge($common, $xml, array('Ruby')), + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Strict', 'Tidy_Name'), // Tidy_XHTML1_1 + array(), + '-//W3C//DTD XHTML 1.1//EN', + 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' + ); + + } + + /** + * Registers a module to the recognized module list, useful for + * overloading pre-existing modules. + * @param $module Mixed: string module name, with or without + * HTMLPurifier_HTMLModule prefix, or instance of + * subclass of HTMLPurifier_HTMLModule. + * @param $overload Boolean whether or not to overload previous modules. + * If this is not set, and you do overload a module, + * HTML Purifier will complain with a warning. + * @note This function will not call autoload, you must instantiate + * (and thus invoke) autoload outside the method. + * @note If a string is passed as a module name, different variants + * will be tested in this order: + * - Check for HTMLPurifier_HTMLModule_$name + * - Check all prefixes with $name in order they were added + * - Check for literal object name + * - Throw fatal error + * If your object name collides with an internal class, specify + * your module manually. All modules must have been included + * externally: registerModule will not perform inclusions for you! + */ + public function registerModule($module, $overload = false) { + if (is_string($module)) { + // attempt to load the module + $original_module = $module; + $ok = false; + foreach ($this->prefixes as $prefix) { + $module = $prefix . $original_module; + if (class_exists($module)) { + $ok = true; + break; + } + } + if (!$ok) { + $module = $original_module; + if (!class_exists($module)) { + trigger_error($original_module . ' module does not exist', + E_USER_ERROR); + return; + } + } + $module = new $module(); + } + if (empty($module->name)) { + trigger_error('Module instance of ' . get_class($module) . ' must have name'); + return; + } + if (!$overload && isset($this->registeredModules[$module->name])) { + trigger_error('Overloading ' . $module->name . ' without explicit overload parameter', E_USER_WARNING); + } + $this->registeredModules[$module->name] = $module; + } + + /** + * Adds a module to the current doctype by first registering it, + * and then tacking it on to the active doctype + */ + public function addModule($module) { + $this->registerModule($module); + if (is_object($module)) $module = $module->name; + $this->userModules[] = $module; + } + + /** + * Adds a class prefix that registerModule() will use to resolve a + * string name to a concrete class + */ + public function addPrefix($prefix) { + $this->prefixes[] = $prefix; + } + + /** + * Performs processing on modules, after being called you may + * use getElement() and getElements() + * @param $config Instance of HTMLPurifier_Config + */ + public function setup($config) { + + $this->trusted = $config->get('HTML.Trusted'); + + // generate + $this->doctype = $this->doctypes->make($config); + $modules = $this->doctype->modules; + + // take out the default modules that aren't allowed + $lookup = $config->get('HTML.AllowedModules'); + $special_cases = $config->get('HTML.CoreModules'); + + if (is_array($lookup)) { + foreach ($modules as $k => $m) { + if (isset($special_cases[$m])) continue; + if (!isset($lookup[$m])) unset($modules[$k]); + } + } + + // add proprietary module (this gets special treatment because + // it is completely removed from doctypes, etc.) + if ($config->get('HTML.Proprietary')) { + $modules[] = 'Proprietary'; + } + + // add SafeObject/Safeembed modules + if ($config->get('HTML.SafeObject')) { + $modules[] = 'SafeObject'; + } + if ($config->get('HTML.SafeEmbed')) { + $modules[] = 'SafeEmbed'; + } + + // merge in custom modules + $modules = array_merge($modules, $this->userModules); + + foreach ($modules as $module) { + $this->processModule($module); + $this->modules[$module]->setup($config); + } + + foreach ($this->doctype->tidyModules as $module) { + $this->processModule($module); + $this->modules[$module]->setup($config); + } + + // prepare any injectors + foreach ($this->modules as $module) { + $n = array(); + foreach ($module->info_injector as $i => $injector) { + if (!is_object($injector)) { + $class = "HTMLPurifier_Injector_$injector"; + $injector = new $class; + } + $n[$injector->name] = $injector; + } + $module->info_injector = $n; + } + + // setup lookup table based on all valid modules + foreach ($this->modules as $module) { + foreach ($module->info as $name => $def) { + if (!isset($this->elementLookup[$name])) { + $this->elementLookup[$name] = array(); + } + $this->elementLookup[$name][] = $module->name; + } + } + + // note the different choice + $this->contentSets = new HTMLPurifier_ContentSets( + // content set assembly deals with all possible modules, + // not just ones deemed to be "safe" + $this->modules + ); + $this->attrCollections = new HTMLPurifier_AttrCollections( + $this->attrTypes, + // there is no way to directly disable a global attribute, + // but using AllowedAttributes or simply not including + // the module in your custom doctype should be sufficient + $this->modules + ); + } + + /** + * Takes a module and adds it to the active module collection, + * registering it if necessary. + */ + public function processModule($module) { + if (!isset($this->registeredModules[$module]) || is_object($module)) { + $this->registerModule($module); + } + $this->modules[$module] = $this->registeredModules[$module]; + } + + /** + * Retrieves merged element definitions. + * @return Array of HTMLPurifier_ElementDef + */ + public function getElements() { + + $elements = array(); + foreach ($this->modules as $module) { + if (!$this->trusted && !$module->safe) continue; + foreach ($module->info as $name => $v) { + if (isset($elements[$name])) continue; + $elements[$name] = $this->getElement($name); + } + } + + // remove dud elements, this happens when an element that + // appeared to be safe actually wasn't + foreach ($elements as $n => $v) { + if ($v === false) unset($elements[$n]); + } + + return $elements; + + } + + /** + * Retrieves a single merged element definition + * @param $name Name of element + * @param $trusted Boolean trusted overriding parameter: set to true + * if you want the full version of an element + * @return Merged HTMLPurifier_ElementDef + * @note You may notice that modules are getting iterated over twice (once + * in getElements() and once here). This + * is because + */ + public function getElement($name, $trusted = null) { + + if (!isset($this->elementLookup[$name])) { + return false; + } + + // setup global state variables + $def = false; + if ($trusted === null) $trusted = $this->trusted; + + // iterate through each module that has registered itself to this + // element + foreach($this->elementLookup[$name] as $module_name) { + + $module = $this->modules[$module_name]; + + // refuse to create/merge from a module that is deemed unsafe-- + // pretend the module doesn't exist--when trusted mode is not on. + if (!$trusted && !$module->safe) { + continue; + } + + // clone is used because, ideally speaking, the original + // definition should not be modified. Usually, this will + // make no difference, but for consistency's sake + $new_def = clone $module->info[$name]; + + if (!$def && $new_def->standalone) { + $def = $new_def; + } elseif ($def) { + // This will occur even if $new_def is standalone. In practice, + // this will usually result in a full replacement. + $def->mergeIn($new_def); + } else { + // :TODO: + // non-standalone definitions that don't have a standalone + // to merge into could be deferred to the end + continue; + } + + // attribute value expansions + $this->attrCollections->performInclusions($def->attr); + $this->attrCollections->expandIdentifiers($def->attr, $this->attrTypes); + + // descendants_are_inline, for ChildDef_Chameleon + if (is_string($def->content_model) && + strpos($def->content_model, 'Inline') !== false) { + if ($name != 'del' && $name != 'ins') { + // this is for you, ins/del + $def->descendants_are_inline = true; + } + } + + $this->contentSets->generateChildDef($def, $module); + } + + // This can occur if there is a blank definition, but no base to + // mix it in with + if (!$def) return false; + + // add information on required attributes + foreach ($def->attr as $attr_name => $attr_def) { + if ($attr_def->required) { + $def->required_attr[] = $attr_name; + } + } + + return $def; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/IDAccumulator.php b/extlib/HTMLPurifier/HTMLPurifier/IDAccumulator.php new file mode 100644 index 0000000000..73215295a5 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/IDAccumulator.php @@ -0,0 +1,53 @@ +load($config->get('Attr.IDBlacklist')); + return $id_accumulator; + } + + /** + * Add an ID to the lookup table. + * @param $id ID to be added. + * @return Bool status, true if success, false if there's a dupe + */ + public function add($id) { + if (isset($this->ids[$id])) return false; + return $this->ids[$id] = true; + } + + /** + * Load a list of IDs into the lookup table + * @param $array_of_ids Array of IDs to load + * @note This function doesn't care about duplicates + */ + public function load($array_of_ids) { + foreach ($array_of_ids as $id) { + $this->ids[$id] = true; + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Injector.php b/extlib/HTMLPurifier/HTMLPurifier/Injector.php new file mode 100644 index 0000000000..5922f81305 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Injector.php @@ -0,0 +1,239 @@ +processToken() + * documentation. + * + * @todo Allow injectors to request a re-run on their output. This + * would help if an operation is recursive. + */ +abstract class HTMLPurifier_Injector +{ + + /** + * Advisory name of injector, this is for friendly error messages + */ + public $name; + + /** + * Instance of HTMLPurifier_HTMLDefinition + */ + protected $htmlDefinition; + + /** + * Reference to CurrentNesting variable in Context. This is an array + * list of tokens that we are currently "inside" + */ + protected $currentNesting; + + /** + * Reference to InputTokens variable in Context. This is an array + * list of the input tokens that are being processed. + */ + protected $inputTokens; + + /** + * Reference to InputIndex variable in Context. This is an integer + * array index for $this->inputTokens that indicates what token + * is currently being processed. + */ + protected $inputIndex; + + /** + * Array of elements and attributes this injector creates and therefore + * need to be allowed by the definition. Takes form of + * array('element' => array('attr', 'attr2'), 'element2') + */ + public $needed = array(); + + /** + * Index of inputTokens to rewind to. + */ + protected $rewind = false; + + /** + * Rewind to a spot to re-perform processing. This is useful if you + * deleted a node, and now need to see if this change affected any + * earlier nodes. Rewinding does not affect other injectors, and can + * result in infinite loops if not used carefully. + * @warning HTML Purifier will prevent you from fast-forwarding with this + * function. + */ + public function rewind($index) { + $this->rewind = $index; + } + + /** + * Retrieves rewind, and then unsets it. + */ + public function getRewind() { + $r = $this->rewind; + $this->rewind = false; + return $r; + } + + /** + * Prepares the injector by giving it the config and context objects: + * this allows references to important variables to be made within + * the injector. This function also checks if the HTML environment + * will work with the Injector (see checkNeeded()). + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + * @return Boolean false if success, string of missing needed element/attribute if failure + */ + public function prepare($config, $context) { + $this->htmlDefinition = $config->getHTMLDefinition(); + // Even though this might fail, some unit tests ignore this and + // still test checkNeeded, so be careful. Maybe get rid of that + // dependency. + $result = $this->checkNeeded($config); + if ($result !== false) return $result; + $this->currentNesting =& $context->get('CurrentNesting'); + $this->inputTokens =& $context->get('InputTokens'); + $this->inputIndex =& $context->get('InputIndex'); + return false; + } + + /** + * This function checks if the HTML environment + * will work with the Injector: if p tags are not allowed, the + * Auto-Paragraphing injector should not be enabled. + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + * @return Boolean false if success, string of missing needed element/attribute if failure + */ + public function checkNeeded($config) { + $def = $config->getHTMLDefinition(); + foreach ($this->needed as $element => $attributes) { + if (is_int($element)) $element = $attributes; + if (!isset($def->info[$element])) return $element; + if (!is_array($attributes)) continue; + foreach ($attributes as $name) { + if (!isset($def->info[$element]->attr[$name])) return "$element.$name"; + } + } + return false; + } + + /** + * Tests if the context node allows a certain element + * @param $name Name of element to test for + * @return True if element is allowed, false if it is not + */ + public function allowsElement($name) { + if (!empty($this->currentNesting)) { + $parent_token = array_pop($this->currentNesting); + $this->currentNesting[] = $parent_token; + $parent = $this->htmlDefinition->info[$parent_token->name]; + } else { + $parent = $this->htmlDefinition->info_parent_def; + } + if (!isset($parent->child->elements[$name]) || isset($parent->excludes[$name])) { + return false; + } + // check for exclusion + for ($i = count($this->currentNesting) - 2; $i >= 0; $i--) { + $node = $this->currentNesting[$i]; + $def = $this->htmlDefinition->info[$node->name]; + if (isset($def->excludes[$name])) return false; + } + return true; + } + + /** + * Iterator function, which starts with the next token and continues until + * you reach the end of the input tokens. + * @warning Please prevent previous references from interfering with this + * functions by setting $i = null beforehand! + * @param &$i Current integer index variable for inputTokens + * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference + */ + protected function forward(&$i, &$current) { + if ($i === null) $i = $this->inputIndex + 1; + else $i++; + if (!isset($this->inputTokens[$i])) return false; + $current = $this->inputTokens[$i]; + return true; + } + + /** + * Similar to _forward, but accepts a third parameter $nesting (which + * should be initialized at 0) and stops when we hit the end tag + * for the node $this->inputIndex starts in. + */ + protected function forwardUntilEndToken(&$i, &$current, &$nesting) { + $result = $this->forward($i, $current); + if (!$result) return false; + if ($nesting === null) $nesting = 0; + if ($current instanceof HTMLPurifier_Token_Start) $nesting++; + elseif ($current instanceof HTMLPurifier_Token_End) { + if ($nesting <= 0) return false; + $nesting--; + } + return true; + } + + /** + * Iterator function, starts with the previous token and continues until + * you reach the beginning of input tokens. + * @warning Please prevent previous references from interfering with this + * functions by setting $i = null beforehand! + * @param &$i Current integer index variable for inputTokens + * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference + */ + protected function backward(&$i, &$current) { + if ($i === null) $i = $this->inputIndex - 1; + else $i--; + if ($i < 0) return false; + $current = $this->inputTokens[$i]; + return true; + } + + /** + * Initializes the iterator at the current position. Use in a do {} while; + * loop to force the _forward and _backward functions to start at the + * current location. + * @warning Please prevent previous references from interfering with this + * functions by setting $i = null beforehand! + * @param &$i Current integer index variable for inputTokens + * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference + */ + protected function current(&$i, &$current) { + if ($i === null) $i = $this->inputIndex; + $current = $this->inputTokens[$i]; + } + + /** + * Handler that is called when a text token is processed + */ + public function handleText(&$token) {} + + /** + * Handler that is called when a start or empty token is processed + */ + public function handleElement(&$token) {} + + /** + * Handler that is called when an end token is processed + */ + public function handleEnd(&$token) { + $this->notifyEnd($token); + } + + /** + * Notifier that is called when an end token is processed + * @note This differs from handlers in that the token is read-only + * @deprecated + */ + public function notifyEnd($token) {} + + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Injector/AutoParagraph.php b/extlib/HTMLPurifier/HTMLPurifier/Injector/AutoParagraph.php new file mode 100644 index 0000000000..8cc952549c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Injector/AutoParagraph.php @@ -0,0 +1,340 @@ +armor['MakeWellFormed_TagClosedError'] = true; + return $par; + } + + public function handleText(&$token) { + $text = $token->data; + // Does the current parent allow

tags? + if ($this->allowsElement('p')) { + if (empty($this->currentNesting) || strpos($text, "\n\n") !== false) { + // Note that we have differing behavior when dealing with text + // in the anonymous root node, or a node inside the document. + // If the text as a double-newline, the treatment is the same; + // if it doesn't, see the next if-block if you're in the document. + + $i = $nesting = null; + if (!$this->forwardUntilEndToken($i, $current, $nesting) && $token->is_whitespace) { + // State 1.1: ... ^ (whitespace, then document end) + // ---- + // This is a degenerate case + } else { + // State 1.2: PAR1 + // ---- + + // State 1.3: PAR1\n\nPAR2 + // ------------ + + // State 1.4:

PAR1\n\nPAR2 (see State 2) + // ------------ + $token = array($this->_pStart()); + $this->_splitText($text, $token); + } + } else { + // State 2:
PAR1... (similar to 1.4) + // ---- + + // We're in an element that allows paragraph tags, but we're not + // sure if we're going to need them. + if ($this->_pLookAhead()) { + // State 2.1:
PAR1PAR1\n\nPAR2 + // ---- + // Note: This will always be the first child, since any + // previous inline element would have triggered this very + // same routine, and found the double newline. One possible + // exception would be a comment. + $token = array($this->_pStart(), $token); + } else { + // State 2.2.1:
PAR1
+ // ---- + + // State 2.2.2:
PAR1PAR1
+ // ---- + } + } + // Is the current parent a

tag? + } elseif ( + !empty($this->currentNesting) && + $this->currentNesting[count($this->currentNesting)-1]->name == 'p' + ) { + // State 3.1: ...

PAR1 + // ---- + + // State 3.2: ...

PAR1\n\nPAR2 + // ------------ + $token = array(); + $this->_splitText($text, $token); + // Abort! + } else { + // State 4.1: ...PAR1 + // ---- + + // State 4.2: ...PAR1\n\nPAR2 + // ------------ + } + } + + public function handleElement(&$token) { + // We don't have to check if we're already in a

tag for block + // tokens, because the tag would have been autoclosed by MakeWellFormed. + if ($this->allowsElement('p')) { + if (!empty($this->currentNesting)) { + if ($this->_isInline($token)) { + // State 1:

... + // --- + + // Check if this token is adjacent to the parent token + // (seek backwards until token isn't whitespace) + $i = null; + $this->backward($i, $prev); + + if (!$prev instanceof HTMLPurifier_Token_Start) { + // Token wasn't adjacent + + if ( + $prev instanceof HTMLPurifier_Token_Text && + substr($prev->data, -2) === "\n\n" + ) { + // State 1.1.4:

PAR1

\n\n + // --- + + // Quite frankly, this should be handled by splitText + $token = array($this->_pStart(), $token); + } else { + // State 1.1.1:

PAR1

+ // --- + + // State 1.1.2:

+ // --- + + // State 1.1.3:
PAR + // --- + } + + } else { + // State 1.2.1:
+ // --- + + // Lookahead to see if

is needed. + if ($this->_pLookAhead()) { + // State 1.3.1:

PAR1\n\nPAR2 + // --- + $token = array($this->_pStart(), $token); + } else { + // State 1.3.2:
PAR1
+ // --- + + // State 1.3.3:
PAR1
\n\n
+ // --- + } + } + } else { + // State 2.3: ...
+ // ----- + } + } else { + if ($this->_isInline($token)) { + // State 3.1: + // --- + // This is where the {p} tag is inserted, not reflected in + // inputTokens yet, however. + $token = array($this->_pStart(), $token); + } else { + // State 3.2:
+ // ----- + } + + $i = null; + if ($this->backward($i, $prev)) { + if ( + !$prev instanceof HTMLPurifier_Token_Text + ) { + // State 3.1.1: ...

{p} + // --- + + // State 3.2.1: ...

+ // ----- + + if (!is_array($token)) $token = array($token); + array_unshift($token, new HTMLPurifier_Token_Text("\n\n")); + } else { + // State 3.1.2: ...

\n\n{p} + // --- + + // State 3.2.2: ...

\n\n
+ // ----- + + // Note: PAR cannot occur because PAR would have been + // wrapped in

tags. + } + } + } + } else { + // State 2.2:

  • + // ---- + + // State 2.4:

    + // --- + } + } + + /** + * Splits up a text in paragraph tokens and appends them + * to the result stream that will replace the original + * @param $data String text data that will be processed + * into paragraphs + * @param $result Reference to array of tokens that the + * tags will be appended onto + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + */ + private function _splitText($data, &$result) { + $raw_paragraphs = explode("\n\n", $data); + $paragraphs = array(); // without empty paragraphs + $needs_start = false; + $needs_end = false; + + $c = count($raw_paragraphs); + if ($c == 1) { + // There were no double-newlines, abort quickly. In theory this + // should never happen. + $result[] = new HTMLPurifier_Token_Text($data); + return; + } + for ($i = 0; $i < $c; $i++) { + $par = $raw_paragraphs[$i]; + if (trim($par) !== '') { + $paragraphs[] = $par; + } else { + if ($i == 0) { + // Double newline at the front + if (empty($result)) { + // The empty result indicates that the AutoParagraph + // injector did not add any start paragraph tokens. + // This means that we have been in a paragraph for + // a while, and the newline means we should start a new one. + $result[] = new HTMLPurifier_Token_End('p'); + $result[] = new HTMLPurifier_Token_Text("\n\n"); + // However, the start token should only be added if + // there is more processing to be done (i.e. there are + // real paragraphs in here). If there are none, the + // next start paragraph tag will be handled by the + // next call to the injector + $needs_start = true; + } else { + // We just started a new paragraph! + // Reinstate a double-newline for presentation's sake, since + // it was in the source code. + array_unshift($result, new HTMLPurifier_Token_Text("\n\n")); + } + } elseif ($i + 1 == $c) { + // Double newline at the end + // There should be a trailing

    when we're finally done. + $needs_end = true; + } + } + } + + // Check if this was just a giant blob of whitespace. Move this earlier, + // perhaps? + if (empty($paragraphs)) { + return; + } + + // Add the start tag indicated by \n\n at the beginning of $data + if ($needs_start) { + $result[] = $this->_pStart(); + } + + // Append the paragraphs onto the result + foreach ($paragraphs as $par) { + $result[] = new HTMLPurifier_Token_Text($par); + $result[] = new HTMLPurifier_Token_End('p'); + $result[] = new HTMLPurifier_Token_Text("\n\n"); + $result[] = $this->_pStart(); + } + + // Remove trailing start token; Injector will handle this later if + // it was indeed needed. This prevents from needing to do a lookahead, + // at the cost of a lookbehind later. + array_pop($result); + + // If there is no need for an end tag, remove all of it and let + // MakeWellFormed close it later. + if (!$needs_end) { + array_pop($result); // removes \n\n + array_pop($result); // removes

    + } + + } + + /** + * Returns true if passed token is inline (and, ergo, allowed in + * paragraph tags) + */ + private function _isInline($token) { + return isset($this->htmlDefinition->info['p']->child->elements[$token->name]); + } + + /** + * Looks ahead in the token list and determines whether or not we need + * to insert a

    tag. + */ + private function _pLookAhead() { + $this->current($i, $current); + if ($current instanceof HTMLPurifier_Token_Start) $nesting = 1; + else $nesting = 0; + $ok = false; + while ($this->forwardUntilEndToken($i, $current, $nesting)) { + $result = $this->_checkNeedsP($current); + if ($result !== null) { + $ok = $result; + break; + } + } + return $ok; + } + + /** + * Determines if a particular token requires an earlier inline token + * to get a paragraph. This should be used with _forwardUntilEndToken + */ + private function _checkNeedsP($current) { + if ($current instanceof HTMLPurifier_Token_Start){ + if (!$this->_isInline($current)) { + //

    PAR1
    + // ---- + // Terminate early, since we hit a block element + return false; + } + } elseif ($current instanceof HTMLPurifier_Token_Text) { + if (strpos($current->data, "\n\n") !== false) { + //
    PAR1PAR1\n\nPAR2 + // ---- + return true; + } else { + //
    PAR1PAR1... + // ---- + } + } + return null; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Injector/DisplayLinkURI.php b/extlib/HTMLPurifier/HTMLPurifier/Injector/DisplayLinkURI.php new file mode 100644 index 0000000000..9dce9bd085 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Injector/DisplayLinkURI.php @@ -0,0 +1,26 @@ +start->attr['href'])){ + $url = $token->start->attr['href']; + unset($token->start->attr['href']); + $token = array($token, new HTMLPurifier_Token_Text(" ($url)")); + } else { + // nothing to display + } + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Injector/Linkify.php b/extlib/HTMLPurifier/HTMLPurifier/Injector/Linkify.php new file mode 100644 index 0000000000..296dac2829 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Injector/Linkify.php @@ -0,0 +1,46 @@ + array('href')); + + public function handleText(&$token) { + if (!$this->allowsElement('a')) return; + + if (strpos($token->data, '://') === false) { + // our really quick heuristic failed, abort + // this may not work so well if we want to match things like + // "google.com", but then again, most people don't + return; + } + + // there is/are URL(s). Let's split the string: + // Note: this regex is extremely permissive + $bits = preg_split('#((?:https?|ftp)://[^\s\'"<>()]+)#S', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE); + + $token = array(); + + // $i = index + // $c = count + // $l = is link + for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) { + if (!$l) { + if ($bits[$i] === '') continue; + $token[] = new HTMLPurifier_Token_Text($bits[$i]); + } else { + $token[] = new HTMLPurifier_Token_Start('a', array('href' => $bits[$i])); + $token[] = new HTMLPurifier_Token_Text($bits[$i]); + $token[] = new HTMLPurifier_Token_End('a'); + } + } + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Injector/PurifierLinkify.php b/extlib/HTMLPurifier/HTMLPurifier/Injector/PurifierLinkify.php new file mode 100644 index 0000000000..ad2455a91c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Injector/PurifierLinkify.php @@ -0,0 +1,45 @@ + array('href')); + + public function prepare($config, $context) { + $this->docURL = $config->get('AutoFormat.PurifierLinkify.DocURL'); + return parent::prepare($config, $context); + } + + public function handleText(&$token) { + if (!$this->allowsElement('a')) return; + if (strpos($token->data, '%') === false) return; + + $bits = preg_split('#%([a-z0-9]+\.[a-z0-9]+)#Si', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE); + $token = array(); + + // $i = index + // $c = count + // $l = is link + for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) { + if (!$l) { + if ($bits[$i] === '') continue; + $token[] = new HTMLPurifier_Token_Text($bits[$i]); + } else { + $token[] = new HTMLPurifier_Token_Start('a', + array('href' => str_replace('%s', $bits[$i], $this->docURL))); + $token[] = new HTMLPurifier_Token_Text('%' . $bits[$i]); + $token[] = new HTMLPurifier_Token_End('a'); + } + } + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Injector/RemoveEmpty.php b/extlib/HTMLPurifier/HTMLPurifier/Injector/RemoveEmpty.php new file mode 100644 index 0000000000..638bfca03b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Injector/RemoveEmpty.php @@ -0,0 +1,51 @@ +config = $config; + $this->context = $context; + $this->removeNbsp = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp'); + $this->removeNbspExceptions = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions'); + $this->attrValidator = new HTMLPurifier_AttrValidator(); + } + + public function handleElement(&$token) { + if (!$token instanceof HTMLPurifier_Token_Start) return; + $next = false; + for ($i = $this->inputIndex + 1, $c = count($this->inputTokens); $i < $c; $i++) { + $next = $this->inputTokens[$i]; + if ($next instanceof HTMLPurifier_Token_Text) { + if ($next->is_whitespace) continue; + if ($this->removeNbsp && !isset($this->removeNbspExceptions[$token->name])) { + $plain = str_replace("\xC2\xA0", "", $next->data); + $isWsOrNbsp = $plain === '' || ctype_space($plain); + if ($isWsOrNbsp) continue; + } + } + break; + } + if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) { + if ($token->name == 'colgroup') return; + $this->attrValidator->validateToken($token, $this->config, $this->context); + $token->armor['ValidateAttributes'] = true; + if (isset($token->attr['id']) || isset($token->attr['name'])) return; + $token = $i - $this->inputIndex + 1; + for ($b = $this->inputIndex - 1; $b > 0; $b--) { + $prev = $this->inputTokens[$b]; + if ($prev instanceof HTMLPurifier_Token_Text && $prev->is_whitespace) continue; + break; + } + // This is safe because we removed the token that triggered this. + $this->rewind($b - 1); + return; + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Injector/SafeObject.php b/extlib/HTMLPurifier/HTMLPurifier/Injector/SafeObject.php new file mode 100644 index 0000000000..3415828685 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Injector/SafeObject.php @@ -0,0 +1,87 @@ + 'never', + 'allowNetworking' => 'internal', + ); + protected $allowedParam = array( + 'wmode' => true, + 'movie' => true, + ); + + public function prepare($config, $context) { + parent::prepare($config, $context); + } + + public function handleElement(&$token) { + if ($token->name == 'object') { + $this->objectStack[] = $token; + $this->paramStack[] = array(); + $new = array($token); + foreach ($this->addParam as $name => $value) { + $new[] = new HTMLPurifier_Token_Empty('param', array('name' => $name, 'value' => $value)); + } + $token = $new; + } elseif ($token->name == 'param') { + $nest = count($this->currentNesting) - 1; + if ($nest >= 0 && $this->currentNesting[$nest]->name === 'object') { + $i = count($this->objectStack) - 1; + if (!isset($token->attr['name'])) { + $token = false; + return; + } + $n = $token->attr['name']; + // We need this fix because YouTube doesn't supply a data + // attribute, which we need if a type is specified. This is + // *very* Flash specific. + if (!isset($this->objectStack[$i]->attr['data']) && $token->attr['name'] == 'movie') { + $this->objectStack[$i]->attr['data'] = $token->attr['value']; + } + // Check if the parameter is the correct value but has not + // already been added + if ( + !isset($this->paramStack[$i][$n]) && + isset($this->addParam[$n]) && + $token->attr['name'] === $this->addParam[$n] + ) { + // keep token, and add to param stack + $this->paramStack[$i][$n] = true; + } elseif (isset($this->allowedParam[$n])) { + // keep token, don't do anything to it + // (could possibly check for duplicates here) + } else { + $token = false; + } + } else { + // not directly inside an object, DENY! + $token = false; + } + } + } + + public function handleEnd(&$token) { + // This is the WRONG way of handling the object and param stacks; + // we should be inserting them directly on the relevant object tokens + // so that the global stack handling handles it. + if ($token->name == 'object') { + array_pop($this->objectStack); + array_pop($this->paramStack); + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Language.php b/extlib/HTMLPurifier/HTMLPurifier/Language.php new file mode 100644 index 0000000000..3e2be03b58 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Language.php @@ -0,0 +1,163 @@ +config = $config; + $this->context = $context; + } + + /** + * Loads language object with necessary info from factory cache + * @note This is a lazy loader + */ + public function load() { + if ($this->_loaded) return; + $factory = HTMLPurifier_LanguageFactory::instance(); + $factory->loadLanguage($this->code); + foreach ($factory->keys as $key) { + $this->$key = $factory->cache[$this->code][$key]; + } + $this->_loaded = true; + } + + /** + * Retrieves a localised message. + * @param $key string identifier of message + * @return string localised message + */ + public function getMessage($key) { + if (!$this->_loaded) $this->load(); + if (!isset($this->messages[$key])) return "[$key]"; + return $this->messages[$key]; + } + + /** + * Retrieves a localised error name. + * @param $int integer error number, corresponding to PHP's error + * reporting + * @return string localised message + */ + public function getErrorName($int) { + if (!$this->_loaded) $this->load(); + if (!isset($this->errorNames[$int])) return "[Error: $int]"; + return $this->errorNames[$int]; + } + + /** + * Converts an array list into a string readable representation + */ + public function listify($array) { + $sep = $this->getMessage('Item separator'); + $sep_last = $this->getMessage('Item separator last'); + $ret = ''; + for ($i = 0, $c = count($array); $i < $c; $i++) { + if ($i == 0) { + } elseif ($i + 1 < $c) { + $ret .= $sep; + } else { + $ret .= $sep_last; + } + $ret .= $array[$i]; + } + return $ret; + } + + /** + * Formats a localised message with passed parameters + * @param $key string identifier of message + * @param $args Parameters to substitute in + * @return string localised message + * @todo Implement conditionals? Right now, some messages make + * reference to line numbers, but those aren't always available + */ + public function formatMessage($key, $args = array()) { + if (!$this->_loaded) $this->load(); + if (!isset($this->messages[$key])) return "[$key]"; + $raw = $this->messages[$key]; + $subst = array(); + $generator = false; + foreach ($args as $i => $value) { + if (is_object($value)) { + if ($value instanceof HTMLPurifier_Token) { + // factor this out some time + if (!$generator) $generator = $this->context->get('Generator'); + if (isset($value->name)) $subst['$'.$i.'.Name'] = $value->name; + if (isset($value->data)) $subst['$'.$i.'.Data'] = $value->data; + $subst['$'.$i.'.Compact'] = + $subst['$'.$i.'.Serialized'] = $generator->generateFromToken($value); + // a more complex algorithm for compact representation + // could be introduced for all types of tokens. This + // may need to be factored out into a dedicated class + if (!empty($value->attr)) { + $stripped_token = clone $value; + $stripped_token->attr = array(); + $subst['$'.$i.'.Compact'] = $generator->generateFromToken($stripped_token); + } + $subst['$'.$i.'.Line'] = $value->line ? $value->line : 'unknown'; + } + continue; + } elseif (is_array($value)) { + $keys = array_keys($value); + if (array_keys($keys) === $keys) { + // list + $subst['$'.$i] = $this->listify($value); + } else { + // associative array + // no $i implementation yet, sorry + $subst['$'.$i.'.Keys'] = $this->listify($keys); + $subst['$'.$i.'.Values'] = $this->listify(array_values($value)); + } + continue; + } + $subst['$' . $i] = $value; + } + return strtr($raw, $subst); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Language/classes/en-x-test.php b/extlib/HTMLPurifier/HTMLPurifier/Language/classes/en-x-test.php new file mode 100644 index 0000000000..d52fcb7ac1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Language/classes/en-x-test.php @@ -0,0 +1,12 @@ + 'HTML Purifier X' +); + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Language/messages/en-x-testmini.php b/extlib/HTMLPurifier/HTMLPurifier/Language/messages/en-x-testmini.php new file mode 100644 index 0000000000..806c83fbf7 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Language/messages/en-x-testmini.php @@ -0,0 +1,12 @@ + 'HTML Purifier XNone' +); + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Language/messages/en.php b/extlib/HTMLPurifier/HTMLPurifier/Language/messages/en.php new file mode 100644 index 0000000000..aab2e52ebc --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Language/messages/en.php @@ -0,0 +1,62 @@ + 'HTML Purifier', + +// for unit testing purposes +'LanguageFactoryTest: Pizza' => 'Pizza', +'LanguageTest: List' => '$1', +'LanguageTest: Hash' => '$1.Keys; $1.Values', + +'Item separator' => ', ', +'Item separator last' => ' and ', // non-Harvard style + +'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.', +'ErrorCollector: At line' => ' at line $line', +'ErrorCollector: Incidental errors' => 'Incidental errors', + +'Lexer: Unclosed comment' => 'Unclosed comment', +'Lexer: Unescaped lt' => 'Unescaped less-than sign (<) should be <', +'Lexer: Missing gt' => 'Missing greater-than sign (>), previous less-than sign (<) should be escaped', +'Lexer: Missing attribute key' => 'Attribute declaration has no key', +'Lexer: Missing end quote' => 'Attribute declaration has no end quote', + +'Strategy_RemoveForeignElements: Tag transform' => '<$1> element transformed into $CurrentToken.Serialized', +'Strategy_RemoveForeignElements: Missing required attribute' => '$CurrentToken.Compact element missing required attribute $1', +'Strategy_RemoveForeignElements: Foreign element to text' => 'Unrecognized $CurrentToken.Serialized tag converted to text', +'Strategy_RemoveForeignElements: Foreign element removed' => 'Unrecognized $CurrentToken.Serialized tag removed', +'Strategy_RemoveForeignElements: Comment removed' => 'Comment containing "$CurrentToken.Data" removed', +'Strategy_RemoveForeignElements: Foreign meta element removed' => 'Unrecognized $CurrentToken.Serialized meta tag and all descendants removed', +'Strategy_RemoveForeignElements: Token removed to end' => 'Tags and text starting from $1 element where removed to end', +'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' => 'Trailing hyphen(s) in comment removed', +'Strategy_RemoveForeignElements: Hyphens in comment collapsed' => 'Double hyphens in comments are not allowed, and were collapsed into single hyphens', + +'Strategy_MakeWellFormed: Unnecessary end tag removed' => 'Unnecessary $CurrentToken.Serialized tag removed', +'Strategy_MakeWellFormed: Unnecessary end tag to text' => 'Unnecessary $CurrentToken.Serialized tag converted to text', +'Strategy_MakeWellFormed: Tag auto closed' => '$1.Compact started on line $1.Line auto-closed by $CurrentToken.Compact', +'Strategy_MakeWellFormed: Tag carryover' => '$1.Compact started on line $1.Line auto-continued into $CurrentToken.Compact', +'Strategy_MakeWellFormed: Stray end tag removed' => 'Stray $CurrentToken.Serialized tag removed', +'Strategy_MakeWellFormed: Stray end tag to text' => 'Stray $CurrentToken.Serialized tag converted to text', +'Strategy_MakeWellFormed: Tag closed by element end' => '$1.Compact tag started on line $1.Line closed by end of $CurrentToken.Serialized', +'Strategy_MakeWellFormed: Tag closed by document end' => '$1.Compact tag started on line $1.Line closed by end of document', + +'Strategy_FixNesting: Node removed' => '$CurrentToken.Compact node removed', +'Strategy_FixNesting: Node excluded' => '$CurrentToken.Compact node removed due to descendant exclusion by ancestor element', +'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model', +'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed', + +'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys', +'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed', + +); + +$errorNames = array( + E_ERROR => 'Error', + E_WARNING => 'Warning', + E_NOTICE => 'Notice' +); + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/LanguageFactory.php b/extlib/HTMLPurifier/HTMLPurifier/LanguageFactory.php new file mode 100644 index 0000000000..134ef8c745 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/LanguageFactory.php @@ -0,0 +1,198 @@ +cache[$language_code][$key] = $value + * @value array map + */ + public $cache; + + /** + * Valid keys in the HTMLPurifier_Language object. Designates which + * variables to slurp out of a message file. + * @value array list + */ + public $keys = array('fallback', 'messages', 'errorNames'); + + /** + * Instance of HTMLPurifier_AttrDef_Lang to validate language codes + * @value object HTMLPurifier_AttrDef_Lang + */ + protected $validator; + + /** + * Cached copy of dirname(__FILE__), directory of current file without + * trailing slash + * @value string filename + */ + protected $dir; + + /** + * Keys whose contents are a hash map and can be merged + * @value array lookup + */ + protected $mergeable_keys_map = array('messages' => true, 'errorNames' => true); + + /** + * Keys whose contents are a list and can be merged + * @value array lookup + */ + protected $mergeable_keys_list = array(); + + /** + * Retrieve sole instance of the factory. + * @param $prototype Optional prototype to overload sole instance with, + * or bool true to reset to default factory. + */ + public static function instance($prototype = null) { + static $instance = null; + if ($prototype !== null) { + $instance = $prototype; + } elseif ($instance === null || $prototype == true) { + $instance = new HTMLPurifier_LanguageFactory(); + $instance->setup(); + } + return $instance; + } + + /** + * Sets up the singleton, much like a constructor + * @note Prevents people from getting this outside of the singleton + */ + public function setup() { + $this->validator = new HTMLPurifier_AttrDef_Lang(); + $this->dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier'; + } + + /** + * Creates a language object, handles class fallbacks + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + * @param $code Code to override configuration with. Private parameter. + */ + public function create($config, $context, $code = false) { + + // validate language code + if ($code === false) { + $code = $this->validator->validate( + $config->get('Core.Language'), $config, $context + ); + } else { + $code = $this->validator->validate($code, $config, $context); + } + if ($code === false) $code = 'en'; // malformed code becomes English + + $pcode = str_replace('-', '_', $code); // make valid PHP classname + static $depth = 0; // recursion protection + + if ($code == 'en') { + $lang = new HTMLPurifier_Language($config, $context); + } else { + $class = 'HTMLPurifier_Language_' . $pcode; + $file = $this->dir . '/Language/classes/' . $code . '.php'; + if (file_exists($file) || class_exists($class, false)) { + $lang = new $class($config, $context); + } else { + // Go fallback + $raw_fallback = $this->getFallbackFor($code); + $fallback = $raw_fallback ? $raw_fallback : 'en'; + $depth++; + $lang = $this->create($config, $context, $fallback); + if (!$raw_fallback) { + $lang->error = true; + } + $depth--; + } + } + + $lang->code = $code; + + return $lang; + + } + + /** + * Returns the fallback language for language + * @note Loads the original language into cache + * @param $code string language code + */ + public function getFallbackFor($code) { + $this->loadLanguage($code); + return $this->cache[$code]['fallback']; + } + + /** + * Loads language into the cache, handles message file and fallbacks + * @param $code string language code + */ + public function loadLanguage($code) { + static $languages_seen = array(); // recursion guard + + // abort if we've already loaded it + if (isset($this->cache[$code])) return; + + // generate filename + $filename = $this->dir . '/Language/messages/' . $code . '.php'; + + // default fallback : may be overwritten by the ensuing include + $fallback = ($code != 'en') ? 'en' : false; + + // load primary localisation + if (!file_exists($filename)) { + // skip the include: will rely solely on fallback + $filename = $this->dir . '/Language/messages/en.php'; + $cache = array(); + } else { + include $filename; + $cache = compact($this->keys); + } + + // load fallback localisation + if (!empty($fallback)) { + + // infinite recursion guard + if (isset($languages_seen[$code])) { + trigger_error('Circular fallback reference in language ' . + $code, E_USER_ERROR); + $fallback = 'en'; + } + $language_seen[$code] = true; + + // load the fallback recursively + $this->loadLanguage($fallback); + $fallback_cache = $this->cache[$fallback]; + + // merge fallback with current language + foreach ( $this->keys as $key ) { + if (isset($cache[$key]) && isset($fallback_cache[$key])) { + if (isset($this->mergeable_keys_map[$key])) { + $cache[$key] = $cache[$key] + $fallback_cache[$key]; + } elseif (isset($this->mergeable_keys_list[$key])) { + $cache[$key] = array_merge( $fallback_cache[$key], $cache[$key] ); + } + } else { + $cache[$key] = $fallback_cache[$key]; + } + } + + } + + // save to cache for later retrieval + $this->cache[$code] = $cache; + + return; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Length.php b/extlib/HTMLPurifier/HTMLPurifier/Length.php new file mode 100644 index 0000000000..8d2a46b7da --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Length.php @@ -0,0 +1,115 @@ + true, 'ex' => true, 'px' => true, 'in' => true, + 'cm' => true, 'mm' => true, 'pt' => true, 'pc' => true + ); + + /** + * @param number $n Magnitude + * @param string $u Unit + */ + public function __construct($n = '0', $u = false) { + $this->n = (string) $n; + $this->unit = $u !== false ? (string) $u : false; + } + + /** + * @param string $s Unit string, like '2em' or '3.4in' + * @warning Does not perform validation. + */ + static public function make($s) { + if ($s instanceof HTMLPurifier_Length) return $s; + $n_length = strspn($s, '1234567890.+-'); + $n = substr($s, 0, $n_length); + $unit = substr($s, $n_length); + if ($unit === '') $unit = false; + return new HTMLPurifier_Length($n, $unit); + } + + /** + * Validates the number and unit. + */ + protected function validate() { + // Special case: + if ($this->n === '+0' || $this->n === '-0') $this->n = '0'; + if ($this->n === '0' && $this->unit === false) return true; + if (!ctype_lower($this->unit)) $this->unit = strtolower($this->unit); + if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) return false; + // Hack: + $def = new HTMLPurifier_AttrDef_CSS_Number(); + $result = $def->validate($this->n, false, false); + if ($result === false) return false; + $this->n = $result; + return true; + } + + /** + * Returns string representation of number. + */ + public function toString() { + if (!$this->isValid()) return false; + return $this->n . $this->unit; + } + + /** + * Retrieves string numeric magnitude. + */ + public function getN() {return $this->n;} + + /** + * Retrieves string unit. + */ + public function getUnit() {return $this->unit;} + + /** + * Returns true if this length unit is valid. + */ + public function isValid() { + if ($this->isValid === null) $this->isValid = $this->validate(); + return $this->isValid; + } + + /** + * Compares two lengths, and returns 1 if greater, -1 if less and 0 if equal. + * @warning If both values are too large or small, this calculation will + * not work properly + */ + public function compareTo($l) { + if ($l === false) return false; + if ($l->unit !== $this->unit) { + $converter = new HTMLPurifier_UnitConverter(); + $l = $converter->convert($l, $this->unit); + if ($l === false) return false; + } + return $this->n - $l->n; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Lexer.php b/extlib/HTMLPurifier/HTMLPurifier/Lexer.php new file mode 100644 index 0000000000..8cce008d3d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Lexer.php @@ -0,0 +1,298 @@ +get('Core.LexerImpl'); + } + + $needs_tracking = + $config->get('Core.MaintainLineNumbers') || + $config->get('Core.CollectErrors'); + + $inst = null; + if (is_object($lexer)) { + $inst = $lexer; + } else { + + if (is_null($lexer)) { do { + // auto-detection algorithm + + if ($needs_tracking) { + $lexer = 'DirectLex'; + break; + } + + if ( + class_exists('DOMDocument') && + method_exists('DOMDocument', 'loadHTML') && + !extension_loaded('domxml') + ) { + // check for DOM support, because while it's part of the + // core, it can be disabled compile time. Also, the PECL + // domxml extension overrides the default DOM, and is evil + // and nasty and we shan't bother to support it + $lexer = 'DOMLex'; + } else { + $lexer = 'DirectLex'; + } + + } while(0); } // do..while so we can break + + // instantiate recognized string names + switch ($lexer) { + case 'DOMLex': + $inst = new HTMLPurifier_Lexer_DOMLex(); + break; + case 'DirectLex': + $inst = new HTMLPurifier_Lexer_DirectLex(); + break; + case 'PH5P': + $inst = new HTMLPurifier_Lexer_PH5P(); + break; + default: + throw new HTMLPurifier_Exception("Cannot instantiate unrecognized Lexer type " . htmlspecialchars($lexer)); + } + } + + if (!$inst) throw new HTMLPurifier_Exception('No lexer was instantiated'); + + // once PHP DOM implements native line numbers, or we + // hack out something using XSLT, remove this stipulation + if ($needs_tracking && !$inst->tracksLineNumbers) { + throw new HTMLPurifier_Exception('Cannot use lexer that does not support line numbers with Core.MaintainLineNumbers or Core.CollectErrors (use DirectLex instead)'); + } + + return $inst; + + } + + // -- CONVENIENCE MEMBERS --------------------------------------------- + + public function __construct() { + $this->_entity_parser = new HTMLPurifier_EntityParser(); + } + + /** + * Most common entity to raw value conversion table for special entities. + */ + protected $_special_entity2str = + array( + '"' => '"', + '&' => '&', + '<' => '<', + '>' => '>', + ''' => "'", + ''' => "'", + ''' => "'" + ); + + /** + * Parses special entities into the proper characters. + * + * This string will translate escaped versions of the special characters + * into the correct ones. + * + * @warning + * You should be able to treat the output of this function as + * completely parsed, but that's only because all other entities should + * have been handled previously in substituteNonSpecialEntities() + * + * @param $string String character data to be parsed. + * @returns Parsed character data. + */ + public function parseData($string) { + + // following functions require at least one character + if ($string === '') return ''; + + // subtracts amps that cannot possibly be escaped + $num_amp = substr_count($string, '&') - substr_count($string, '& ') - + ($string[strlen($string)-1] === '&' ? 1 : 0); + + if (!$num_amp) return $string; // abort if no entities + $num_esc_amp = substr_count($string, '&'); + $string = strtr($string, $this->_special_entity2str); + + // code duplication for sake of optimization, see above + $num_amp_2 = substr_count($string, '&') - substr_count($string, '& ') - + ($string[strlen($string)-1] === '&' ? 1 : 0); + + if ($num_amp_2 <= $num_esc_amp) return $string; + + // hmm... now we have some uncommon entities. Use the callback. + $string = $this->_entity_parser->substituteSpecialEntities($string); + return $string; + } + + /** + * Lexes an HTML string into tokens. + * + * @param $string String HTML. + * @return HTMLPurifier_Token array representation of HTML. + */ + public function tokenizeHTML($string, $config, $context) { + trigger_error('Call to abstract class', E_USER_ERROR); + } + + /** + * Translates CDATA sections into regular sections (through escaping). + * + * @param $string HTML string to process. + * @returns HTML with CDATA sections escaped. + */ + protected static function escapeCDATA($string) { + return preg_replace_callback( + '//s', + array('HTMLPurifier_Lexer', 'CDATACallback'), + $string + ); + } + + /** + * Special CDATA case that is especially convoluted for )#si', + array($this, 'scriptCallback'), $html); + } + + $html = $this->normalize($html, $config, $context); + + $cursor = 0; // our location in the text + $inside_tag = false; // whether or not we're parsing the inside of a tag + $array = array(); // result array + + // This is also treated to mean maintain *column* numbers too + $maintain_line_numbers = $config->get('Core.MaintainLineNumbers'); + + if ($maintain_line_numbers === null) { + // automatically determine line numbering by checking + // if error collection is on + $maintain_line_numbers = $config->get('Core.CollectErrors'); + } + + if ($maintain_line_numbers) { + $current_line = 1; + $current_col = 0; + $length = strlen($html); + } else { + $current_line = false; + $current_col = false; + $length = false; + } + $context->register('CurrentLine', $current_line); + $context->register('CurrentCol', $current_col); + $nl = "\n"; + // how often to manually recalculate. This will ALWAYS be right, + // but it's pretty wasteful. Set to 0 to turn off + $synchronize_interval = $config->get('Core.DirectLexLineNumberSyncInterval'); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // for testing synchronization + $loops = 0; + + while(++$loops) { + + // $cursor is either at the start of a token, or inside of + // a tag (i.e. there was a < immediately before it), as indicated + // by $inside_tag + + if ($maintain_line_numbers) { + + // $rcursor, however, is always at the start of a token. + $rcursor = $cursor - (int) $inside_tag; + + // Column number is cheap, so we calculate it every round. + // We're interested at the *end* of the newline string, so + // we need to add strlen($nl) == 1 to $nl_pos before subtracting it + // from our "rcursor" position. + $nl_pos = strrpos($html, $nl, $rcursor - $length); + $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); + + // recalculate lines + if ( + $synchronize_interval && // synchronization is on + $cursor > 0 && // cursor is further than zero + $loops % $synchronize_interval === 0 // time to synchronize! + ) { + $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); + } + + } + + $position_next_lt = strpos($html, '<', $cursor); + $position_next_gt = strpos($html, '>', $cursor); + + // triggers on "asdf" but not "asdf " + // special case to set up context + if ($position_next_lt === $cursor) { + $inside_tag = true; + $cursor++; + } + + if (!$inside_tag && $position_next_lt !== false) { + // We are not inside tag and there still is another tag to parse + $token = new + HTMLPurifier_Token_Text( + $this->parseData( + substr( + $html, $cursor, $position_next_lt - $cursor + ) + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); + } + $array[] = $token; + $cursor = $position_next_lt + 1; + $inside_tag = true; + continue; + } elseif (!$inside_tag) { + // We are not inside tag but there are no more tags + // If we're already at the end, break + if ($cursor === strlen($html)) break; + // Create Text of rest of string + $token = new + HTMLPurifier_Token_Text( + $this->parseData( + substr( + $html, $cursor + ) + ) + ); + if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); + $array[] = $token; + break; + } elseif ($inside_tag && $position_next_gt !== false) { + // We are in tag and it is well formed + // Grab the internals of the tag + $strlen_segment = $position_next_gt - $cursor; + + if ($strlen_segment < 1) { + // there's nothing to process! + $token = new HTMLPurifier_Token_Text('<'); + $cursor++; + continue; + } + + $segment = substr($html, $cursor, $strlen_segment); + + if ($segment === false) { + // somehow, we attempted to access beyond the end of + // the string, defense-in-depth, reported by Nate Abele + break; + } + + // Check if it's a comment + if ( + substr($segment, 0, 3) === '!--' + ) { + // re-determine segment length, looking for --> + $position_comment_end = strpos($html, '-->', $cursor); + if ($position_comment_end === false) { + // uh oh, we have a comment that extends to + // infinity. Can't be helped: set comment + // end position to end of string + if ($e) $e->send(E_WARNING, 'Lexer: Unclosed comment'); + $position_comment_end = strlen($html); + $end = true; + } else { + $end = false; + } + $strlen_segment = $position_comment_end - $cursor; + $segment = substr($html, $cursor, $strlen_segment); + $token = new + HTMLPurifier_Token_Comment( + substr( + $segment, 3, $strlen_segment - 3 + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); + } + $array[] = $token; + $cursor = $end ? $position_comment_end : $position_comment_end + 3; + $inside_tag = false; + continue; + } + + // Check if it's an end tag + $is_end_tag = (strpos($segment,'/') === 0); + if ($is_end_tag) { + $type = substr($segment, 1); + $token = new HTMLPurifier_Token_End($type); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Check leading character is alnum, if not, we may + // have accidently grabbed an emoticon. Translate into + // text and go our merry way + if (!ctype_alpha($segment[0])) { + // XML: $segment[0] !== '_' && $segment[0] !== ':' + if ($e) $e->send(E_NOTICE, 'Lexer: Unescaped lt'); + $token = new HTMLPurifier_Token_Text('<'); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + continue; + } + + // Check if it is explicitly self closing, if so, remove + // trailing slash. Remember, we could have a tag like
    , so + // any later token processing scripts must convert improperly + // classified EmptyTags from StartTags. + $is_self_closing = (strrpos($segment,'/') === $strlen_segment-1); + if ($is_self_closing) { + $strlen_segment--; + $segment = substr($segment, 0, $strlen_segment); + } + + // Check if there are any attributes + $position_first_space = strcspn($segment, $this->_whitespace); + + if ($position_first_space >= $strlen_segment) { + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($segment); + } else { + $token = new HTMLPurifier_Token_Start($segment); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Grab out all the data + $type = substr($segment, 0, $position_first_space); + $attribute_string = + trim( + substr( + $segment, $position_first_space + ) + ); + if ($attribute_string) { + $attr = $this->parseAttributeString( + $attribute_string + , $config, $context + ); + } else { + $attr = array(); + } + + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($type, $attr); + } else { + $token = new HTMLPurifier_Token_Start($type, $attr); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $cursor = $position_next_gt + 1; + $inside_tag = false; + continue; + } else { + // inside tag, but there's no ending > sign + if ($e) $e->send(E_WARNING, 'Lexer: Missing gt'); + $token = new + HTMLPurifier_Token_Text( + '<' . + $this->parseData( + substr($html, $cursor) + ) + ); + if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); + // no cursor scroll? Hmm... + $array[] = $token; + break; + } + break; + } + + $context->destroy('CurrentLine'); + $context->destroy('CurrentCol'); + return $array; + } + + /** + * PHP 5.0.x compatible substr_count that implements offset and length + */ + protected function substrCount($haystack, $needle, $offset, $length) { + static $oldVersion; + if ($oldVersion === null) { + $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); + } + if ($oldVersion) { + $haystack = substr($haystack, $offset, $length); + return substr_count($haystack, $needle); + } else { + return substr_count($haystack, $needle, $offset, $length); + } + } + + /** + * Takes the inside of an HTML tag and makes an assoc array of attributes. + * + * @param $string Inside of tag excluding name. + * @returns Assoc array of attributes. + */ + public function parseAttributeString($string, $config, $context) { + $string = (string) $string; // quick typecast + + if ($string == '') return array(); // no attributes + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // let's see if we can abort as quickly as possible + // one equal sign, no spaces => one attribute + $num_equal = substr_count($string, '='); + $has_space = strpos($string, ' '); + if ($num_equal === 0 && !$has_space) { + // bool attribute + return array($string => $string); + } elseif ($num_equal === 1 && !$has_space) { + // only one attribute + list($key, $quoted_value) = explode('=', $string); + $quoted_value = trim($quoted_value); + if (!$key) { + if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); + return array(); + } + if (!$quoted_value) return array($key => ''); + $first_char = @$quoted_value[0]; + $last_char = @$quoted_value[strlen($quoted_value)-1]; + + $same_quote = ($first_char == $last_char); + $open_quote = ($first_char == '"' || $first_char == "'"); + + if ( $same_quote && $open_quote) { + // well behaved + $value = substr($quoted_value, 1, strlen($quoted_value) - 2); + } else { + // not well behaved + if ($open_quote) { + if ($e) $e->send(E_ERROR, 'Lexer: Missing end quote'); + $value = substr($quoted_value, 1); + } else { + $value = $quoted_value; + } + } + if ($value === false) $value = ''; + return array($key => $value); + } + + // setup loop environment + $array = array(); // return assoc array of attributes + $cursor = 0; // current position in string (moves forward) + $size = strlen($string); // size of the string (stays the same) + + // if we have unquoted attributes, the parser expects a terminating + // space, so let's guarantee that there's always a terminating space. + $string .= ' '; + + while(true) { + + if ($cursor >= $size) { + break; + } + + $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); + // grab the key + + $key_begin = $cursor; //we're currently at the start of the key + + // scroll past all characters that are the key (not whitespace or =) + $cursor += strcspn($string, $this->_whitespace . '=', $cursor); + + $key_end = $cursor; // now at the end of the key + + $key = substr($string, $key_begin, $key_end - $key_begin); + + if (!$key) { + if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); + $cursor += strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop + continue; // empty key + } + + // scroll past all whitespace + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor >= $size) { + $array[$key] = $key; + break; + } + + // if the next character is an equal sign, we've got a regular + // pair, otherwise, it's a bool attribute + $first_char = @$string[$cursor]; + + if ($first_char == '=') { + // key="value" + + $cursor++; + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor === false) { + $array[$key] = ''; + break; + } + + // we might be in front of a quote right now + + $char = @$string[$cursor]; + + if ($char == '"' || $char == "'") { + // it's quoted, end bound is $char + $cursor++; + $value_begin = $cursor; + $cursor = strpos($string, $char, $cursor); + $value_end = $cursor; + } else { + // it's not quoted, end bound is whitespace + $value_begin = $cursor; + $cursor += strcspn($string, $this->_whitespace, $cursor); + $value_end = $cursor; + } + + // we reached a premature end + if ($cursor === false) { + $cursor = $size; + $value_end = $cursor; + } + + $value = substr($string, $value_begin, $value_end - $value_begin); + if ($value === false) $value = ''; + $array[$key] = $this->parseData($value); + $cursor++; + + } else { + // boolattr + if ($key !== '') { + $array[$key] = $key; + } else { + // purely theoretical + if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + + } + } + return $array; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php b/extlib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php new file mode 100644 index 0000000000..57cffa82ab --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php @@ -0,0 +1,106 @@ +tokens = array(); + + $string = $this->normalize($string, $config, $context); + + $parser = new XML_HTMLSax3(); + $parser->set_object($this); + $parser->set_element_handler('openHandler','closeHandler'); + $parser->set_data_handler('dataHandler'); + $parser->set_escape_handler('escapeHandler'); + + // doesn't seem to work correctly for attributes + $parser->set_option('XML_OPTION_ENTITIES_PARSED', 1); + + $parser->parse($string); + + return $this->tokens; + + } + + /** + * Open tag event handler, interface is defined by PEAR package. + */ + public function openHandler(&$parser, $name, $attrs, $closed) { + // entities are not resolved in attrs + foreach ($attrs as $key => $attr) { + $attrs[$key] = $this->parseData($attr); + } + if ($closed) { + $this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs); + } else { + $this->tokens[] = new HTMLPurifier_Token_Start($name, $attrs); + } + return true; + } + + /** + * Close tag event handler, interface is defined by PEAR package. + */ + public function closeHandler(&$parser, $name) { + // HTMLSax3 seems to always send empty tags an extra close tag + // check and ignore if you see it: + // [TESTME] to make sure it doesn't overreach + if ($this->tokens[count($this->tokens)-1] instanceof HTMLPurifier_Token_Empty) { + return true; + } + $this->tokens[] = new HTMLPurifier_Token_End($name); + return true; + } + + /** + * Data event handler, interface is defined by PEAR package. + */ + public function dataHandler(&$parser, $data) { + $this->tokens[] = new HTMLPurifier_Token_Text($data); + return true; + } + + /** + * Escaped text handler, interface is defined by PEAR package. + */ + public function escapeHandler(&$parser, $data) { + if (strpos($data, '--') === 0) { + $this->tokens[] = new HTMLPurifier_Token_Comment($data); + } + // CDATA is handled elsewhere, but if it was handled here: + //if (strpos($data, '[CDATA[') === 0) { + // $this->tokens[] = new HTMLPurifier_Token_Text( + // substr($data, 7, strlen($data) - 9) ); + //} + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php b/extlib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php new file mode 100644 index 0000000000..fa1bf973e0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php @@ -0,0 +1,3906 @@ +normalize($html, $config, $context); + $new_html = $this->wrapHTML($new_html, $config, $context); + try { + $parser = new HTML5($new_html); + $doc = $parser->save(); + } catch (DOMException $e) { + // Uh oh, it failed. Punt to DirectLex. + $lexer = new HTMLPurifier_Lexer_DirectLex(); + $context->register('PH5PError', $e); // save the error, so we can detect it + return $lexer->tokenizeHTML($html, $config, $context); // use original HTML + } + $tokens = array(); + $this->tokenizeDOM( + $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0)-> // + getElementsByTagName('div')->item(0) //
    + , $tokens); + return $tokens; + } + +} + +/* + +Copyright 2007 Jeroen van der Meer + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +class HTML5 { + private $data; + private $char; + private $EOF; + private $state; + private $tree; + private $token; + private $content_model; + private $escape = false; + private $entities = array('AElig;','AElig','AMP;','AMP','Aacute;','Aacute', + 'Acirc;','Acirc','Agrave;','Agrave','Alpha;','Aring;','Aring','Atilde;', + 'Atilde','Auml;','Auml','Beta;','COPY;','COPY','Ccedil;','Ccedil','Chi;', + 'Dagger;','Delta;','ETH;','ETH','Eacute;','Eacute','Ecirc;','Ecirc','Egrave;', + 'Egrave','Epsilon;','Eta;','Euml;','Euml','GT;','GT','Gamma;','Iacute;', + 'Iacute','Icirc;','Icirc','Igrave;','Igrave','Iota;','Iuml;','Iuml','Kappa;', + 'LT;','LT','Lambda;','Mu;','Ntilde;','Ntilde','Nu;','OElig;','Oacute;', + 'Oacute','Ocirc;','Ocirc','Ograve;','Ograve','Omega;','Omicron;','Oslash;', + 'Oslash','Otilde;','Otilde','Ouml;','Ouml','Phi;','Pi;','Prime;','Psi;', + 'QUOT;','QUOT','REG;','REG','Rho;','Scaron;','Sigma;','THORN;','THORN', + 'TRADE;','Tau;','Theta;','Uacute;','Uacute','Ucirc;','Ucirc','Ugrave;', + 'Ugrave','Upsilon;','Uuml;','Uuml','Xi;','Yacute;','Yacute','Yuml;','Zeta;', + 'aacute;','aacute','acirc;','acirc','acute;','acute','aelig;','aelig', + 'agrave;','agrave','alefsym;','alpha;','amp;','amp','and;','ang;','apos;', + 'aring;','aring','asymp;','atilde;','atilde','auml;','auml','bdquo;','beta;', + 'brvbar;','brvbar','bull;','cap;','ccedil;','ccedil','cedil;','cedil', + 'cent;','cent','chi;','circ;','clubs;','cong;','copy;','copy','crarr;', + 'cup;','curren;','curren','dArr;','dagger;','darr;','deg;','deg','delta;', + 'diams;','divide;','divide','eacute;','eacute','ecirc;','ecirc','egrave;', + 'egrave','empty;','emsp;','ensp;','epsilon;','equiv;','eta;','eth;','eth', + 'euml;','euml','euro;','exist;','fnof;','forall;','frac12;','frac12', + 'frac14;','frac14','frac34;','frac34','frasl;','gamma;','ge;','gt;','gt', + 'hArr;','harr;','hearts;','hellip;','iacute;','iacute','icirc;','icirc', + 'iexcl;','iexcl','igrave;','igrave','image;','infin;','int;','iota;', + 'iquest;','iquest','isin;','iuml;','iuml','kappa;','lArr;','lambda;','lang;', + 'laquo;','laquo','larr;','lceil;','ldquo;','le;','lfloor;','lowast;','loz;', + 'lrm;','lsaquo;','lsquo;','lt;','lt','macr;','macr','mdash;','micro;','micro', + 'middot;','middot','minus;','mu;','nabla;','nbsp;','nbsp','ndash;','ne;', + 'ni;','not;','not','notin;','nsub;','ntilde;','ntilde','nu;','oacute;', + 'oacute','ocirc;','ocirc','oelig;','ograve;','ograve','oline;','omega;', + 'omicron;','oplus;','or;','ordf;','ordf','ordm;','ordm','oslash;','oslash', + 'otilde;','otilde','otimes;','ouml;','ouml','para;','para','part;','permil;', + 'perp;','phi;','pi;','piv;','plusmn;','plusmn','pound;','pound','prime;', + 'prod;','prop;','psi;','quot;','quot','rArr;','radic;','rang;','raquo;', + 'raquo','rarr;','rceil;','rdquo;','real;','reg;','reg','rfloor;','rho;', + 'rlm;','rsaquo;','rsquo;','sbquo;','scaron;','sdot;','sect;','sect','shy;', + 'shy','sigma;','sigmaf;','sim;','spades;','sub;','sube;','sum;','sup1;', + 'sup1','sup2;','sup2','sup3;','sup3','sup;','supe;','szlig;','szlig','tau;', + 'there4;','theta;','thetasym;','thinsp;','thorn;','thorn','tilde;','times;', + 'times','trade;','uArr;','uacute;','uacute','uarr;','ucirc;','ucirc', + 'ugrave;','ugrave','uml;','uml','upsih;','upsilon;','uuml;','uuml','weierp;', + 'xi;','yacute;','yacute','yen;','yen','yuml;','yuml','zeta;','zwj;','zwnj;'); + + const PCDATA = 0; + const RCDATA = 1; + const CDATA = 2; + const PLAINTEXT = 3; + + const DOCTYPE = 0; + const STARTTAG = 1; + const ENDTAG = 2; + const COMMENT = 3; + const CHARACTR = 4; + const EOF = 5; + + public function __construct($data) { + $data = str_replace("\r\n", "\n", $data); + $data = str_replace("\r", null, $data); + + $this->data = $data; + $this->char = -1; + $this->EOF = strlen($data); + $this->tree = new HTML5TreeConstructer; + $this->content_model = self::PCDATA; + + $this->state = 'data'; + + while($this->state !== null) { + $this->{$this->state.'State'}(); + } + } + + public function save() { + return $this->tree->save(); + } + + private function char() { + return ($this->char < $this->EOF) + ? $this->data[$this->char] + : false; + } + + private function character($s, $l = 0) { + if($s + $l < $this->EOF) { + if($l === 0) { + return $this->data[$s]; + } else { + return substr($this->data, $s, $l); + } + } + } + + private function characters($char_class, $start) { + return preg_replace('#^(['.$char_class.']+).*#s', '\\1', substr($this->data, $start)); + } + + private function dataState() { + // Consume the next input character + $this->char++; + $char = $this->char(); + + if($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { + /* U+0026 AMPERSAND (&) + When the content model flag is set to one of the PCDATA or RCDATA + states: switch to the entity data state. Otherwise: treat it as per + the "anything else" entry below. */ + $this->state = 'entityData'; + + } elseif($char === '-') { + /* If the content model flag is set to either the RCDATA state or + the CDATA state, and the escape flag is false, and there are at + least three characters before this one in the input stream, and the + last four characters in the input stream, including this one, are + U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, + and U+002D HYPHEN-MINUS (""), + set the escape flag to false. */ + if(($this->content_model === self::RCDATA || + $this->content_model === self::CDATA) && $this->escape === true && + $this->character($this->char, 3) === '-->') { + $this->escape = false; + } + + /* In any case, emit the input character as a character token. + Stay in the data state. */ + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => $char + )); + + } elseif($this->char === $this->EOF) { + /* EOF + Emit an end-of-file token. */ + $this->EOF(); + + } elseif($this->content_model === self::PLAINTEXT) { + /* When the content model flag is set to the PLAINTEXT state + THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of + the text and emit it as a character token. */ + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => substr($this->data, $this->char) + )); + + $this->EOF(); + + } else { + /* Anything else + THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that + otherwise would also be treated as a character token and emit it + as a single character token. Stay in the data state. */ + $len = strcspn($this->data, '<&', $this->char); + $char = substr($this->data, $this->char, $len); + $this->char += $len - 1; + + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => $char + )); + + $this->state = 'data'; + } + } + + private function entityDataState() { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, emit a U+0026 AMPERSAND character token. + // Otherwise, emit the character token that was returned. + $char = (!$entity) ? '&' : $entity; + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => $char + )); + + // Finally, switch to the data state. + $this->state = 'data'; + } + + private function tagOpenState() { + switch($this->content_model) { + case self::RCDATA: + case self::CDATA: + /* If the next input character is a U+002F SOLIDUS (/) character, + consume it and switch to the close tag open state. If the next + input character is not a U+002F SOLIDUS (/) character, emit a + U+003C LESS-THAN SIGN character token and switch to the data + state to process the next input character. */ + if($this->character($this->char + 1) === '/') { + $this->char++; + $this->state = 'closeTagOpen'; + + } else { + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => '<' + )); + + $this->state = 'data'; + } + break; + + case self::PCDATA: + // If the content model flag is set to the PCDATA state + // Consume the next input character: + $this->char++; + $char = $this->char(); + + if($char === '!') { + /* U+0021 EXCLAMATION MARK (!) + Switch to the markup declaration open state. */ + $this->state = 'markupDeclarationOpen'; + + } elseif($char === '/') { + /* U+002F SOLIDUS (/) + Switch to the close tag open state. */ + $this->state = 'closeTagOpen'; + + } elseif(preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new start tag token, set its tag name to the lowercase + version of the input character (add 0x0020 to the character's code + point), then switch to the tag name state. (Don't emit the token + yet; further details will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::STARTTAG, + 'attr' => array() + ); + + $this->state = 'tagName'; + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Emit a U+003C LESS-THAN SIGN character token and a + U+003E GREATER-THAN SIGN character token. Switch to the data state. */ + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => '<>' + )); + + $this->state = 'data'; + + } elseif($char === '?') { + /* U+003F QUESTION MARK (?) + Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + + } else { + /* Anything else + Parse error. Emit a U+003C LESS-THAN SIGN character token and + reconsume the current input character in the data state. */ + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => '<' + )); + + $this->char--; + $this->state = 'data'; + } + break; + } + } + + private function closeTagOpenState() { + $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); + $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; + + if(($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && + (!$the_same || ($the_same && (!preg_match('/[\t\n\x0b\x0c >\/]/', + $this->character($this->char + 1 + strlen($next_node))) || $this->EOF === $this->char)))) { + /* If the content model flag is set to the RCDATA or CDATA states then + examine the next few characters. If they do not match the tag name of + the last start tag token emitted (case insensitively), or if they do but + they are not immediately followed by one of the following characters: + * U+0009 CHARACTER TABULATION + * U+000A LINE FEED (LF) + * U+000B LINE TABULATION + * U+000C FORM FEED (FF) + * U+0020 SPACE + * U+003E GREATER-THAN SIGN (>) + * U+002F SOLIDUS (/) + * EOF + ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character + token, a U+002F SOLIDUS character token, and switch to the data state + to process the next input character. */ + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => 'state = 'data'; + + } else { + /* Otherwise, if the content model flag is set to the PCDATA state, + or if the next few characters do match that tag name, consume the + next input character: */ + $this->char++; + $char = $this->char(); + + if(preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new end tag token, set its tag name to the lowercase version + of the input character (add 0x0020 to the character's code point), then + switch to the tag name state. (Don't emit the token yet; further details + will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::ENDTAG + ); + + $this->state = 'tagName'; + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Switch to the data state. */ + $this->state = 'data'; + + } elseif($this->char === $this->EOF) { + /* EOF + Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F + SOLIDUS character token. Reconsume the EOF character in the data state. */ + $this->emitToken(array( + 'type' => self::CHARACTR, + 'data' => 'char--; + $this->state = 'data'; + + } else { + /* Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + } + } + } + + private function tagNameState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } elseif($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } else { + /* Anything else + Append the current input character to the current tag token's tag name. + Stay in the tag name state. */ + $this->token['name'] .= strtolower($char); + $this->state = 'tagName'; + } + } + + private function beforeAttributeNameState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Stay in the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function attributeNameState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's name. + Stay in the attribute name state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['name'] .= strtolower($char); + + $this->state = 'attributeName'; + } + } + + private function afterAttributeNameState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the after attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the + before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function beforeAttributeValueState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the attribute value (double-quoted) state. */ + $this->state = 'attributeValueDoubleQuoted'; + + } elseif($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the attribute value (unquoted) state and reconsume + this input character. */ + $this->char--; + $this->state = 'attributeValueUnquoted'; + + } elseif($char === '\'') { + /* U+0027 APOSTROPHE (') + Switch to the attribute value (single-quoted) state. */ + $this->state = 'attributeValueSingleQuoted'; + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Switch to the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function attributeValueDoubleQuotedState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('double'); + + } elseif($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (double-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueDoubleQuoted'; + } + } + + private function attributeValueSingleQuotedState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if($char === '\'') { + /* U+0022 QUOTATION MARK (') + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('single'); + + } elseif($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (single-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueSingleQuoted'; + } + } + + private function attributeValueUnquotedState() { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState(); + + } elseif($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function entityInAttributeValueState() { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, append a U+0026 AMPERSAND character to the + // current attribute's value. Otherwise, emit the character token that + // was returned. + $char = (!$entity) + ? '&' + : $entity; + + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + } + + private function bogusCommentState() { + /* Consume every character up to the first U+003E GREATER-THAN SIGN + character (>) or the end of the file (EOF), whichever comes first. Emit + a comment token whose data is the concatenation of all the characters + starting from and including the character that caused the state machine + to switch into the bogus comment state, up to and including the last + consumed character before the U+003E character, if any, or up to the + end of the file otherwise. (If the comment was started by the end of + the file (EOF), the token is empty.) */ + $data = $this->characters('^>', $this->char); + $this->emitToken(array( + 'data' => $data, + 'type' => self::COMMENT + )); + + $this->char += strlen($data); + + /* Switch to the data state. */ + $this->state = 'data'; + + /* If the end of the file was reached, reconsume the EOF character. */ + if($this->char === $this->EOF) { + $this->char = $this->EOF - 1; + } + } + + private function markupDeclarationOpenState() { + /* If the next two characters are both U+002D HYPHEN-MINUS (-) + characters, consume those two characters, create a comment token whose + data is the empty string, and switch to the comment state. */ + if($this->character($this->char + 1, 2) === '--') { + $this->char += 2; + $this->state = 'comment'; + $this->token = array( + 'data' => null, + 'type' => self::COMMENT + ); + + /* Otherwise if the next seven chacacters are a case-insensitive match + for the word "DOCTYPE", then consume those characters and switch to the + DOCTYPE state. */ + } elseif(strtolower($this->character($this->char + 1, 7)) === 'doctype') { + $this->char += 7; + $this->state = 'doctype'; + + /* Otherwise, is is a parse error. Switch to the bogus comment state. + The next character that is consumed, if any, is the first character + that will be in the comment. */ + } else { + $this->char++; + $this->state = 'bogusComment'; + } + } + + private function commentState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if($char === '-') { + /* Switch to the comment dash state */ + $this->state = 'commentDash'; + + /* EOF */ + } elseif($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append the input character to the comment token's data. Stay in + the comment state. */ + $this->token['data'] .= $char; + } + } + + private function commentDashState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if($char === '-') { + /* Switch to the comment end state */ + $this->state = 'commentEnd'; + + /* EOF */ + } elseif($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append a U+002D HYPHEN-MINUS (-) character and the input + character to the comment token's data. Switch to the comment state. */ + $this->token['data'] .= '-'.$char; + $this->state = 'comment'; + } + } + + private function commentEndState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif($char === '-') { + $this->token['data'] .= '-'; + + } elseif($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['data'] .= '--'.$char; + $this->state = 'comment'; + } + } + + private function doctypeState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'beforeDoctypeName'; + + } else { + $this->char--; + $this->state = 'beforeDoctypeName'; + } + } + + private function beforeDoctypeNameState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the before DOCTYPE name state. + + } elseif(preg_match('/^[a-z]$/', $char)) { + $this->token = array( + 'name' => strtoupper($char), + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + + } elseif($char === '>') { + $this->emitToken(array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + )); + + $this->state = 'data'; + + } elseif($this->char === $this->EOF) { + $this->emitToken(array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + )); + + $this->char--; + $this->state = 'data'; + + } else { + $this->token = array( + 'name' => $char, + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + } + } + + private function doctypeNameState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'AfterDoctypeName'; + + } elseif($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif(preg_match('/^[a-z]$/', $char)) { + $this->token['name'] .= strtoupper($char); + + } elseif($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['name'] .= $char; + } + + $this->token['error'] = ($this->token['name'] === 'HTML') + ? false + : true; + } + + private function afterDoctypeNameState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the DOCTYPE name state. + + } elseif($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['error'] = true; + $this->state = 'bogusDoctype'; + } + } + + private function bogusDoctypeState() { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + // Stay in the bogus DOCTYPE state. + } + } + + private function entity() { + $start = $this->char; + + // This section defines how to consume an entity. This definition is + // used when parsing entities in text and in attributes. + + // The behaviour depends on the identity of the next character (the + // one immediately after the U+0026 AMPERSAND character): + + switch($this->character($this->char + 1)) { + // U+0023 NUMBER SIGN (#) + case '#': + + // The behaviour further depends on the character after the + // U+0023 NUMBER SIGN: + switch($this->character($this->char + 1)) { + // U+0078 LATIN SMALL LETTER X + // U+0058 LATIN CAPITAL LETTER X + case 'x': + case 'X': + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 + // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER + // A, through to U+0046 LATIN CAPITAL LETTER F (in other + // words, 0-9, A-F, a-f). + $char = 1; + $char_class = '0-9A-Fa-f'; + break; + + // Anything else + default: + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE (i.e. just 0-9). + $char = 0; + $char_class = '0-9'; + break; + } + + // Consume as many characters as match the range of characters + // given above. + $this->char++; + $e_name = $this->characters($char_class, $this->char + $char + 1); + $entity = $this->character($start, $this->char); + $cond = strlen($e_name) > 0; + + // The rest of the parsing happens bellow. + break; + + // Anything else + default: + // Consume the maximum number of characters possible, with the + // consumed characters case-sensitively matching one of the + // identifiers in the first column of the entities table. + $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); + $len = strlen($e_name); + + for($c = 1; $c <= $len; $c++) { + $id = substr($e_name, 0, $c); + $this->char++; + + if(in_array($id, $this->entities)) { + if ($e_name[$c-1] !== ';') { + if ($c < $len && $e_name[$c] == ';') { + $this->char++; // consume extra semicolon + } + } + $entity = $id; + break; + } + } + + $cond = isset($entity); + // The rest of the parsing happens bellow. + break; + } + + if(!$cond) { + // If no match can be made, then this is a parse error. No + // characters are consumed, and nothing is returned. + $this->char = $start; + return false; + } + + // Return a character token for the character corresponding to the + // entity name (as given by the second column of the entities table). + return html_entity_decode('&'.$entity.';', ENT_QUOTES, 'UTF-8'); + } + + private function emitToken($token) { + $emit = $this->tree->emitToken($token); + + if(is_int($emit)) { + $this->content_model = $emit; + + } elseif($token['type'] === self::ENDTAG) { + $this->content_model = self::PCDATA; + } + } + + private function EOF() { + $this->state = null; + $this->tree->emitToken(array( + 'type' => self::EOF + )); + } +} + +class HTML5TreeConstructer { + public $stack = array(); + + private $phase; + private $mode; + private $dom; + private $foster_parent = null; + private $a_formatting = array(); + + private $head_pointer = null; + private $form_pointer = null; + + private $scoping = array('button','caption','html','marquee','object','table','td','th'); + private $formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u'); + private $special = array('address','area','base','basefont','bgsound', + 'blockquote','body','br','center','col','colgroup','dd','dir','div','dl', + 'dt','embed','fieldset','form','frame','frameset','h1','h2','h3','h4','h5', + 'h6','head','hr','iframe','image','img','input','isindex','li','link', + 'listing','menu','meta','noembed','noframes','noscript','ol','optgroup', + 'option','p','param','plaintext','pre','script','select','spacer','style', + 'tbody','textarea','tfoot','thead','title','tr','ul','wbr'); + + // The different phases. + const INIT_PHASE = 0; + const ROOT_PHASE = 1; + const MAIN_PHASE = 2; + const END_PHASE = 3; + + // The different insertion modes for the main phase. + const BEFOR_HEAD = 0; + const IN_HEAD = 1; + const AFTER_HEAD = 2; + const IN_BODY = 3; + const IN_TABLE = 4; + const IN_CAPTION = 5; + const IN_CGROUP = 6; + const IN_TBODY = 7; + const IN_ROW = 8; + const IN_CELL = 9; + const IN_SELECT = 10; + const AFTER_BODY = 11; + const IN_FRAME = 12; + const AFTR_FRAME = 13; + + // The different types of elements. + const SPECIAL = 0; + const SCOPING = 1; + const FORMATTING = 2; + const PHRASING = 3; + + const MARKER = 0; + + public function __construct() { + $this->phase = self::INIT_PHASE; + $this->mode = self::BEFOR_HEAD; + $this->dom = new DOMDocument; + + $this->dom->encoding = 'UTF-8'; + $this->dom->preserveWhiteSpace = true; + $this->dom->substituteEntities = true; + $this->dom->strictErrorChecking = false; + } + + // Process tag tokens + public function emitToken($token) { + switch($this->phase) { + case self::INIT_PHASE: return $this->initPhase($token); break; + case self::ROOT_PHASE: return $this->rootElementPhase($token); break; + case self::MAIN_PHASE: return $this->mainPhase($token); break; + case self::END_PHASE : return $this->trailingEndPhase($token); break; + } + } + + private function initPhase($token) { + /* Initially, the tree construction stage must handle each token + emitted from the tokenisation stage as follows: */ + + /* A DOCTYPE token that is marked as being in error + A comment token + A start tag token + An end tag token + A character token that is not one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE + An end-of-file token */ + if((isset($token['error']) && $token['error']) || + $token['type'] === HTML5::COMMENT || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF || + ($token['type'] === HTML5::CHARACTR && isset($token['data']) && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) { + /* This specification does not define how to handle this case. In + particular, user agents may ignore the entirety of this specification + altogether for such documents, and instead invoke special parse modes + with a greater emphasis on backwards compatibility. */ + + $this->phase = self::ROOT_PHASE; + return $this->rootElementPhase($token); + + /* A DOCTYPE token marked as being correct */ + } elseif(isset($token['error']) && !$token['error']) { + /* Append a DocumentType node to the Document node, with the name + attribute set to the name given in the DOCTYPE token (which will be + "HTML"), and the other attributes specific to DocumentType objects + set to null, empty lists, or the empty string as appropriate. */ + $doctype = new DOMDocumentType(null, null, 'HTML'); + + /* Then, switch to the root element phase of the tree construction + stage. */ + $this->phase = self::ROOT_PHASE; + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/', + $token['data'])) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + } + } + + private function rootElementPhase($token) { + /* After the initial phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED + (FF), or U+0020 SPACE + A start tag token + An end tag token + An end-of-file token */ + } elseif(($token['type'] === HTML5::CHARACTR && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF) { + /* Create an HTMLElement node with the tag name html, in the HTML + namespace. Append it to the Document object. Switch to the main + phase and reprocess the current token. */ + $html = $this->dom->createElement('html'); + $this->dom->appendChild($html); + $this->stack[] = $html; + + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + } + } + + private function mainPhase($token) { + /* Tokens in the main phase must be handled as follows: */ + + /* A DOCTYPE token */ + if($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A start tag token with the tag name "html" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { + /* If this start tag token was not the first start tag token, then + it is a parse error. */ + + /* For each attribute on the token, check to see if the attribute + is already present on the top element of the stack of open elements. + If it is not, add the attribute and its corresponding value to that + element. */ + foreach($token['attr'] as $attr) { + if(!$this->stack[0]->hasAttribute($attr['name'])) { + $this->stack[0]->setAttribute($attr['name'], $attr['value']); + } + } + + /* An end-of-file token */ + } elseif($token['type'] === HTML5::EOF) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Anything else. */ + } else { + /* Depends on the insertion mode: */ + switch($this->mode) { + case self::BEFOR_HEAD: return $this->beforeHead($token); break; + case self::IN_HEAD: return $this->inHead($token); break; + case self::AFTER_HEAD: return $this->afterHead($token); break; + case self::IN_BODY: return $this->inBody($token); break; + case self::IN_TABLE: return $this->inTable($token); break; + case self::IN_CAPTION: return $this->inCaption($token); break; + case self::IN_CGROUP: return $this->inColumnGroup($token); break; + case self::IN_TBODY: return $this->inTableBody($token); break; + case self::IN_ROW: return $this->inRow($token); break; + case self::IN_CELL: return $this->inCell($token); break; + case self::IN_SELECT: return $this->inSelect($token); break; + case self::AFTER_BODY: return $this->afterBody($token); break; + case self::IN_FRAME: return $this->inFrameset($token); break; + case self::AFTR_FRAME: return $this->afterFrameset($token); break; + case self::END_PHASE: return $this->trailingEndPhase($token); break; + } + } + } + + private function beforeHead($token) { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "head" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { + /* Create an element for the token, append the new element to the + current node and push it onto the stack of open elements. */ + $element = $this->insertElement($token); + + /* Set the head element pointer to this new element node. */ + $this->head_pointer = $element; + + /* Change the insertion mode to "in head". */ + $this->mode = self::IN_HEAD; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title". Or an end tag with the tag name "html". + Or a character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or any other start tag token */ + } elseif($token['type'] === HTML5::STARTTAG || + ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || + ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/', + $token['data']))) { + /* Act as if a start tag token with the tag name "head" and no + attributes had been seen, then reprocess the current token. */ + $this->beforeHead(array( + 'name' => 'head', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + return $this->inHead($token); + + /* Any other end tag */ + } elseif($token['type'] === HTML5::ENDTAG) { + /* Parse error. Ignore the token. */ + } + } + + private function inHead($token) { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. + + THIS DIFFERS FROM THE SPEC: If the current node is either a title, style + or script element, append the character to the current node regardless + of its content. */ + if(($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( + $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName, + array('title', 'style', 'script')))) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + } elseif($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('title', 'style', 'script'))) { + array_pop($this->stack); + return HTML5::PCDATA; + + /* A start tag with the tag name "title" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $element = $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the RCDATA state. */ + return HTML5::RCDATA; + + /* A start tag with the tag name "style" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "script" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { + /* Create an element for the token. */ + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "base", "link", or "meta" */ + } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('base', 'link', 'meta'))) { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + array_pop($this->stack); + + } else { + $this->insertElement($token); + } + + /* An end tag with the tag name "head" */ + } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { + /* If the current node is a head element, pop the current node off + the stack of open elements. */ + if($this->head_pointer->isSameNode(end($this->stack))) { + array_pop($this->stack); + + /* Otherwise, this is a parse error. */ + } else { + // k + } + + /* Change the insertion mode to "after head". */ + $this->mode = self::AFTER_HEAD; + + /* A start tag with the tag name "head" or an end tag except "html". */ + } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || + ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* If the current node is a head element, act as if an end tag + token with the tag name "head" had been seen. */ + if($this->head_pointer->isSameNode(end($this->stack))) { + $this->inHead(array( + 'name' => 'head', + 'type' => HTML5::ENDTAG + )); + + /* Otherwise, change the insertion mode to "after head". */ + } else { + $this->mode = self::AFTER_HEAD; + } + + /* Then, reprocess the current token. */ + return $this->afterHead($token); + } + } + + private function afterHead($token) { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "body" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { + /* Insert a body element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in body". */ + $this->mode = self::IN_BODY; + + /* A start tag token with the tag name "frameset" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { + /* Insert a frameset element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in frameset". */ + $this->mode = self::IN_FRAME; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title" */ + } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('base', 'link', 'meta', 'script', 'style', 'title'))) { + /* Parse error. Switch the insertion mode back to "in head" and + reprocess the token. */ + $this->mode = self::IN_HEAD; + return $this->inHead($token); + + /* Anything else */ + } else { + /* Act as if a start tag token with the tag name "body" and no + attributes had been seen, and then reprocess the current token. */ + $this->afterHead(array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + return $this->inBody($token); + } + } + + private function inBody($token) { + /* Handle the token as follows: */ + + switch($token['type']) { + /* A character token */ + case HTML5::CHARACTR: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + break; + + /* A comment token */ + case HTML5::COMMENT: + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + break; + + case HTML5::STARTTAG: + switch($token['name']) { + /* A start tag token whose tag name is one of: "script", + "style" */ + case 'script': case 'style': + /* Process the token as if the insertion mode had been "in + head". */ + return $this->inHead($token); + break; + + /* A start tag token whose tag name is one of: "base", "link", + "meta", "title" */ + case 'base': case 'link': case 'meta': case 'title': + /* Parse error. Process the token as if the insertion mode + had been "in head". */ + return $this->inHead($token); + break; + + /* A start tag token with the tag name "body" */ + case 'body': + /* Parse error. If the second element on the stack of open + elements is not a body element, or, if the stack of open + elements has only one node on it, then ignore the token. + (innerHTML case) */ + if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { + // Ignore + + /* Otherwise, for each attribute on the token, check to see + if the attribute is already present on the body element (the + second element) on the stack of open elements. If it is not, + add the attribute and its corresponding value to that + element. */ + } else { + foreach($token['attr'] as $attr) { + if(!$this->stack[1]->hasAttribute($attr['name'])) { + $this->stack[1]->setAttribute($attr['name'], $attr['value']); + } + } + } + break; + + /* A start tag whose tag name is one of: "address", + "blockquote", "center", "dir", "div", "dl", "fieldset", + "listing", "menu", "ol", "p", "ul" */ + case 'address': case 'blockquote': case 'center': case 'dir': + case 'div': case 'dl': case 'fieldset': case 'listing': + case 'menu': case 'ol': case 'p': case 'ul': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if($this->elementInScope('p')) { + $this->emitToken(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "form" */ + case 'form': + /* If the form element pointer is not null, ignore the + token with a parse error. */ + if($this->form_pointer !== null) { + // Ignore. + + /* Otherwise: */ + } else { + /* If the stack of open elements has a p element in + scope, then act as if an end tag with the tag name p + had been seen. */ + if($this->elementInScope('p')) { + $this->emitToken(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + } + + /* Insert an HTML element for the token, and set the + form element pointer to point to the element created. */ + $element = $this->insertElement($token); + $this->form_pointer = $element; + } + break; + + /* A start tag whose tag name is "li", "dd" or "dt" */ + case 'li': case 'dd': case 'dt': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if($this->elementInScope('p')) { + $this->emitToken(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + } + + $stack_length = count($this->stack) - 1; + + for($n = $stack_length; 0 <= $n; $n--) { + /* 1. Initialise node to be the current node (the + bottommost node of the stack). */ + $stop = false; + $node = $this->stack[$n]; + $cat = $this->getElementCategory($node->tagName); + + /* 2. If node is an li, dd or dt element, then pop all + the nodes from the current node up to node, including + node, then stop this algorithm. */ + if($token['name'] === $node->tagName || ($token['name'] !== 'li' + && ($node->tagName === 'dd' || $node->tagName === 'dt'))) { + for($x = $stack_length; $x >= $n ; $x--) { + array_pop($this->stack); + } + + break; + } + + /* 3. If node is not in the formatting category, and is + not in the phrasing category, and is not an address or + div element, then stop this algorithm. */ + if($cat !== self::FORMATTING && $cat !== self::PHRASING && + $node->tagName !== 'address' && $node->tagName !== 'div') { + break; + } + } + + /* Finally, insert an HTML element with the same tag + name as the token's. */ + $this->insertElement($token); + break; + + /* A start tag token whose tag name is "plaintext" */ + case 'plaintext': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if($this->elementInScope('p')) { + $this->emitToken(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + return HTML5::PLAINTEXT; + break; + + /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if($this->elementInScope('p')) { + $this->emitToken(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + } + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + this is a parse error; pop elements from the stack until an + element with one of those tag names has been popped from the + stack. */ + while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { + array_pop($this->stack); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "a" */ + case 'a': + /* If the list of active formatting elements contains + an element whose tag name is "a" between the end of the + list and the last marker on the list (or the start of + the list if there is no marker on the list), then this + is a parse error; act as if an end tag with the tag name + "a" had been seen, then remove that element from the list + of active formatting elements and the stack of open + elements if the end tag didn't already remove it (it + might not have if the element is not in table scope). */ + $leng = count($this->a_formatting); + + for($n = $leng - 1; $n >= 0; $n--) { + if($this->a_formatting[$n] === self::MARKER) { + break; + + } elseif($this->a_formatting[$n]->nodeName === 'a') { + $this->emitToken(array( + 'name' => 'a', + 'type' => HTML5::ENDTAG + )); + break; + } + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag whose tag name is one of: "b", "big", "em", "font", + "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'b': case 'big': case 'em': case 'font': case 'i': + case 'nobr': case 's': case 'small': case 'strike': + case 'strong': case 'tt': case 'u': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag token whose tag name is "button" */ + case 'button': + /* If the stack of open elements has a button element in scope, + then this is a parse error; act as if an end tag with the tag + name "button" had been seen, then reprocess the token. (We don't + do that. Unnecessary.) */ + if($this->elementInScope('button')) { + $this->inBody(array( + 'name' => 'button', + 'type' => HTML5::ENDTAG + )); + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is one of: "marquee", "object" */ + case 'marquee': case 'object': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is "xmp" */ + case 'xmp': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Switch the content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "table" */ + case 'table': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if($this->elementInScope('p')) { + $this->emitToken(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + break; + + /* A start tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ + case 'area': case 'basefont': case 'bgsound': case 'br': + case 'embed': case 'img': case 'param': case 'spacer': + case 'wbr': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "hr" */ + case 'hr': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if($this->elementInScope('p')) { + $this->emitToken(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "image" */ + case 'image': + /* Parse error. Change the token's tag name to "img" and + reprocess it. (Don't ask.) */ + $token['name'] = 'img'; + return $this->inBody($token); + break; + + /* A start tag whose tag name is "input" */ + case 'input': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an input element for the token. */ + $element = $this->insertElement($token, false); + + /* If the form element pointer is not null, then associate the + input element with the form element pointed to by the form + element pointer. */ + $this->form_pointer !== null + ? $this->form_pointer->appendChild($element) + : end($this->stack)->appendChild($element); + + /* Pop that input element off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "isindex" */ + case 'isindex': + /* Parse error. */ + // w/e + + /* If the form element pointer is not null, + then ignore the token. */ + if($this->form_pointer === null) { + /* Act as if a start tag token with the tag name "form" had + been seen. */ + $this->inBody(array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody(array( + 'name' => 'hr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + /* Act as if a start tag token with the tag name "p" had + been seen. */ + $this->inBody(array( + 'name' => 'p', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + /* Act as if a start tag token with the tag name "label" + had been seen. */ + $this->inBody(array( + 'name' => 'label', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + /* Act as if a stream of character tokens had been seen. */ + $this->insertText('This is a searchable index. '. + 'Insert your search keywords here: '); + + /* Act as if a start tag token with the tag name "input" + had been seen, with all the attributes from the "isindex" + token, except with the "name" attribute set to the value + "isindex" (ignoring any explicit "name" attribute). */ + $attr = $token['attr']; + $attr[] = array('name' => 'name', 'value' => 'isindex'); + + $this->inBody(array( + 'name' => 'input', + 'type' => HTML5::STARTTAG, + 'attr' => $attr + )); + + /* Act as if a stream of character tokens had been seen + (see below for what they should say). */ + $this->insertText('This is a searchable index. '. + 'Insert your search keywords here: '); + + /* Act as if an end tag token with the tag name "label" + had been seen. */ + $this->inBody(array( + 'name' => 'label', + 'type' => HTML5::ENDTAG + )); + + /* Act as if an end tag token with the tag name "p" had + been seen. */ + $this->inBody(array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + )); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody(array( + 'name' => 'hr', + 'type' => HTML5::ENDTAG + )); + + /* Act as if an end tag token with the tag name "form" had + been seen. */ + $this->inBody(array( + 'name' => 'form', + 'type' => HTML5::ENDTAG + )); + } + break; + + /* A start tag whose tag name is "textarea" */ + case 'textarea': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the + RCDATA state. */ + return HTML5::RCDATA; + break; + + /* A start tag whose tag name is one of: "iframe", "noembed", + "noframes" */ + case 'iframe': case 'noembed': case 'noframes': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "select" */ + case 'select': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in select". */ + $this->mode = self::IN_SELECT; + break; + + /* A start or end tag whose tag name is one of: "caption", "col", + "colgroup", "frame", "frameset", "head", "option", "optgroup", + "tbody", "td", "tfoot", "th", "thead", "tr". */ + case 'caption': case 'col': case 'colgroup': case 'frame': + case 'frameset': case 'head': case 'option': case 'optgroup': + case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': + case 'tr': + // Parse error. Ignore the token. + break; + + /* A start or end tag whose tag name is one of: "event-source", + "section", "nav", "article", "aside", "header", "footer", + "datagrid", "command" */ + case 'event-source': case 'section': case 'nav': case 'article': + case 'aside': case 'header': case 'footer': case 'datagrid': + case 'command': + // Work in progress! + break; + + /* A start tag token not covered by the previous entries */ + default: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + $this->insertElement($token, true, true); + break; + } + break; + + case HTML5::ENDTAG: + switch($token['name']) { + /* An end tag with the tag name "body" */ + case 'body': + /* If the second element in the stack of open elements is + not a body element, this is a parse error. Ignore the token. + (innerHTML case) */ + if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { + // Ignore. + + /* If the current node is not the body element, then this + is a parse error. */ + } elseif(end($this->stack)->nodeName !== 'body') { + // Parse error. + } + + /* Change the insertion mode to "after body". */ + $this->mode = self::AFTER_BODY; + break; + + /* An end tag with the tag name "html" */ + case 'html': + /* Act as if an end tag with tag name "body" had been seen, + then, if that token wasn't ignored, reprocess the current + token. */ + $this->inBody(array( + 'name' => 'body', + 'type' => HTML5::ENDTAG + )); + + return $this->afterBody($token); + break; + + /* An end tag whose tag name is one of: "address", "blockquote", + "center", "dir", "div", "dl", "fieldset", "listing", "menu", + "ol", "pre", "ul" */ + case 'address': case 'blockquote': case 'center': case 'dir': + case 'div': case 'dl': case 'fieldset': case 'listing': + case 'menu': case 'ol': case 'pre': case 'ul': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with + the same tag name as that of the token, then this + is a parse error. */ + // w/e + + /* If the stack of open elements has an element in + scope with the same tag name as that of the token, + then pop elements from this stack until an element + with that tag name has been popped from the stack. */ + for($n = count($this->stack) - 1; $n >= 0; $n--) { + if($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is "form" */ + case 'form': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + } + + if(end($this->stack)->nodeName !== $token['name']) { + /* Now, if the current node is not an element with the + same tag name as that of the token, then this is a parse + error. */ + // w/e + + } else { + /* Otherwise, if the current node is an element with + the same tag name as that of the token pop that element + from the stack. */ + array_pop($this->stack); + } + + /* In any case, set the form element pointer to null. */ + $this->form_pointer = null; + break; + + /* An end tag whose tag name is "p" */ + case 'p': + /* If the stack of open elements has a p element in scope, + then generate implied end tags, except for p elements. */ + if($this->elementInScope('p')) { + $this->generateImpliedEndTags(array('p')); + + /* If the current node is not a p element, then this is + a parse error. */ + // k + + /* If the stack of open elements has a p element in + scope, then pop elements from this stack until the stack + no longer has a p element in scope. */ + for($n = count($this->stack) - 1; $n >= 0; $n--) { + if($this->elementInScope('p')) { + array_pop($this->stack); + + } else { + break; + } + } + } + break; + + /* An end tag whose tag name is "dd", "dt", or "li" */ + case 'dd': case 'dt': case 'li': + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + generate implied end tags, except for elements with the + same tag name as the token. */ + if($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(array($token['name'])); + + /* If the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + pop elements from this stack until an element with that + tag name has been popped from the stack. */ + for($n = count($this->stack) - 1; $n >= 0; $n--) { + if($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': + $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + generate implied end tags. */ + if($this->elementInScope($elements)) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as that of the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has in scope an element + whose tag name is one of "h1", "h2", "h3", "h4", "h5", or + "h6", then pop elements from the stack until an element + with one of those tag names has been popped from the stack. */ + while($this->elementInScope($elements)) { + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "a", "b", "big", "em", + "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'a': case 'b': case 'big': case 'em': case 'font': + case 'i': case 'nobr': case 's': case 'small': case 'strike': + case 'strong': case 'tt': case 'u': + /* 1. Let the formatting element be the last element in + the list of active formatting elements that: + * is between the end of the list and the last scope + marker in the list, if any, or the start of the list + otherwise, and + * has the same tag name as the token. + */ + while(true) { + for($a = count($this->a_formatting) - 1; $a >= 0; $a--) { + if($this->a_formatting[$a] === self::MARKER) { + break; + + } elseif($this->a_formatting[$a]->tagName === $token['name']) { + $formatting_element = $this->a_formatting[$a]; + $in_stack = in_array($formatting_element, $this->stack, true); + $fe_af_pos = $a; + break; + } + } + + /* If there is no such node, or, if that node is + also in the stack of open elements but the element + is not in scope, then this is a parse error. Abort + these steps. The token is ignored. */ + if(!isset($formatting_element) || ($in_stack && + !$this->elementInScope($token['name']))) { + break; + + /* Otherwise, if there is such a node, but that node + is not in the stack of open elements, then this is a + parse error; remove the element from the list, and + abort these steps. */ + } elseif(isset($formatting_element) && !$in_stack) { + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 2. Let the furthest block be the topmost node in the + stack of open elements that is lower in the stack + than the formatting element, and is not an element in + the phrasing or formatting categories. There might + not be one. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $length = count($this->stack); + + for($s = $fe_s_pos + 1; $s < $length; $s++) { + $category = $this->getElementCategory($this->stack[$s]->nodeName); + + if($category !== self::PHRASING && $category !== self::FORMATTING) { + $furthest_block = $this->stack[$s]; + } + } + + /* 3. If there is no furthest block, then the UA must + skip the subsequent steps and instead just pop all + the nodes from the bottom of the stack of open + elements, from the current node up to the formatting + element, and remove the formatting element from the + list of active formatting elements. */ + if(!isset($furthest_block)) { + for($n = $length - 1; $n >= $fe_s_pos; $n--) { + array_pop($this->stack); + } + + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 4. Let the common ancestor be the element + immediately above the formatting element in the stack + of open elements. */ + $common_ancestor = $this->stack[$fe_s_pos - 1]; + + /* 5. If the furthest block has a parent node, then + remove the furthest block from its parent node. */ + if($furthest_block->parentNode !== null) { + $furthest_block->parentNode->removeChild($furthest_block); + } + + /* 6. Let a bookmark note the position of the + formatting element in the list of active formatting + elements relative to the elements on either side + of it in the list. */ + $bookmark = $fe_af_pos; + + /* 7. Let node and last node be the furthest block. + Follow these steps: */ + $node = $furthest_block; + $last_node = $furthest_block; + + while(true) { + for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { + /* 7.1 Let node be the element immediately + prior to node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 7.2 If node is not in the list of active + formatting elements, then remove node from + the stack of open elements and then go back + to step 1. */ + if(!in_array($node, $this->a_formatting, true)) { + unset($this->stack[$n]); + $this->stack = array_merge($this->stack); + + } else { + break; + } + } + + /* 7.3 Otherwise, if node is the formatting + element, then go to the next step in the overall + algorithm. */ + if($node === $formatting_element) { + break; + + /* 7.4 Otherwise, if last node is the furthest + block, then move the aforementioned bookmark to + be immediately after the node in the list of + active formatting elements. */ + } elseif($last_node === $furthest_block) { + $bookmark = array_search($node, $this->a_formatting, true) + 1; + } + + /* 7.5 If node has any children, perform a + shallow clone of node, replace the entry for + node in the list of active formatting elements + with an entry for the clone, replace the entry + for node in the stack of open elements with an + entry for the clone, and let node be the clone. */ + if($node->hasChildNodes()) { + $clone = $node->cloneNode(); + $s_pos = array_search($node, $this->stack, true); + $a_pos = array_search($node, $this->a_formatting, true); + + $this->stack[$s_pos] = $clone; + $this->a_formatting[$a_pos] = $clone; + $node = $clone; + } + + /* 7.6 Insert last node into node, first removing + it from its previous parent node if any. */ + if($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $node->appendChild($last_node); + + /* 7.7 Let last node be node. */ + $last_node = $node; + } + + /* 8. Insert whatever last node ended up being in + the previous step into the common ancestor node, + first removing it from its previous parent node if + any. */ + if($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $common_ancestor->appendChild($last_node); + + /* 9. Perform a shallow clone of the formatting + element. */ + $clone = $formatting_element->cloneNode(); + + /* 10. Take all of the child nodes of the furthest + block and append them to the clone created in the + last step. */ + while($furthest_block->hasChildNodes()) { + $child = $furthest_block->firstChild; + $furthest_block->removeChild($child); + $clone->appendChild($child); + } + + /* 11. Append that clone to the furthest block. */ + $furthest_block->appendChild($clone); + + /* 12. Remove the formatting element from the list + of active formatting elements, and insert the clone + into the list of active formatting elements at the + position of the aforementioned bookmark. */ + $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + + $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); + $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); + $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); + + /* 13. Remove the formatting element from the stack + of open elements, and insert the clone into the stack + of open elements immediately after (i.e. in a more + deeply nested position than) the position of the + furthest block in that stack. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $fb_s_pos = array_search($furthest_block, $this->stack, true); + unset($this->stack[$fe_s_pos]); + + $s_part1 = array_slice($this->stack, 0, $fb_s_pos); + $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); + $this->stack = array_merge($s_part1, array($clone), $s_part2); + + /* 14. Jump back to step 1 in this series of steps. */ + unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); + } + break; + + /* An end tag token whose tag name is one of: "button", + "marquee", "object" */ + case 'button': case 'marquee': case 'object': + /* If the stack of open elements has an element in scope whose + tag name matches the tag name of the token, then generate implied + tags. */ + if($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // k + + /* Now, if the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then pop + elements from the stack until that element has been popped from + the stack, and clear the list of active formatting elements up + to the last marker. */ + for($n = count($this->stack) - 1; $n >= 0; $n--) { + if($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + + $marker = end(array_keys($this->a_formatting, self::MARKER, true)); + + for($n = count($this->a_formatting) - 1; $n > $marker; $n--) { + array_pop($this->a_formatting); + } + } + break; + + /* Or an end tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "hr", "iframe", "image", "img", + "input", "isindex", "noembed", "noframes", "param", "select", + "spacer", "table", "textarea", "wbr" */ + case 'area': case 'basefont': case 'bgsound': case 'br': + case 'embed': case 'hr': case 'iframe': case 'image': + case 'img': case 'input': case 'isindex': case 'noembed': + case 'noframes': case 'param': case 'select': case 'spacer': + case 'table': case 'textarea': case 'wbr': + // Parse error. Ignore the token. + break; + + /* An end tag token not covered by the previous entries */ + default: + for($n = count($this->stack) - 1; $n >= 0; $n--) { + /* Initialise node to be the current node (the bottommost + node of the stack). */ + $node = end($this->stack); + + /* If node has the same tag name as the end tag token, + then: */ + if($token['name'] === $node->nodeName) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* If the tag name of the end tag token does not + match the tag name of the current node, this is a + parse error. */ + // k + + /* Pop all the nodes from the current node up to + node, including node, then stop this algorithm. */ + for($x = count($this->stack) - $n; $x >= $n; $x--) { + array_pop($this->stack); + } + + } else { + $category = $this->getElementCategory($node); + + if($category !== self::SPECIAL && $category !== self::SCOPING) { + /* Otherwise, if node is in neither the formatting + category nor the phrasing category, then this is a + parse error. Stop this algorithm. The end tag token + is ignored. */ + return false; + } + } + } + break; + } + break; + } + } + + private function inTable($token) { + $clear = array('html', 'table'); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "caption" */ + } elseif($token['type'] === HTML5::STARTTAG && + $token['name'] === 'caption') { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + + /* Insert an HTML element for the token, then switch the + insertion mode to "in caption". */ + $this->insertElement($token); + $this->mode = self::IN_CAPTION; + + /* A start tag whose tag name is "colgroup" */ + } elseif($token['type'] === HTML5::STARTTAG && + $token['name'] === 'colgroup') { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the + insertion mode to "in column group". */ + $this->insertElement($token); + $this->mode = self::IN_CGROUP; + + /* A start tag whose tag name is "col" */ + } elseif($token['type'] === HTML5::STARTTAG && + $token['name'] === 'col') { + $this->inTable(array( + 'name' => 'colgroup', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + $this->inColumnGroup($token); + + /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('tbody', 'tfoot', 'thead'))) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in table body". */ + $this->insertElement($token); + $this->mode = self::IN_TBODY; + + /* A start tag whose tag name is one of: "td", "th", "tr" */ + } elseif($token['type'] === HTML5::STARTTAG && + in_array($token['name'], array('td', 'th', 'tr'))) { + /* Act as if a start tag token with the tag name "tbody" had been + seen, then reprocess the current token. */ + $this->inTable(array( + 'name' => 'tbody', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + return $this->inTableBody($token); + + /* A start tag whose tag name is "table" */ + } elseif($token['type'] === HTML5::STARTTAG && + $token['name'] === 'table') { + /* Parse error. Act as if an end tag token with the tag name "table" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inTable(array( + 'name' => 'table', + 'type' => HTML5::ENDTAG + )); + + return $this->mainPhase($token); + + /* An end tag whose tag name is "table" */ + } elseif($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if(!$this->elementInScope($token['name'], true)) { + return false; + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a table element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a table element has been + popped from the stack. */ + while(true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if($current === 'table') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td', + 'tfoot', 'th', 'thead', 'tr'))) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Parse error. Process the token as if the insertion mode was "in + body", with the following exception: */ + + /* If the current node is a table, tbody, tfoot, thead, or tr + element, then, whenever a node would be inserted into the current + node, it must instead be inserted into the foster parent element. */ + if(in_array(end($this->stack)->nodeName, + array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { + /* The foster parent element is the parent element of the last + table element in the stack of open elements, if there is a + table element and it has such a parent element. If there is no + table element in the stack of open elements (innerHTML case), + then the foster parent element is the first element in the + stack of open elements (the html element). Otherwise, if there + is a table element in the stack of open elements, but the last + table element in the stack of open elements has no parent, or + its parent node is not an element, then the foster parent + element is the element before the last table element in the + stack of open elements. */ + for($n = count($this->stack) - 1; $n >= 0; $n--) { + if($this->stack[$n]->nodeName === 'table') { + $table = $this->stack[$n]; + break; + } + } + + if(isset($table) && $table->parentNode !== null) { + $this->foster_parent = $table->parentNode; + + } elseif(!isset($table)) { + $this->foster_parent = $this->stack[0]; + + } elseif(isset($table) && ($table->parentNode === null || + $table->parentNode->nodeType !== XML_ELEMENT_NODE)) { + $this->foster_parent = $this->stack[$n - 1]; + } + } + + $this->inBody($token); + } + } + + private function inCaption($token) { + /* An end tag whose tag name is "caption" */ + if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if(!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a caption element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a caption element has + been popped from the stack. */ + while(true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if($node === 'caption') { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag + name is "table" */ + } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', + 'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table')) { + /* Parse error. Act as if an end tag with the tag name "caption" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inCaption(array( + 'name' => 'caption', + 'type' => HTML5::ENDTAG + )); + + return $this->inTable($token); + + /* An end tag whose tag name is one of: "body", "col", "colgroup", + "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], + array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th', + 'thead', 'tr'))) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inColumnGroup($token) { + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "col" */ + } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { + /* Insert a col element for the token. Immediately pop the current + node off the stack of open elements. */ + $this->insertElement($token); + array_pop($this->stack); + + /* An end tag whose tag name is "colgroup" */ + } elseif($token['type'] === HTML5::ENDTAG && + $token['name'] === 'colgroup') { + /* If the current node is the root html element, then this is a + parse error, ignore the token. (innerHTML case) */ + if(end($this->stack)->nodeName === 'html') { + // Ignore + + /* Otherwise, pop the current node (which will be a colgroup + element) from the stack of open elements. Switch the insertion + mode to "in table". */ + } else { + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* An end tag whose tag name is "col" */ + } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Act as if an end tag with the tag name "colgroup" had been seen, + and then, if that token wasn't ignored, reprocess the current token. */ + $this->inColumnGroup(array( + 'name' => 'colgroup', + 'type' => HTML5::ENDTAG + )); + + return $this->inTable($token); + } + } + + private function inTableBody($token) { + $clear = array('tbody', 'tfoot', 'thead', 'html'); + + /* A start tag whose tag name is "tr" */ + if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Insert a tr element for the token, then switch the insertion + mode to "in row". */ + $this->insertElement($token); + $this->mode = self::IN_ROW; + + /* A start tag whose tag name is one of: "th", "td" */ + } elseif($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td')) { + /* Parse error. Act as if a start tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inTableBody(array( + 'name' => 'tr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + )); + + return $this->inRow($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if(!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node from the stack of open elements. Switch + the insertion mode to "in table". */ + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ + } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) || + ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) { + /* If the stack of open elements does not have a tbody, thead, or + tfoot element in table scope, this is a parse error. Ignore the + token. (innerHTML case) */ + if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Act as if an end tag with the same tag name as the current + node ("tbody", "tfoot", or "thead") had been seen, then + reprocess the current token. */ + $this->inTableBody(array( + 'name' => end($this->stack)->nodeName, + 'type' => HTML5::ENDTAG + )); + + return $this->mainPhase($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th", "tr" */ + } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inRow($token) { + $clear = array('tr', 'html'); + + /* A start tag whose tag name is one of: "th", "td" */ + if($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td')) { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in cell". */ + $this->insertElement($token); + $this->mode = self::IN_CELL; + + /* Insert a marker at the end of the list of active formatting + elements. */ + $this->a_formatting[] = self::MARKER; + + /* An end tag whose tag name is "tr" */ + } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if(!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node (which will be a tr element) from the + stack of open elements. Switch the insertion mode to "in table + body". */ + array_pop($this->stack); + $this->mode = self::IN_TBODY; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ + } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) { + /* Act as if an end tag with the tag name "tr" had been seen, then, + if that token wasn't ignored, reprocess the current token. */ + $this->inRow(array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + )); + + return $this->inCell($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if(!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Otherwise, act as if an end tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inRow(array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + )); + + return $this->inCell($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th" */ + } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inCell($token) { + /* An end tag whose tag name is one of: "td", "th" */ + if($token['type'] === HTML5::ENDTAG && + ($token['name'] === 'td' || $token['name'] === 'th')) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token, then this is a + parse error and the token must be ignored. */ + if(!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Generate implied end tags, except for elements with the same + tag name as the token. */ + $this->generateImpliedEndTags(array($token['name'])); + + /* Now, if the current node is not an element with the same tag + name as the token, then this is a parse error. */ + // k + + /* Pop elements from this stack until an element with the same + tag name as the token has been popped from the stack. */ + while(true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if($node === $token['name']) { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in row". (The current node + will be a tr element at this point.) */ + $this->mode = self::IN_ROW; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', + 'thead', 'tr'))) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if(!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', + 'thead', 'tr'))) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if(!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html" */ + } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], + array('body', 'caption', 'col', 'colgroup', 'html'))) { + /* Parse error. Ignore the token. */ + + /* An end tag whose tag name is one of: "table", "tbody", "tfoot", + "thead", "tr" */ + } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], + array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token (which can only + happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), + then this is a parse error and the token must be ignored. */ + if(!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inSelect($token) { + /* Handle the token as follows: */ + + /* A character token */ + if($token['type'] === HTML5::CHARACTR) { + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token whose tag name is "option" */ + } elseif($token['type'] === HTML5::STARTTAG && + $token['name'] === 'option') { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if(end($this->stack)->nodeName === 'option') { + $this->inSelect(array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + )); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* A start tag token whose tag name is "optgroup" */ + } elseif($token['type'] === HTML5::STARTTAG && + $token['name'] === 'optgroup') { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if(end($this->stack)->nodeName === 'option') { + $this->inSelect(array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + )); + } + + /* If the current node is an optgroup element, act as if an end tag + with the tag name "optgroup" had been seen. */ + if(end($this->stack)->nodeName === 'optgroup') { + $this->inSelect(array( + 'name' => 'optgroup', + 'type' => HTML5::ENDTAG + )); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* An end tag token whose tag name is "optgroup" */ + } elseif($token['type'] === HTML5::ENDTAG && + $token['name'] === 'optgroup') { + /* First, if the current node is an option element, and the node + immediately before it in the stack of open elements is an optgroup + element, then act as if an end tag with the tag name "option" had + been seen. */ + $elements_in_stack = count($this->stack); + + if($this->stack[$elements_in_stack - 1]->nodeName === 'option' && + $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') { + $this->inSelect(array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + )); + } + + /* If the current node is an optgroup element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if($this->stack[$elements_in_stack - 1] === 'optgroup') { + array_pop($this->stack); + } + + /* An end tag token whose tag name is "option" */ + } elseif($token['type'] === HTML5::ENDTAG && + $token['name'] === 'option') { + /* If the current node is an option element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if(end($this->stack)->nodeName === 'option') { + array_pop($this->stack); + } + + /* An end tag whose tag name is "select" */ + } elseif($token['type'] === HTML5::ENDTAG && + $token['name'] === 'select') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if(!$this->elementInScope($token['name'], true)) { + // w/e + + /* Otherwise: */ + } else { + /* Pop elements from the stack of open elements until a select + element has been popped from the stack. */ + while(true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if($current === 'select') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* A start tag whose tag name is "select" */ + } elseif($token['name'] === 'select' && + $token['type'] === HTML5::STARTTAG) { + /* Parse error. Act as if the token had been an end tag with the + tag name "select" instead. */ + $this->inSelect(array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + )); + + /* An end tag whose tag name is one of: "caption", "table", "tbody", + "tfoot", "thead", "tr", "td", "th" */ + } elseif(in_array($token['name'], array('caption', 'table', 'tbody', + 'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) { + /* Parse error. */ + // w/e + + /* If the stack of open elements has an element in table scope with + the same tag name as that of the token, then act as if an end tag + with the tag name "select" had been seen, and reprocess the token. + Otherwise, ignore the token. */ + if($this->elementInScope($token['name'], true)) { + $this->inSelect(array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + )); + + $this->mainPhase($token); + } + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterBody($token) { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Process the token as it would be processed if the insertion mode + was "in body". */ + $this->inBody($token); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the first element in the stack of open + elements (the html element), with the data attribute set to the + data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->stack[0]->appendChild($comment); + + /* An end tag with the tag name "html" */ + } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { + /* If the parser was originally created in order to handle the + setting of an element's innerHTML attribute, this is a parse error; + ignore the token. (The element will be an html element in this + case.) (innerHTML case) */ + + /* Otherwise, switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* Anything else */ + } else { + /* Parse error. Set the insertion mode to "in body" and reprocess + the token. */ + $this->mode = self::IN_BODY; + return $this->inBody($token); + } + } + + private function inFrameset($token) { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag with the tag name "frameset" */ + } elseif($token['name'] === 'frameset' && + $token['type'] === HTML5::STARTTAG) { + $this->insertElement($token); + + /* An end tag with the tag name "frameset" */ + } elseif($token['name'] === 'frameset' && + $token['type'] === HTML5::ENDTAG) { + /* If the current node is the root html element, then this is a + parse error; ignore the token. (innerHTML case) */ + if(end($this->stack)->nodeName === 'html') { + // Ignore + + } else { + /* Otherwise, pop the current node from the stack of open + elements. */ + array_pop($this->stack); + + /* If the parser was not originally created in order to handle + the setting of an element's innerHTML attribute (innerHTML case), + and the current node is no longer a frameset element, then change + the insertion mode to "after frameset". */ + $this->mode = self::AFTR_FRAME; + } + + /* A start tag with the tag name "frame" */ + } elseif($token['name'] === 'frame' && + $token['type'] === HTML5::STARTTAG) { + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + + /* A start tag with the tag name "noframes" */ + } elseif($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterFrameset($token) { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* An end tag with the tag name "html" */ + } elseif($token['name'] === 'html' && + $token['type'] === HTML5::ENDTAG) { + /* Switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* A start tag with the tag name "noframes" */ + } elseif($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function trailingEndPhase($token) { + /* After the main phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { + /* Process the token as it would be processed in the main phase. */ + $this->mainPhase($token); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or a start tag token. Or an end tag token. */ + } elseif(($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) { + /* Parse error. Switch back to the main phase and reprocess the + token. */ + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + + /* An end-of-file token */ + } elseif($token['type'] === HTML5::EOF) { + /* OMG DONE!! */ + } + } + + private function insertElement($token, $append = true, $check = false) { + // Proprietary workaround for libxml2's limitations with tag names + if ($check) { + // Slightly modified HTML5 tag-name modification, + // removing anything that's not an ASCII letter, digit, or hyphen + $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); + // Remove leading hyphens and numbers + $token['name'] = ltrim($token['name'], '-0..9'); + // In theory, this should ever be needed, but just in case + if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice + } + + $el = $this->dom->createElement($token['name']); + + foreach($token['attr'] as $attr) { + if(!$el->hasAttribute($attr['name'])) { + $el->setAttribute($attr['name'], $attr['value']); + } + } + + $this->appendToRealParent($el); + $this->stack[] = $el; + + return $el; + } + + private function insertText($data) { + $text = $this->dom->createTextNode($data); + $this->appendToRealParent($text); + } + + private function insertComment($data) { + $comment = $this->dom->createComment($data); + $this->appendToRealParent($comment); + } + + private function appendToRealParent($node) { + if($this->foster_parent === null) { + end($this->stack)->appendChild($node); + + } elseif($this->foster_parent !== null) { + /* If the foster parent element is the parent element of the + last table element in the stack of open elements, then the new + node must be inserted immediately before the last table element + in the stack of open elements in the foster parent element; + otherwise, the new node must be appended to the foster parent + element. */ + for($n = count($this->stack) - 1; $n >= 0; $n--) { + if($this->stack[$n]->nodeName === 'table' && + $this->stack[$n]->parentNode !== null) { + $table = $this->stack[$n]; + break; + } + } + + if(isset($table) && $this->foster_parent->isSameNode($table->parentNode)) + $this->foster_parent->insertBefore($node, $table); + else + $this->foster_parent->appendChild($node); + + $this->foster_parent = null; + } + } + + private function elementInScope($el, $table = false) { + if(is_array($el)) { + foreach($el as $element) { + if($this->elementInScope($element, $table)) { + return true; + } + } + + return false; + } + + $leng = count($this->stack); + + for($n = 0; $n < $leng; $n++) { + /* 1. Initialise node to be the current node (the bottommost node of + the stack). */ + $node = $this->stack[$leng - 1 - $n]; + + if($node->tagName === $el) { + /* 2. If node is the target node, terminate in a match state. */ + return true; + + } elseif($node->tagName === 'table') { + /* 3. Otherwise, if node is a table element, terminate in a failure + state. */ + return false; + + } elseif($table === true && in_array($node->tagName, array('caption', 'td', + 'th', 'button', 'marquee', 'object'))) { + /* 4. Otherwise, if the algorithm is the "has an element in scope" + variant (rather than the "has an element in table scope" variant), + and node is one of the following, terminate in a failure state. */ + return false; + + } elseif($node === $node->ownerDocument->documentElement) { + /* 5. Otherwise, if node is an html element (root element), terminate + in a failure state. (This can only happen if the node is the topmost + node of the stack of open elements, and prevents the next step from + being invoked if there are no more elements in the stack.) */ + return false; + } + + /* Otherwise, set node to the previous entry in the stack of open + elements and return to step 2. (This will never fail, since the loop + will always terminate in the previous step if the top of the stack + is reached.) */ + } + } + + private function reconstructActiveFormattingElements() { + /* 1. If there are no entries in the list of active formatting elements, + then there is nothing to reconstruct; stop this algorithm. */ + $formatting_elements = count($this->a_formatting); + + if($formatting_elements === 0) { + return false; + } + + /* 3. Let entry be the last (most recently added) element in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. If the last (most recently added) entry in the list of active + formatting elements is a marker, or if it is an element that is in the + stack of open elements, then there is nothing to reconstruct; stop this + algorithm. */ + if($entry === self::MARKER || in_array($entry, $this->stack, true)) { + return false; + } + + for($a = $formatting_elements - 1; $a >= 0; true) { + /* 4. If there are no entries before entry in the list of active + formatting elements, then jump to step 8. */ + if($a === 0) { + $step_seven = false; + break; + } + + /* 5. Let entry be the entry one earlier than entry in the list of + active formatting elements. */ + $a--; + $entry = $this->a_formatting[$a]; + + /* 6. If entry is neither a marker nor an element that is also in + thetack of open elements, go to step 4. */ + if($entry === self::MARKER || in_array($entry, $this->stack, true)) { + break; + } + } + + while(true) { + /* 7. Let entry be the element one later than entry in the list of + active formatting elements. */ + if(isset($step_seven) && $step_seven === true) { + $a++; + $entry = $this->a_formatting[$a]; + } + + /* 8. Perform a shallow clone of the element entry to obtain clone. */ + $clone = $entry->cloneNode(); + + /* 9. Append clone to the current node and push it onto the stack + of open elements so that it is the new current node. */ + end($this->stack)->appendChild($clone); + $this->stack[] = $clone; + + /* 10. Replace the entry for entry in the list with an entry for + clone. */ + $this->a_formatting[$a] = $clone; + + /* 11. If the entry for clone in the list of active formatting + elements is not the last entry in the list, return to step 7. */ + if(end($this->a_formatting) !== $clone) { + $step_seven = true; + } else { + break; + } + } + } + + private function clearTheActiveFormattingElementsUpToTheLastMarker() { + /* When the steps below require the UA to clear the list of active + formatting elements up to the last marker, the UA must perform the + following steps: */ + + while(true) { + /* 1. Let entry be the last (most recently added) entry in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. Remove entry from the list of active formatting elements. */ + array_pop($this->a_formatting); + + /* 3. If entry was a marker, then stop the algorithm at this point. + The list has been cleared up to the last marker. */ + if($entry === self::MARKER) { + break; + } + } + } + + private function generateImpliedEndTags($exclude = array()) { + /* When the steps below require the UA to generate implied end tags, + then, if the current node is a dd element, a dt element, an li element, + a p element, a td element, a th element, or a tr element, the UA must + act as if an end tag with the respective tag name had been seen and + then generate implied end tags again. */ + $node = end($this->stack); + $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); + + while(in_array(end($this->stack)->nodeName, $elements)) { + array_pop($this->stack); + } + } + + private function getElementCategory($node) { + $name = $node->tagName; + if(in_array($name, $this->special)) + return self::SPECIAL; + + elseif(in_array($name, $this->scoping)) + return self::SCOPING; + + elseif(in_array($name, $this->formatting)) + return self::FORMATTING; + + else + return self::PHRASING; + } + + private function clearStackToTableContext($elements) { + /* When the steps above require the UA to clear the stack back to a + table context, it means that the UA must, while the current node is not + a table element or an html element, pop elements from the stack of open + elements. If this causes any elements to be popped from the stack, then + this is a parse error. */ + while(true) { + $node = end($this->stack)->nodeName; + + if(in_array($node, $elements)) { + break; + } else { + array_pop($this->stack); + } + } + } + + private function resetInsertionMode() { + /* 1. Let last be false. */ + $last = false; + $leng = count($this->stack); + + for($n = $leng - 1; $n >= 0; $n--) { + /* 2. Let node be the last node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 3. If node is the first node in the stack of open elements, then + set last to true. If the element whose innerHTML attribute is being + set is neither a td element nor a th element, then set node to the + element whose innerHTML attribute is being set. (innerHTML case) */ + if($this->stack[0]->isSameNode($node)) { + $last = true; + } + + /* 4. If node is a select element, then switch the insertion mode to + "in select" and abort these steps. (innerHTML case) */ + if($node->nodeName === 'select') { + $this->mode = self::IN_SELECT; + break; + + /* 5. If node is a td or th element, then switch the insertion mode + to "in cell" and abort these steps. */ + } elseif($node->nodeName === 'td' || $node->nodeName === 'th') { + $this->mode = self::IN_CELL; + break; + + /* 6. If node is a tr element, then switch the insertion mode to + "in row" and abort these steps. */ + } elseif($node->nodeName === 'tr') { + $this->mode = self::IN_ROW; + break; + + /* 7. If node is a tbody, thead, or tfoot element, then switch the + insertion mode to "in table body" and abort these steps. */ + } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { + $this->mode = self::IN_TBODY; + break; + + /* 8. If node is a caption element, then switch the insertion mode + to "in caption" and abort these steps. */ + } elseif($node->nodeName === 'caption') { + $this->mode = self::IN_CAPTION; + break; + + /* 9. If node is a colgroup element, then switch the insertion mode + to "in column group" and abort these steps. (innerHTML case) */ + } elseif($node->nodeName === 'colgroup') { + $this->mode = self::IN_CGROUP; + break; + + /* 10. If node is a table element, then switch the insertion mode + to "in table" and abort these steps. */ + } elseif($node->nodeName === 'table') { + $this->mode = self::IN_TABLE; + break; + + /* 11. If node is a head element, then switch the insertion mode + to "in body" ("in body"! not "in head"!) and abort these steps. + (innerHTML case) */ + } elseif($node->nodeName === 'head') { + $this->mode = self::IN_BODY; + break; + + /* 12. If node is a body element, then switch the insertion mode to + "in body" and abort these steps. */ + } elseif($node->nodeName === 'body') { + $this->mode = self::IN_BODY; + break; + + /* 13. If node is a frameset element, then switch the insertion + mode to "in frameset" and abort these steps. (innerHTML case) */ + } elseif($node->nodeName === 'frameset') { + $this->mode = self::IN_FRAME; + break; + + /* 14. If node is an html element, then: if the head element + pointer is null, switch the insertion mode to "before head", + otherwise, switch the insertion mode to "after head". In either + case, abort these steps. (innerHTML case) */ + } elseif($node->nodeName === 'html') { + $this->mode = ($this->head_pointer === null) + ? self::BEFOR_HEAD + : self::AFTER_HEAD; + + break; + + /* 15. If last is true, then set the insertion mode to "in body" + and abort these steps. (innerHTML case) */ + } elseif($last) { + $this->mode = self::IN_BODY; + break; + } + } + } + + private function closeCell() { + /* If the stack of open elements has a td or th element in table scope, + then act as if an end tag token with that tag name had been seen. */ + foreach(array('td', 'th') as $cell) { + if($this->elementInScope($cell, true)) { + $this->inCell(array( + 'name' => $cell, + 'type' => HTML5::ENDTAG + )); + + break; + } + } + } + + public function save() { + return $this->dom; + } +} +?> diff --git a/extlib/HTMLPurifier/HTMLPurifier/PercentEncoder.php b/extlib/HTMLPurifier/HTMLPurifier/PercentEncoder.php new file mode 100644 index 0000000000..a43c44f4c5 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/PercentEncoder.php @@ -0,0 +1,98 @@ +preserve[$i] = true; // digits + for ($i = 65; $i <= 90; $i++) $this->preserve[$i] = true; // upper-case + for ($i = 97; $i <= 122; $i++) $this->preserve[$i] = true; // lower-case + $this->preserve[45] = true; // Dash - + $this->preserve[46] = true; // Period . + $this->preserve[95] = true; // Underscore _ + $this->preserve[126]= true; // Tilde ~ + + // extra letters not to escape + if ($preserve !== false) { + for ($i = 0, $c = strlen($preserve); $i < $c; $i++) { + $this->preserve[ord($preserve[$i])] = true; + } + } + } + + /** + * Our replacement for urlencode, it encodes all non-reserved characters, + * as well as any extra characters that were instructed to be preserved. + * @note + * Assumes that the string has already been normalized, making any + * and all percent escape sequences valid. Percents will not be + * re-escaped, regardless of their status in $preserve + * @param $string String to be encoded + * @return Encoded string. + */ + public function encode($string) { + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])]) ) { + $ret .= '%' . sprintf('%02X', $int); + } else { + $ret .= $string[$i]; + } + } + return $ret; + } + + /** + * Fix up percent-encoding by decoding unreserved characters and normalizing. + * @warning This function is affected by $preserve, even though the + * usual desired behavior is for this not to preserve those + * characters. Be careful when reusing instances of PercentEncoder! + * @param $string String to normalize + */ + public function normalize($string) { + if ($string == '') return ''; + $parts = explode('%', $string); + $ret = array_shift($parts); + foreach ($parts as $part) { + $length = strlen($part); + if ($length < 2) { + $ret .= '%25' . $part; + continue; + } + $encoding = substr($part, 0, 2); + $text = substr($part, 2); + if (!ctype_xdigit($encoding)) { + $ret .= '%25' . $part; + continue; + } + $int = hexdec($encoding); + if (isset($this->preserve[$int])) { + $ret .= chr($int) . $text; + continue; + } + $encoding = strtoupper($encoding); + $ret .= '%' . $encoding . $text; + } + return $ret; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Printer.php b/extlib/HTMLPurifier/HTMLPurifier/Printer.php new file mode 100644 index 0000000000..e7eb82e83e --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Printer.php @@ -0,0 +1,176 @@ +getAll(); + $context = new HTMLPurifier_Context(); + $this->generator = new HTMLPurifier_Generator($config, $context); + } + + /** + * Main function that renders object or aspect of that object + * @note Parameters vary depending on printer + */ + // function render() {} + + /** + * Returns a start tag + * @param $tag Tag name + * @param $attr Attribute array + */ + protected function start($tag, $attr = array()) { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) + ); + } + + /** + * Returns an end teg + * @param $tag Tag name + */ + protected function end($tag) { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_End($tag) + ); + } + + /** + * Prints a complete element with content inside + * @param $tag Tag name + * @param $contents Element contents + * @param $attr Tag attributes + * @param $escape Bool whether or not to escape contents + */ + protected function element($tag, $contents, $attr = array(), $escape = true) { + return $this->start($tag, $attr) . + ($escape ? $this->escape($contents) : $contents) . + $this->end($tag); + } + + protected function elementEmpty($tag, $attr = array()) { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Empty($tag, $attr) + ); + } + + protected function text($text) { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Text($text) + ); + } + + /** + * Prints a simple key/value row in a table. + * @param $name Key + * @param $value Value + */ + protected function row($name, $value) { + if (is_bool($value)) $value = $value ? 'On' : 'Off'; + return + $this->start('tr') . "\n" . + $this->element('th', $name) . "\n" . + $this->element('td', $value) . "\n" . + $this->end('tr') + ; + } + + /** + * Escapes a string for HTML output. + * @param $string String to escape + */ + protected function escape($string) { + $string = HTMLPurifier_Encoder::cleanUTF8($string); + $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); + return $string; + } + + /** + * Takes a list of strings and turns them into a single list + * @param $array List of strings + * @param $polite Bool whether or not to add an end before the last + */ + protected function listify($array, $polite = false) { + if (empty($array)) return 'None'; + $ret = ''; + $i = count($array); + foreach ($array as $value) { + $i--; + $ret .= $value; + if ($i > 0 && !($polite && $i == 1)) $ret .= ', '; + if ($polite && $i == 1) $ret .= 'and '; + } + return $ret; + } + + /** + * Retrieves the class of an object without prefixes, as well as metadata + * @param $obj Object to determine class of + * @param $prefix Further prefix to remove + */ + protected function getClass($obj, $sec_prefix = '') { + static $five = null; + if ($five === null) $five = version_compare(PHP_VERSION, '5', '>='); + $prefix = 'HTMLPurifier_' . $sec_prefix; + if (!$five) $prefix = strtolower($prefix); + $class = str_replace($prefix, '', get_class($obj)); + $lclass = strtolower($class); + $class .= '('; + switch ($lclass) { + case 'enum': + $values = array(); + foreach ($obj->valid_values as $value => $bool) { + $values[] = $value; + } + $class .= implode(', ', $values); + break; + case 'css_composite': + $values = array(); + foreach ($obj->defs as $def) { + $values[] = $this->getClass($def, $sec_prefix); + } + $class .= implode(', ', $values); + break; + case 'css_multiple': + $class .= $this->getClass($obj->single, $sec_prefix) . ', '; + $class .= $obj->max; + break; + case 'css_denyelementdecorator': + $class .= $this->getClass($obj->def, $sec_prefix) . ', '; + $class .= $obj->element; + break; + case 'css_importantdecorator': + $class .= $this->getClass($obj->def, $sec_prefix); + if ($obj->allow) $class .= ', !important'; + break; + } + $class .= ')'; + return $class; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php b/extlib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php new file mode 100644 index 0000000000..81f9865901 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php @@ -0,0 +1,38 @@ +def = $config->getCSSDefinition(); + $ret = ''; + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + $ret .= $this->start('table'); + + $ret .= $this->element('caption', 'Properties ($info)'); + + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Property', array('class' => 'heavy')); + $ret .= $this->element('th', 'Definition', array('class' => 'heavy', 'style' => 'width:auto;')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + + ksort($this->def->info); + foreach ($this->def->info as $property => $obj) { + $name = $this->getClass($obj, 'AttrDef_'); + $ret .= $this->row($property, $name); + } + + $ret .= $this->end('table'); + $ret .= $this->end('div'); + + return $ret; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css b/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css new file mode 100644 index 0000000000..3ff1a88aa4 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css @@ -0,0 +1,10 @@ + +.hp-config {} + +.hp-config tbody th {text-align:right; padding-right:0.5em;} +.hp-config thead, .hp-config .namespace {background:#3C578C; color:#FFF;} +.hp-config .namespace th {text-align:center;} +.hp-config .verbose {display:none;} +.hp-config .controls {text-align:center;} + +/* vim: et sw=4 sts=4 */ diff --git a/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js b/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js new file mode 100644 index 0000000000..cba00c9b80 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js @@ -0,0 +1,5 @@ +function toggleWriteability(id_of_patient, checked) { + document.getElementById(id_of_patient).disabled = checked; +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php b/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php new file mode 100644 index 0000000000..02aa656894 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php @@ -0,0 +1,368 @@ +docURL = $doc_url; + $this->name = $name; + $this->compress = $compress; + // initialize sub-printers + $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); + $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); + } + + /** + * Sets default column and row size for textareas in sub-printers + * @param $cols Integer columns of textarea, null to use default + * @param $rows Integer rows of textarea, null to use default + */ + public function setTextareaDimensions($cols = null, $rows = null) { + if ($cols) $this->fields['default']->cols = $cols; + if ($rows) $this->fields['default']->rows = $rows; + } + + /** + * Retrieves styling, in case it is not accessible by webserver + */ + public static function getCSS() { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); + } + + /** + * Retrieves JavaScript, in case it is not accessible by webserver + */ + public static function getJavaScript() { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); + } + + /** + * Returns HTML output for a configuration form + * @param $config Configuration object of current form state, or an array + * where [0] has an HTML namespace and [1] is being rendered. + * @param $allowed Optional namespace(s) and directives to restrict form to. + */ + public function render($config, $allowed = true, $render_controls = true) { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + + $this->config = $config; + $this->genConfig = $gen_config; + $this->prepareGenerator($gen_config); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); + $all = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $all[$ns][$directive] = $config->get($ns .'.'. $directive); + } + + $ret = ''; + $ret .= $this->start('table', array('class' => 'hp-config')); + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); + $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + foreach ($all as $ns => $directives) { + $ret .= $this->renderNamespace($ns, $directives); + } + if ($render_controls) { + $ret .= $this->start('tbody'); + $ret .= $this->start('tr'); + $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); + $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); + $ret .= '[Reset]'; + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a single namespace + * @param $ns String namespace name + * @param $directive Associative array of directives to values + */ + protected function renderNamespace($ns, $directives) { + $ret = ''; + $ret .= $this->start('tbody', array('class' => 'namespace')); + $ret .= $this->start('tr'); + $ret .= $this->element('th', $ns, array('colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + $ret .= $this->start('tbody'); + foreach ($directives as $directive => $value) { + $ret .= $this->start('tr'); + $ret .= $this->start('th'); + if ($this->docURL) { + $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); + $ret .= $this->start('a', array('href' => $url)); + } + $attr = array('for' => "{$this->name}:$ns.$directive"); + + // crop directive name if it's too long + if (!$this->compress || (strlen($directive) < $this->compress)) { + $directive_disp = $directive; + } else { + $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; + $attr['title'] = $directive; + } + + $ret .= $this->element( + 'label', + $directive_disp, + // component printers must create an element with this id + $attr + ); + if ($this->docURL) $ret .= $this->end('a'); + $ret .= $this->end('th'); + + $ret .= $this->start('td'); + $def = $this->config->def->info["$ns.$directive"]; + if (is_int($def)) { + $allow_null = $def < 0; + $type = abs($def); + } else { + $type = $def->type; + $allow_null = isset($def->allow_null); + } + if (!isset($this->fields[$type])) $type = 0; // default + $type_obj = $this->fields[$type]; + if ($allow_null) { + $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); + } + $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + } + $ret .= $this->end('tbody'); + return $ret; + } + +} + +/** + * Printer decorator for directives that accept null + */ +class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer { + /** + * Printer being decorated + */ + protected $obj; + /** + * @param $obj Printer to decorate + */ + public function __construct($obj) { + parent::__construct(); + $this->obj = $obj; + } + public function render($ns, $directive, $value, $name, $config) { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + + $ret = ''; + $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Null/Disabled'); + $ret .= $this->end('label'); + $attr = array( + 'type' => 'checkbox', + 'value' => '1', + 'class' => 'null-toggle', + 'name' => "$name"."[Null_$ns.$directive]", + 'id' => "$name:Null_$ns.$directive", + 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! + ); + if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { + // modify inline javascript slightly + $attr['onclick'] = "toggleWriteability('$name:Yes_$ns.$directive',checked);toggleWriteability('$name:No_$ns.$directive',checked)"; + } + if ($value === null) $attr['checked'] = 'checked'; + $ret .= $this->elementEmpty('input', $attr); + $ret .= $this->text(' or '); + $ret .= $this->elementEmpty('br'); + $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); + return $ret; + } +} + +/** + * Swiss-army knife configuration form field printer + */ +class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { + public $cols = 18; + public $rows = 5; + public function render($ns, $directive, $value, $name, $config) { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + // this should probably be split up a little + $ret = ''; + $def = $config->def->info["$ns.$directive"]; + if (is_int($def)) { + $type = abs($def); + } else { + $type = $def->type; + } + if (is_array($value)) { + switch ($type) { + case HTMLPurifier_VarParser::LOOKUP: + $array = $value; + $value = array(); + foreach ($array as $val => $b) { + $value[] = $val; + } + case HTMLPurifier_VarParser::ALIST: + $value = implode(PHP_EOL, $value); + break; + case HTMLPurifier_VarParser::HASH: + $nvalue = ''; + foreach ($value as $i => $v) { + $nvalue .= "$i:$v" . PHP_EOL; + } + $value = $nvalue; + break; + default: + $value = ''; + } + } + if ($type === HTMLPurifier_VarParser::MIXED) { + return 'Not supported'; + $value = serialize($value); + } + $attr = array( + 'name' => "$name"."[$ns.$directive]", + 'id' => "$name:$ns.$directive" + ); + if ($value === null) $attr['disabled'] = 'disabled'; + if (isset($def->allowed)) { + $ret .= $this->start('select', $attr); + foreach ($def->allowed as $val => $b) { + $attr = array(); + if ($value == $val) $attr['selected'] = 'selected'; + $ret .= $this->element('option', $val, $attr); + } + $ret .= $this->end('select'); + } elseif ( + $type === HTMLPurifier_VarParser::TEXT || + $type === HTMLPurifier_VarParser::ITEXT || + $type === HTMLPurifier_VarParser::ALIST || + $type === HTMLPurifier_VarParser::HASH || + $type === HTMLPurifier_VarParser::LOOKUP + ) { + $attr['cols'] = $this->cols; + $attr['rows'] = $this->rows; + $ret .= $this->start('textarea', $attr); + $ret .= $this->text($value); + $ret .= $this->end('textarea'); + } else { + $attr['value'] = $value; + $attr['type'] = 'text'; + $ret .= $this->elementEmpty('input', $attr); + } + return $ret; + } +} + +/** + * Bool form field printer + */ +class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { + public function render($ns, $directive, $value, $name, $config) { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + $ret = ''; + $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); + + $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Yes'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name"."[$ns.$directive]", + 'id' => "$name:Yes_$ns.$directive", + 'value' => '1' + ); + if ($value === true) $attr['checked'] = 'checked'; + if ($value === null) $attr['disabled'] = 'disabled'; + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' No'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name"."[$ns.$directive]", + 'id' => "$name:No_$ns.$directive", + 'value' => '0' + ); + if ($value === false) $attr['checked'] = 'checked'; + if ($value === null) $attr['disabled'] = 'disabled'; + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php b/extlib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php new file mode 100644 index 0000000000..8a8f126b81 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php @@ -0,0 +1,272 @@ +config =& $config; + + $this->def = $config->getHTMLDefinition(); + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + + $ret .= $this->renderDoctype(); + $ret .= $this->renderEnvironment(); + $ret .= $this->renderContentSets(); + $ret .= $this->renderInfo(); + + $ret .= $this->end('div'); + + return $ret; + } + + /** + * Renders the Doctype table + */ + protected function renderDoctype() { + $doctype = $this->def->doctype; + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Doctype'); + $ret .= $this->row('Name', $doctype->name); + $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No'); + $ret .= $this->row('Default Modules', implode($doctype->modules, ', ')); + $ret .= $this->row('Default Tidy Modules', implode($doctype->tidyModules, ', ')); + $ret .= $this->end('table'); + return $ret; + } + + + /** + * Renders environment table, which is miscellaneous info + */ + protected function renderEnvironment() { + $def = $this->def; + + $ret = ''; + + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Environment'); + + $ret .= $this->row('Parent of fragment', $def->info_parent); + $ret .= $this->renderChildren($def->info_parent_def->child); + $ret .= $this->row('Block wrap name', $def->info_block_wrapper); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Global attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr),0,0); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Tag transforms'); + $list = array(); + foreach ($def->info_tag_transform as $old => $new) { + $new = $this->getClass($new, 'TagTransform_'); + $list[] = "<$old> with $new"; + } + $ret .= $this->element('td', $this->listify($list)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); + $ret .= $this->end('tr'); + + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Content Sets table + */ + protected function renderContentSets() { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Content Sets'); + foreach ($this->def->info_content_sets as $name => $lookup) { + $ret .= $this->heavyHeader($name); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($lookup)); + $ret .= $this->end('tr'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Elements ($info) table + */ + protected function renderInfo() { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Elements ($info)'); + ksort($this->def->info); + $ret .= $this->heavyHeader('Allowed tags', 2); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2)); + $ret .= $this->end('tr'); + foreach ($this->def->info as $name => $def) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', "<$name>", array('class'=>'heavy', 'colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Inline content'); + $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); + $ret .= $this->end('tr'); + if (!empty($def->excludes)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Excludes'); + $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_pre)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_post)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); + $ret .= $this->end('tr'); + } + if (!empty($def->auto_close)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Auto closed by'); + $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); + $ret .= $this->end('tr'); + } + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Allowed attributes'); + $ret .= $this->element('td',$this->listifyAttr($def->attr), array(), 0); + $ret .= $this->end('tr'); + + if (!empty($def->required_attr)) { + $ret .= $this->row('Required attributes', $this->listify($def->required_attr)); + } + + $ret .= $this->renderChildren($def->child); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a row describing the allowed children of an element + * @param $def HTMLPurifier_ChildDef of pertinent element + */ + protected function renderChildren($def) { + $context = new HTMLPurifier_Context(); + $ret = ''; + $ret .= $this->start('tr'); + $elements = array(); + $attr = array(); + if (isset($def->elements)) { + if ($def->type == 'strictblockquote') { + $def->validateChildren(array(), $this->config, $context); + } + $elements = $def->elements; + } + if ($def->type == 'chameleon') { + $attr['rowspan'] = 2; + } elseif ($def->type == 'empty') { + $elements = array(); + } elseif ($def->type == 'table') { + $elements = array_flip(array('col', 'caption', 'colgroup', 'thead', + 'tfoot', 'tbody', 'tr')); + } + $ret .= $this->element('th', 'Allowed children', $attr); + + if ($def->type == 'chameleon') { + + $ret .= $this->element('td', + 'Block: ' . + $this->escape($this->listifyTagLookup($def->block->elements)),0,0); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element('td', + 'Inline: ' . + $this->escape($this->listifyTagLookup($def->inline->elements)),0,0); + + } elseif ($def->type == 'custom') { + + $ret .= $this->element('td', ''.ucfirst($def->type).': ' . + $def->dtd_regex); + + } else { + $ret .= $this->element('td', + ''.ucfirst($def->type).': ' . + $this->escape($this->listifyTagLookup($elements)),0,0); + } + $ret .= $this->end('tr'); + return $ret; + } + + /** + * Listifies a tag lookup table. + * @param $array Tag lookup array in form of array('tagname' => true) + */ + protected function listifyTagLookup($array) { + ksort($array); + $list = array(); + foreach ($array as $name => $discard) { + if ($name !== '#PCDATA' && !isset($this->def->info[$name])) continue; + $list[] = $name; + } + return $this->listify($list); + } + + /** + * Listifies a list of objects by retrieving class names and internal state + * @param $array List of objects + * @todo Also add information about internal state + */ + protected function listifyObjectList($array) { + ksort($array); + $list = array(); + foreach ($array as $discard => $obj) { + $list[] = $this->getClass($obj, 'AttrTransform_'); + } + return $this->listify($list); + } + + /** + * Listifies a hash of attributes to AttrDef classes + * @param $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) + */ + protected function listifyAttr($array) { + ksort($array); + $list = array(); + foreach ($array as $name => $obj) { + if ($obj === false) continue; + $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; + } + return $this->listify($list); + } + + /** + * Creates a heavy header row + */ + protected function heavyHeader($text, $num = 1) { + $ret = ''; + $ret .= $this->start('tr'); + $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); + $ret .= $this->end('tr'); + return $ret; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/PropertyList.php b/extlib/HTMLPurifier/HTMLPurifier/PropertyList.php new file mode 100644 index 0000000000..2b99fb7bc3 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/PropertyList.php @@ -0,0 +1,86 @@ +parent = $parent; + } + + /** + * Recursively retrieves the value for a key + */ + public function get($name) { + if ($this->has($name)) return $this->data[$name]; + // possible performance bottleneck, convert to iterative if necessary + if ($this->parent) return $this->parent->get($name); + throw new HTMLPurifier_Exception("Key '$name' not found"); + } + + /** + * Sets the value of a key, for this plist + */ + public function set($name, $value) { + $this->data[$name] = $value; + } + + /** + * Returns true if a given key exists + */ + public function has($name) { + return array_key_exists($name, $this->data); + } + + /** + * Resets a value to the value of it's parent, usually the default. If + * no value is specified, the entire plist is reset. + */ + public function reset($name = null) { + if ($name == null) $this->data = array(); + else unset($this->data[$name]); + } + + /** + * Squashes this property list and all of its property lists into a single + * array, and returns the array. This value is cached by default. + * @param $force If true, ignores the cache and regenerates the array. + */ + public function squash($force = false) { + if ($this->cache !== null && !$force) return $this->cache; + if ($this->parent) { + return $this->cache = array_merge($this->parent->squash($force), $this->data); + } else { + return $this->cache = $this->data; + } + } + + /** + * Returns the parent plist. + */ + public function getParent() { + return $this->parent; + } + + /** + * Sets the parent plist. + */ + public function setParent($plist) { + $this->parent = $plist; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php b/extlib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php new file mode 100644 index 0000000000..8f250443e4 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php @@ -0,0 +1,32 @@ +l = strlen($filter); + $this->filter = $filter; + } + + public function accept() { + $key = $this->getInnerIterator()->key(); + if( strncmp($key, $this->filter, $this->l) !== 0 ) { + return false; + } + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Strategy.php b/extlib/HTMLPurifier/HTMLPurifier/Strategy.php new file mode 100644 index 0000000000..2462865210 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Strategy.php @@ -0,0 +1,26 @@ +strategies as $strategy) { + $tokens = $strategy->execute($tokens, $config, $context); + } + return $tokens; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Strategy/Core.php b/extlib/HTMLPurifier/HTMLPurifier/Strategy/Core.php new file mode 100644 index 0000000000..d90e158606 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Strategy/Core.php @@ -0,0 +1,18 @@ +strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); + $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); + $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php b/extlib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php new file mode 100644 index 0000000000..f81802391b --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php @@ -0,0 +1,328 @@ +getHTMLDefinition(); + + // insert implicit "parent" node, will be removed at end. + // DEFINITION CALL + $parent_name = $definition->info_parent; + array_unshift($tokens, new HTMLPurifier_Token_Start($parent_name)); + $tokens[] = new HTMLPurifier_Token_End($parent_name); + + // setup the context variable 'IsInline', for chameleon processing + // is 'false' when we are not inline, 'true' when it must always + // be inline, and an integer when it is inline for a certain + // branch of the document tree + $is_inline = $definition->info_parent_def->descendants_are_inline; + $context->register('IsInline', $is_inline); + + // setup error collector + $e =& $context->get('ErrorCollector', true); + + //####################################################################// + // Loop initialization + + // stack that contains the indexes of all parents, + // $stack[count($stack)-1] being the current parent + $stack = array(); + + // stack that contains all elements that are excluded + // it is organized by parent elements, similar to $stack, + // but it is only populated when an element with exclusions is + // processed, i.e. there won't be empty exclusions. + $exclude_stack = array(); + + // variable that contains the start token while we are processing + // nodes. This enables error reporting to do its job + $start_token = false; + $context->register('CurrentToken', $start_token); + + //####################################################################// + // Loop + + // iterate through all start nodes. Determining the start node + // is complicated so it has been omitted from the loop construct + for ($i = 0, $size = count($tokens) ; $i < $size; ) { + + //################################################################// + // Gather information on children + + // child token accumulator + $child_tokens = array(); + + // scroll to the end of this node, report number, and collect + // all children + for ($j = $i, $depth = 0; ; $j++) { + if ($tokens[$j] instanceof HTMLPurifier_Token_Start) { + $depth++; + // skip token assignment on first iteration, this is the + // token we currently are on + if ($depth == 1) continue; + } elseif ($tokens[$j] instanceof HTMLPurifier_Token_End) { + $depth--; + // skip token assignment on last iteration, this is the + // end token of the token we're currently on + if ($depth == 0) break; + } + $child_tokens[] = $tokens[$j]; + } + + // $i is index of start token + // $j is index of end token + + $start_token = $tokens[$i]; // to make token available via CurrentToken + + //################################################################// + // Gather information on parent + + // calculate parent information + if ($count = count($stack)) { + $parent_index = $stack[$count-1]; + $parent_name = $tokens[$parent_index]->name; + if ($parent_index == 0) { + $parent_def = $definition->info_parent_def; + } else { + $parent_def = $definition->info[$parent_name]; + } + } else { + // processing as if the parent were the "root" node + // unknown info, it won't be used anyway, in the future, + // we may want to enforce one element only (this is + // necessary for HTML Purifier to clean entire documents + $parent_index = $parent_name = $parent_def = null; + } + + // calculate context + if ($is_inline === false) { + // check if conditions make it inline + if (!empty($parent_def) && $parent_def->descendants_are_inline) { + $is_inline = $count - 1; + } + } else { + // check if we're out of inline + if ($count === $is_inline) { + $is_inline = false; + } + } + + //################################################################// + // Determine whether element is explicitly excluded SGML-style + + // determine whether or not element is excluded by checking all + // parent exclusions. The array should not be very large, two + // elements at most. + $excluded = false; + if (!empty($exclude_stack)) { + foreach ($exclude_stack as $lookup) { + if (isset($lookup[$tokens[$i]->name])) { + $excluded = true; + // no need to continue processing + break; + } + } + } + + //################################################################// + // Perform child validation + + if ($excluded) { + // there is an exclusion, remove the entire node + $result = false; + $excludes = array(); // not used, but good to initialize anyway + } else { + // DEFINITION CALL + if ($i === 0) { + // special processing for the first node + $def = $definition->info_parent_def; + } else { + $def = $definition->info[$tokens[$i]->name]; + + } + + if (!empty($def->child)) { + // have DTD child def validate children + $result = $def->child->validateChildren( + $child_tokens, $config, $context); + } else { + // weird, no child definition, get rid of everything + $result = false; + } + + // determine whether or not this element has any exclusions + $excludes = $def->excludes; + } + + // $result is now a bool or array + + //################################################################// + // Process result by interpreting $result + + if ($result === true || $child_tokens === $result) { + // leave the node as is + + // register start token as a parental node start + $stack[] = $i; + + // register exclusions if there are any + if (!empty($excludes)) $exclude_stack[] = $excludes; + + // move cursor to next possible start node + $i++; + + } elseif($result === false) { + // remove entire node + + if ($e) { + if ($excluded) { + $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); + } else { + $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); + } + } + + // calculate length of inner tokens and current tokens + $length = $j - $i + 1; + + // perform removal + array_splice($tokens, $i, $length); + + // update size + $size -= $length; + + // there is no start token to register, + // current node is now the next possible start node + // unless it turns out that we need to do a double-check + + // this is a rought heuristic that covers 100% of HTML's + // cases and 99% of all other cases. A child definition + // that would be tricked by this would be something like: + // ( | a b c) where it's all or nothing. Fortunately, + // our current implementation claims that that case would + // not allow empty, even if it did + if (!$parent_def->child->allow_empty) { + // we need to do a double-check + $i = $parent_index; + array_pop($stack); + } + + // PROJECTED OPTIMIZATION: Process all children elements before + // reprocessing parent node. + + } else { + // replace node with $result + + // calculate length of inner tokens + $length = $j - $i - 1; + + if ($e) { + if (empty($result) && $length) { + $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); + } else { + $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); + } + } + + // perform replacement + array_splice($tokens, $i + 1, $length, $result); + + // update size + $size -= $length; + $size += count($result); + + // register start token as a parental node start + $stack[] = $i; + + // register exclusions if there are any + if (!empty($excludes)) $exclude_stack[] = $excludes; + + // move cursor to next possible start node + $i++; + + } + + //################################################################// + // Scroll to next start node + + // We assume, at this point, that $i is the index of the token + // that is the first possible new start point for a node. + + // Test if the token indeed is a start tag, if not, move forward + // and test again. + $size = count($tokens); + while ($i < $size and !$tokens[$i] instanceof HTMLPurifier_Token_Start) { + if ($tokens[$i] instanceof HTMLPurifier_Token_End) { + // pop a token index off the stack if we ended a node + array_pop($stack); + // pop an exclusion lookup off exclusion stack if + // we ended node and that node had exclusions + if ($i == 0 || $i == $size - 1) { + // use specialized var if it's the super-parent + $s_excludes = $definition->info_parent_def->excludes; + } else { + $s_excludes = $definition->info[$tokens[$i]->name]->excludes; + } + if ($s_excludes) { + array_pop($exclude_stack); + } + } + $i++; + } + + } + + //####################################################################// + // Post-processing + + // remove implicit parent tokens at the beginning and end + array_shift($tokens); + array_pop($tokens); + + // remove context variables + $context->destroy('IsInline'); + $context->destroy('CurrentToken'); + + //####################################################################// + // Return + + return $tokens; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php b/extlib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php new file mode 100644 index 0000000000..feb0c32b45 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php @@ -0,0 +1,457 @@ +getHTMLDefinition(); + + // local variables + $generator = new HTMLPurifier_Generator($config, $context); + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + $e = $context->get('ErrorCollector', true); + $t = false; // token index + $i = false; // injector index + $token = false; // the current token + $reprocess = false; // whether or not to reprocess the same token + $stack = array(); + + // member variables + $this->stack =& $stack; + $this->t =& $t; + $this->tokens =& $tokens; + $this->config = $config; + $this->context = $context; + + // context variables + $context->register('CurrentNesting', $stack); + $context->register('InputIndex', $t); + $context->register('InputTokens', $tokens); + $context->register('CurrentToken', $token); + + // -- begin INJECTOR -- + + $this->injectors = array(); + + $injectors = $config->getBatch('AutoFormat'); + $def_injectors = $definition->info_injector; + $custom_injectors = $injectors['Custom']; + unset($injectors['Custom']); // special case + foreach ($injectors as $injector => $b) { + // XXX: Fix with a legitimate lookup table of enabled filters + if (strpos($injector, '.') !== false) continue; + $injector = "HTMLPurifier_Injector_$injector"; + if (!$b) continue; + $this->injectors[] = new $injector; + } + foreach ($def_injectors as $injector) { + // assumed to be objects + $this->injectors[] = $injector; + } + foreach ($custom_injectors as $injector) { + if (is_string($injector)) { + $injector = "HTMLPurifier_Injector_$injector"; + $injector = new $injector; + } + $this->injectors[] = $injector; + } + + // give the injectors references to the definition and context + // variables for performance reasons + foreach ($this->injectors as $ix => $injector) { + $error = $injector->prepare($config, $context); + if (!$error) continue; + array_splice($this->injectors, $ix, 1); // rm the injector + trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); + } + + // -- end INJECTOR -- + + // a note on punting: + // In order to reduce code duplication, whenever some code needs + // to make HTML changes in order to make things "correct", the + // new HTML gets sent through the purifier, regardless of its + // status. This means that if we add a start token, because it + // was totally necessary, we don't have to update nesting; we just + // punt ($reprocess = true; continue;) and it does that for us. + + // isset is in loop because $tokens size changes during loop exec + for ( + $t = 0; + $t == 0 || isset($tokens[$t - 1]); + // only increment if we don't need to reprocess + $reprocess ? $reprocess = false : $t++ + ) { + + // check for a rewind + if (is_int($i) && $i >= 0) { + // possibility: disable rewinding if the current token has a + // rewind set on it already. This would offer protection from + // infinite loop, but might hinder some advanced rewinding. + $rewind_to = $this->injectors[$i]->getRewind(); + if (is_int($rewind_to) && $rewind_to < $t) { + if ($rewind_to < 0) $rewind_to = 0; + while ($t > $rewind_to) { + $t--; + $prev = $tokens[$t]; + // indicate that other injectors should not process this token, + // but we need to reprocess it + unset($prev->skip[$i]); + $prev->rewind = $i; + if ($prev instanceof HTMLPurifier_Token_Start) array_pop($this->stack); + elseif ($prev instanceof HTMLPurifier_Token_End) $this->stack[] = $prev->start; + } + } + $i = false; + } + + // handle case of document end + if (!isset($tokens[$t])) { + // kill processing if stack is empty + if (empty($this->stack)) break; + + // peek + $top_nesting = array_pop($this->stack); + $this->stack[] = $top_nesting; + + // send error + if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); + } + + // append, don't splice, since this is the end + $tokens[] = new HTMLPurifier_Token_End($top_nesting->name); + + // punt! + $reprocess = true; + continue; + } + + $token = $tokens[$t]; + + //echo '
    '; printTokens($tokens, $t); printTokens($this->stack); + + // quick-check: if it's not a tag, no need to process + if (empty($token->is_tag)) { + if ($token instanceof HTMLPurifier_Token_Text) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) continue; + if ($token->rewind !== null && $token->rewind !== $i) continue; + $injector->handleText($token); + $this->processToken($token, $i); + $reprocess = true; + break; + } + } + // another possibility is a comment + continue; + } + + if (isset($definition->info[$token->name])) { + $type = $definition->info[$token->name]->child->type; + } else { + $type = false; // Type is unknown, treat accordingly + } + + // quick tag checks: anything that's *not* an end tag + $ok = false; + if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { + // claims to be a start tag but is empty + $token = new HTMLPurifier_Token_Empty($token->name, $token->attr); + $ok = true; + } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { + // claims to be empty but really is a start tag + $this->swap(new HTMLPurifier_Token_End($token->name)); + $this->insertBefore(new HTMLPurifier_Token_Start($token->name, $token->attr)); + // punt (since we had to modify the input stream in a non-trivial way) + $reprocess = true; + continue; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // real empty token + $ok = true; + } elseif ($token instanceof HTMLPurifier_Token_Start) { + // start tag + + // ...unless they also have to close their parent + if (!empty($this->stack)) { + + $parent = array_pop($this->stack); + $this->stack[] = $parent; + + if (isset($definition->info[$parent->name])) { + $elements = $definition->info[$parent->name]->child->getAllowedElements($config); + $autoclose = !isset($elements[$token->name]); + } else { + $autoclose = false; + } + + $carryover = false; + if ($autoclose && $definition->info[$parent->name]->formatting) { + $carryover = true; + } + + if ($autoclose) { + // errors need to be updated + $new_token = new HTMLPurifier_Token_End($parent->name); + $new_token->start = $parent; + if ($carryover) { + $element = clone $parent; + $element->armor['MakeWellFormed_TagClosedError'] = true; + $element->carryover = true; + $this->processToken(array($new_token, $token, $element)); + } else { + $this->insertBefore($new_token); + } + if ($e && !isset($parent->armor['MakeWellFormed_TagClosedError'])) { + if (!$carryover) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', $parent); + } else { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $parent); + } + } + $reprocess = true; + continue; + } + + } + $ok = true; + } + + if ($ok) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) continue; + if ($token->rewind !== null && $token->rewind !== $i) continue; + $injector->handleElement($token); + $this->processToken($token, $i); + $reprocess = true; + break; + } + if (!$reprocess) { + // ah, nothing interesting happened; do normal processing + $this->swap($token); + if ($token instanceof HTMLPurifier_Token_Start) { + $this->stack[] = $token; + } elseif ($token instanceof HTMLPurifier_Token_End) { + throw new HTMLPurifier_Exception('Improper handling of end tag in start code; possible error in MakeWellFormed'); + } + } + continue; + } + + // sanity check: we should be dealing with a closing tag + if (!$token instanceof HTMLPurifier_Token_End) { + throw new HTMLPurifier_Exception('Unaccounted for tag token in input stream, bug in HTML Purifier'); + } + + // make sure that we have something open + if (empty($this->stack)) { + if ($escape_invalid_tags) { + if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text'); + $this->swap(new HTMLPurifier_Token_Text( + $generator->generateFromToken($token) + )); + } else { + $this->remove(); + if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed'); + } + $reprocess = true; + continue; + } + + // first, check for the simplest case: everything closes neatly. + // Eventually, everything passes through here; if there are problems + // we modify the input stream accordingly and then punt, so that + // the tokens get processed again. + $current_parent = array_pop($this->stack); + if ($current_parent->name == $token->name) { + $token->start = $current_parent; + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) continue; + if ($token->rewind !== null && $token->rewind !== $i) continue; + $injector->handleEnd($token); + $this->processToken($token, $i); + $this->stack[] = $current_parent; + $reprocess = true; + break; + } + continue; + } + + // okay, so we're trying to close the wrong tag + + // undo the pop previous pop + $this->stack[] = $current_parent; + + // scroll back the entire nest, trying to find our tag. + // (feature could be to specify how far you'd like to go) + $size = count($this->stack); + // -2 because -1 is the last element, but we already checked that + $skipped_tags = false; + for ($j = $size - 2; $j >= 0; $j--) { + if ($this->stack[$j]->name == $token->name) { + $skipped_tags = array_slice($this->stack, $j); + break; + } + } + + // we didn't find the tag, so remove + if ($skipped_tags === false) { + if ($escape_invalid_tags) { + $this->swap(new HTMLPurifier_Token_Text( + $generator->generateFromToken($token) + )); + if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text'); + } else { + $this->remove(); + if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed'); + } + $reprocess = true; + continue; + } + + // do errors, in REVERSE $j order: a,b,c with
    + $c = count($skipped_tags); + if ($e) { + for ($j = $c - 1; $j > 0; $j--) { + // notice we exclude $j == 0, i.e. the current ending tag, from + // the errors... + if (!isset($skipped_tags[$j]->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$j]); + } + } + } + + // insert tags, in FORWARD $j order: c,b,a with
    + $replace = array($token); + for ($j = 1; $j < $c; $j++) { + // ...as well as from the insertions + $new_token = new HTMLPurifier_Token_End($skipped_tags[$j]->name); + $new_token->start = $skipped_tags[$j]; + array_unshift($replace, $new_token); + if (isset($definition->info[$new_token->name]) && $definition->info[$new_token->name]->formatting) { + $element = clone $skipped_tags[$j]; + $element->carryover = true; + $element->armor['MakeWellFormed_TagClosedError'] = true; + $replace[] = $element; + } + } + $this->processToken($replace); + $reprocess = true; + continue; + } + + $context->destroy('CurrentNesting'); + $context->destroy('InputTokens'); + $context->destroy('InputIndex'); + $context->destroy('CurrentToken'); + + unset($this->injectors, $this->stack, $this->tokens, $this->t); + return $tokens; + } + + /** + * Processes arbitrary token values for complicated substitution patterns. + * In general: + * + * If $token is an array, it is a list of tokens to substitute for the + * current token. These tokens then get individually processed. If there + * is a leading integer in the list, that integer determines how many + * tokens from the stream should be removed. + * + * If $token is a regular token, it is swapped with the current token. + * + * If $token is false, the current token is deleted. + * + * If $token is an integer, that number of tokens (with the first token + * being the current one) will be deleted. + * + * @param $token Token substitution value + * @param $injector Injector that performed the substitution; default is if + * this is not an injector related operation. + */ + protected function processToken($token, $injector = -1) { + + // normalize forms of token + if (is_object($token)) $token = array(1, $token); + if (is_int($token)) $token = array($token); + if ($token === false) $token = array(1); + if (!is_array($token)) throw new HTMLPurifier_Exception('Invalid token type from injector'); + if (!is_int($token[0])) array_unshift($token, 1); + if ($token[0] === 0) throw new HTMLPurifier_Exception('Deleting zero tokens is not valid'); + + // $token is now an array with the following form: + // array(number nodes to delete, new node 1, new node 2, ...) + + $delete = array_shift($token); + $old = array_splice($this->tokens, $this->t, $delete, $token); + + if ($injector > -1) { + // determine appropriate skips + $oldskip = isset($old[0]) ? $old[0]->skip : array(); + foreach ($token as $object) { + $object->skip = $oldskip; + $object->skip[$injector] = true; + } + } + + } + + /** + * Inserts a token before the current token. Cursor now points to this token + */ + private function insertBefore($token) { + array_splice($this->tokens, $this->t, 0, array($token)); + } + + /** + * Removes current token. Cursor now points to new token occupying previously + * occupied space. + */ + private function remove() { + array_splice($this->tokens, $this->t, 1); + } + + /** + * Swap current token with new token. Cursor points to new token (no change). + */ + private function swap($token) { + $this->tokens[$this->t] = $token; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php b/extlib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php new file mode 100644 index 0000000000..cf3a33e406 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php @@ -0,0 +1,171 @@ +getHTMLDefinition(); + $generator = new HTMLPurifier_Generator($config, $context); + $result = array(); + + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + $remove_invalid_img = $config->get('Core.RemoveInvalidImg'); + + // currently only used to determine if comments should be kept + $trusted = $config->get('HTML.Trusted'); + + $remove_script_contents = $config->get('Core.RemoveScriptContents'); + $hidden_elements = $config->get('Core.HiddenElements'); + + // remove script contents compatibility + if ($remove_script_contents === true) { + $hidden_elements['script'] = true; + } elseif ($remove_script_contents === false && isset($hidden_elements['script'])) { + unset($hidden_elements['script']); + } + + $attr_validator = new HTMLPurifier_AttrValidator(); + + // removes tokens until it reaches a closing tag with its value + $remove_until = false; + + // converts comments into text tokens when this is equal to a tag name + $textify_comments = false; + + $token = false; + $context->register('CurrentToken', $token); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + foreach($tokens as $token) { + if ($remove_until) { + if (empty($token->is_tag) || $token->name !== $remove_until) { + continue; + } + } + if (!empty( $token->is_tag )) { + // DEFINITION CALL + + // before any processing, try to transform the element + if ( + isset($definition->info_tag_transform[$token->name]) + ) { + $original_name = $token->name; + // there is a transformation for this tag + // DEFINITION CALL + $token = $definition-> + info_tag_transform[$token->name]-> + transform($token, $config, $context); + if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', $original_name); + } + + if (isset($definition->info[$token->name])) { + + // mostly everything's good, but + // we need to make sure required attributes are in order + if ( + ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) && + $definition->info[$token->name]->required_attr && + ($token->name != 'img' || $remove_invalid_img) // ensure config option still works + ) { + $attr_validator->validateToken($token, $config, $context); + $ok = true; + foreach ($definition->info[$token->name]->required_attr as $name) { + if (!isset($token->attr[$name])) { + $ok = false; + break; + } + } + if (!$ok) { + if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Missing required attribute', $name); + continue; + } + $token->armor['ValidateAttributes'] = true; + } + + if (isset($hidden_elements[$token->name]) && $token instanceof HTMLPurifier_Token_Start) { + $textify_comments = $token->name; + } elseif ($token->name === $textify_comments && $token instanceof HTMLPurifier_Token_End) { + $textify_comments = false; + } + + } elseif ($escape_invalid_tags) { + // invalid tag, generate HTML representation and insert in + if ($e) $e->send(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text'); + $token = new HTMLPurifier_Token_Text( + $generator->generateFromToken($token) + ); + } else { + // check if we need to destroy all of the tag's children + // CAN BE GENERICIZED + if (isset($hidden_elements[$token->name])) { + if ($token instanceof HTMLPurifier_Token_Start) { + $remove_until = $token->name; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // do nothing: we're still looking + } else { + $remove_until = false; + } + if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed'); + } else { + if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed'); + } + continue; + } + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + // textify comments in script tags when they are allowed + if ($textify_comments !== false) { + $data = $token->data; + $token = new HTMLPurifier_Token_Text($data); + } elseif ($trusted) { + // keep, but perform comment cleaning + if ($e) { + // perform check whether or not there's a trailing hyphen + if (substr($token->data, -1) == '-') { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed'); + } + } + $token->data = rtrim($token->data, '-'); + $found_double_hyphen = false; + while (strpos($token->data, '--') !== false) { + if ($e && !$found_double_hyphen) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed'); + } + $found_double_hyphen = true; // prevent double-erroring + $token->data = str_replace('--', '-', $token->data); + } + } else { + // strip comments + if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); + continue; + } + } elseif ($token instanceof HTMLPurifier_Token_Text) { + } else { + continue; + } + $result[] = $token; + } + if ($remove_until && $e) { + // we removed tokens until the end, throw error + $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', $remove_until); + } + + $context->destroy('CurrentToken'); + + return $result; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php b/extlib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php new file mode 100644 index 0000000000..c3328a9d44 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php @@ -0,0 +1,39 @@ +register('CurrentToken', $token); + + foreach ($tokens as $key => $token) { + + // only process tokens that have attributes, + // namely start and empty tags + if (!$token instanceof HTMLPurifier_Token_Start && !$token instanceof HTMLPurifier_Token_Empty) continue; + + // skip tokens that are armored + if (!empty($token->armor['ValidateAttributes'])) continue; + + // note that we have no facilities here for removing tokens + $validator->validateToken($token, $config, $context); + + $tokens[$key] = $token; // for PHP 4 + } + $context->destroy('CurrentToken'); + + return $tokens; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/StringHash.php b/extlib/HTMLPurifier/HTMLPurifier/StringHash.php new file mode 100644 index 0000000000..62085c5c2f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/StringHash.php @@ -0,0 +1,39 @@ +accessed[$index] = true; + return parent::offsetGet($index); + } + + /** + * Returns a lookup array of all array indexes that have been accessed. + * @return Array in form array($index => true). + */ + public function getAccessed() { + return $this->accessed; + } + + /** + * Resets the access array. + */ + public function resetAccessed() { + $this->accessed = array(); + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/StringHashParser.php b/extlib/HTMLPurifier/HTMLPurifier/StringHashParser.php new file mode 100644 index 0000000000..f3e70c712f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/StringHashParser.php @@ -0,0 +1,110 @@ + 'DefaultKeyValue', + * 'KEY' => 'Value', + * 'KEY2' => 'Value2', + * 'MULTILINE-KEY' => "Multiline\nvalue.\n", + * ) + * + * We use this as an easy to use file-format for configuration schema + * files, but the class itself is usage agnostic. + * + * You can use ---- to forcibly terminate parsing of a single string-hash; + * this marker is used in multi string-hashes to delimit boundaries. + */ +class HTMLPurifier_StringHashParser +{ + + public $default = 'ID'; + + /** + * Parses a file that contains a single string-hash. + */ + public function parseFile($file) { + if (!file_exists($file)) return false; + $fh = fopen($file, 'r'); + if (!$fh) return false; + $ret = $this->parseHandle($fh); + fclose($fh); + return $ret; + } + + /** + * Parses a file that contains multiple string-hashes delimited by '----' + */ + public function parseMultiFile($file) { + if (!file_exists($file)) return false; + $ret = array(); + $fh = fopen($file, 'r'); + if (!$fh) return false; + while (!feof($fh)) { + $ret[] = $this->parseHandle($fh); + } + fclose($fh); + return $ret; + } + + /** + * Internal parser that acepts a file handle. + * @note While it's possible to simulate in-memory parsing by using + * custom stream wrappers, if such a use-case arises we should + * factor out the file handle into its own class. + * @param $fh File handle with pointer at start of valid string-hash + * block. + */ + protected function parseHandle($fh) { + $state = false; + $single = false; + $ret = array(); + do { + $line = fgets($fh); + if ($line === false) break; + $line = rtrim($line, "\n\r"); + if (!$state && $line === '') continue; + if ($line === '----') break; + if (strncmp('--#', $line, 3) === 0) { + // Comment + continue; + } elseif (strncmp('--', $line, 2) === 0) { + // Multiline declaration + $state = trim($line, '- '); + if (!isset($ret[$state])) $ret[$state] = ''; + continue; + } elseif (!$state) { + $single = true; + if (strpos($line, ':') !== false) { + // Single-line declaration + list($state, $line) = explode(':', $line, 2); + $line = trim($line); + } else { + // Use default declaration + $state = $this->default; + } + } + if ($single) { + $ret[$state] = $line; + $single = false; + $state = false; + } else { + $ret[$state] .= "$line\n"; + } + } while (!feof($fh)); + return $ret; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/TagTransform.php b/extlib/HTMLPurifier/HTMLPurifier/TagTransform.php new file mode 100644 index 0000000000..210a447217 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/TagTransform.php @@ -0,0 +1,36 @@ + 'xx-small', + '1' => 'xx-small', + '2' => 'small', + '3' => 'medium', + '4' => 'large', + '5' => 'x-large', + '6' => 'xx-large', + '7' => '300%', + '-1' => 'smaller', + '-2' => '60%', + '+1' => 'larger', + '+2' => '150%', + '+3' => '200%', + '+4' => '300%' + ); + + public function transform($tag, $config, $context) { + + if ($tag instanceof HTMLPurifier_Token_End) { + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + return $new_tag; + } + + $attr = $tag->attr; + $prepend_style = ''; + + // handle color transform + if (isset($attr['color'])) { + $prepend_style .= 'color:' . $attr['color'] . ';'; + unset($attr['color']); + } + + // handle face transform + if (isset($attr['face'])) { + $prepend_style .= 'font-family:' . $attr['face'] . ';'; + unset($attr['face']); + } + + // handle size transform + if (isset($attr['size'])) { + // normalize large numbers + if ($attr['size']{0} == '+' || $attr['size']{0} == '-') { + $size = (int) $attr['size']; + if ($size < -2) $attr['size'] = '-2'; + if ($size > 4) $attr['size'] = '+4'; + } else { + $size = (int) $attr['size']; + if ($size > 7) $attr['size'] = '7'; + } + if (isset($this->_size_lookup[$attr['size']])) { + $prepend_style .= 'font-size:' . + $this->_size_lookup[$attr['size']] . ';'; + } + unset($attr['size']); + } + + if ($prepend_style) { + $attr['style'] = isset($attr['style']) ? + $prepend_style . $attr['style'] : + $prepend_style; + } + + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + $new_tag->attr = $attr; + + return $new_tag; + + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php b/extlib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php new file mode 100644 index 0000000000..0e36130f25 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php @@ -0,0 +1,35 @@ +transform_to = $transform_to; + $this->style = $style; + } + + public function transform($tag, $config, $context) { + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + if (!is_null($this->style) && + ($new_tag instanceof HTMLPurifier_Token_Start || $new_tag instanceof HTMLPurifier_Token_Empty) + ) { + $this->prependCSS($new_tag->attr, $this->style); + } + return $new_tag; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Token.php b/extlib/HTMLPurifier/HTMLPurifier/Token.php new file mode 100644 index 0000000000..7900e6cb10 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Token.php @@ -0,0 +1,57 @@ +line = $l; + $this->col = $c; + } + + /** + * Convenience function for DirectLex settings line/col position. + */ + public function rawPosition($l, $c) { + if ($c === -1) $l++; + $this->line = $l; + $this->col = $c; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Token/Comment.php b/extlib/HTMLPurifier/HTMLPurifier/Token/Comment.php new file mode 100644 index 0000000000..dc6bdcabb8 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Token/Comment.php @@ -0,0 +1,22 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Token/Empty.php b/extlib/HTMLPurifier/HTMLPurifier/Token/Empty.php new file mode 100644 index 0000000000..2a82b47ad1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Token/Empty.php @@ -0,0 +1,11 @@ +!empty($obj->is_tag) + * without having to use a function call is_a(). + */ + public $is_tag = true; + + /** + * The lower-case name of the tag, like 'a', 'b' or 'blockquote'. + * + * @note Strictly speaking, XML tags are case sensitive, so we shouldn't + * be lower-casing them, but these tokens cater to HTML tags, which are + * insensitive. + */ + public $name; + + /** + * Associative array of the tag's attributes. + */ + public $attr = array(); + + /** + * Non-overloaded constructor, which lower-cases passed tag name. + * + * @param $name String name. + * @param $attr Associative array of attributes. + */ + public function __construct($name, $attr = array(), $line = null, $col = null) { + $this->name = ctype_lower($name) ? $name : strtolower($name); + foreach ($attr as $key => $value) { + // normalization only necessary when key is not lowercase + if (!ctype_lower($key)) { + $new_key = strtolower($key); + if (!isset($attr[$new_key])) { + $attr[$new_key] = $attr[$key]; + } + if ($new_key !== $key) { + unset($attr[$key]); + } + } + } + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/Token/Text.php b/extlib/HTMLPurifier/HTMLPurifier/Token/Text.php new file mode 100644 index 0000000000..82efd823d6 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/Token/Text.php @@ -0,0 +1,33 @@ +data = $data; + $this->is_whitespace = ctype_space($data); + $this->line = $line; + $this->col = $col; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/TokenFactory.php b/extlib/HTMLPurifier/HTMLPurifier/TokenFactory.php new file mode 100644 index 0000000000..7cf48fb41c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/TokenFactory.php @@ -0,0 +1,94 @@ +p_start = new HTMLPurifier_Token_Start('', array()); + $this->p_end = new HTMLPurifier_Token_End(''); + $this->p_empty = new HTMLPurifier_Token_Empty('', array()); + $this->p_text = new HTMLPurifier_Token_Text(''); + $this->p_comment= new HTMLPurifier_Token_Comment(''); + } + + /** + * Creates a HTMLPurifier_Token_Start. + * @param $name Tag name + * @param $attr Associative array of attributes + * @return Generated HTMLPurifier_Token_Start + */ + public function createStart($name, $attr = array()) { + $p = clone $this->p_start; + $p->__construct($name, $attr); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_End. + * @param $name Tag name + * @return Generated HTMLPurifier_Token_End + */ + public function createEnd($name) { + $p = clone $this->p_end; + $p->__construct($name); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Empty. + * @param $name Tag name + * @param $attr Associative array of attributes + * @return Generated HTMLPurifier_Token_Empty + */ + public function createEmpty($name, $attr = array()) { + $p = clone $this->p_empty; + $p->__construct($name, $attr); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Text. + * @param $data Data of text token + * @return Generated HTMLPurifier_Token_Text + */ + public function createText($data) { + $p = clone $this->p_text; + $p->__construct($data); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Comment. + * @param $data Data of comment token + * @return Generated HTMLPurifier_Token_Comment + */ + public function createComment($data) { + $p = clone $this->p_comment; + $p->__construct($data); + return $p; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URI.php b/extlib/HTMLPurifier/HTMLPurifier/URI.php new file mode 100644 index 0000000000..8b50d0d18d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URI.php @@ -0,0 +1,173 @@ +scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme); + $this->userinfo = $userinfo; + $this->host = $host; + $this->port = is_null($port) ? $port : (int) $port; + $this->path = $path; + $this->query = $query; + $this->fragment = $fragment; + } + + /** + * Retrieves a scheme object corresponding to the URI's scheme/default + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + * @return Scheme object appropriate for validating this URI + */ + public function getSchemeObj($config, $context) { + $registry = HTMLPurifier_URISchemeRegistry::instance(); + if ($this->scheme !== null) { + $scheme_obj = $registry->getScheme($this->scheme, $config, $context); + if (!$scheme_obj) return false; // invalid scheme, clean it out + } else { + // no scheme: retrieve the default one + $def = $config->getDefinition('URI'); + $scheme_obj = $registry->getScheme($def->defaultScheme, $config, $context); + if (!$scheme_obj) { + // something funky happened to the default scheme object + trigger_error( + 'Default scheme object "' . $def->defaultScheme . '" was not readable', + E_USER_WARNING + ); + return false; + } + } + return $scheme_obj; + } + + /** + * Generic validation method applicable for all schemes. May modify + * this URI in order to get it into a compliant form. + * @param $config Instance of HTMLPurifier_Config + * @param $context Instance of HTMLPurifier_Context + * @return True if validation/filtering succeeds, false if failure + */ + public function validate($config, $context) { + + // ABNF definitions from RFC 3986 + $chars_sub_delims = '!$&\'()*+,;='; + $chars_gen_delims = ':/?#[]@'; + $chars_pchar = $chars_sub_delims . ':@'; + + // validate scheme (MUST BE FIRST!) + if (!is_null($this->scheme) && is_null($this->host)) { + $def = $config->getDefinition('URI'); + if ($def->defaultScheme === $this->scheme) { + $this->scheme = null; + } + } + + // validate host + if (!is_null($this->host)) { + $host_def = new HTMLPurifier_AttrDef_URI_Host(); + $this->host = $host_def->validate($this->host, $config, $context); + if ($this->host === false) $this->host = null; + } + + // validate username + if (!is_null($this->userinfo)) { + $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':'); + $this->userinfo = $encoder->encode($this->userinfo); + } + + // validate port + if (!is_null($this->port)) { + if ($this->port < 1 || $this->port > 65535) $this->port = null; + } + + // validate path + $path_parts = array(); + $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/'); + if (!is_null($this->host)) { + // path-abempty (hier and relative) + $this->path = $segments_encoder->encode($this->path); + } elseif ($this->path !== '' && $this->path[0] === '/') { + // path-absolute (hier and relative) + if (strlen($this->path) >= 2 && $this->path[1] === '/') { + // This shouldn't ever happen! + $this->path = ''; + } else { + $this->path = $segments_encoder->encode($this->path); + } + } elseif (!is_null($this->scheme) && $this->path !== '') { + // path-rootless (hier) + // Short circuit evaluation means we don't need to check nz + $this->path = $segments_encoder->encode($this->path); + } elseif (is_null($this->scheme) && $this->path !== '') { + // path-noscheme (relative) + // (once again, not checking nz) + $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@'); + $c = strpos($this->path, '/'); + if ($c !== false) { + $this->path = + $segment_nc_encoder->encode(substr($this->path, 0, $c)) . + $segments_encoder->encode(substr($this->path, $c)); + } else { + $this->path = $segment_nc_encoder->encode($this->path); + } + } else { + // path-empty (hier and relative) + $this->path = ''; // just to be safe + } + + // qf = query and fragment + $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?'); + + if (!is_null($this->query)) { + $this->query = $qf_encoder->encode($this->query); + } + + if (!is_null($this->fragment)) { + $this->fragment = $qf_encoder->encode($this->fragment); + } + + return true; + + } + + /** + * Convert URI back to string + * @return String URI appropriate for output + */ + public function toString() { + // reconstruct authority + $authority = null; + if (!is_null($this->host)) { + $authority = ''; + if(!is_null($this->userinfo)) $authority .= $this->userinfo . '@'; + $authority .= $this->host; + if(!is_null($this->port)) $authority .= ':' . $this->port; + } + + // reconstruct the result + $result = ''; + if (!is_null($this->scheme)) $result .= $this->scheme . ':'; + if (!is_null($authority)) $result .= '//' . $authority; + $result .= $this->path; + if (!is_null($this->query)) $result .= '?' . $this->query; + if (!is_null($this->fragment)) $result .= '#' . $this->fragment; + + return $result; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIDefinition.php b/extlib/HTMLPurifier/HTMLPurifier/URIDefinition.php new file mode 100644 index 0000000000..ea2b8fe245 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIDefinition.php @@ -0,0 +1,93 @@ +registerFilter(new HTMLPurifier_URIFilter_DisableExternal()); + $this->registerFilter(new HTMLPurifier_URIFilter_DisableExternalResources()); + $this->registerFilter(new HTMLPurifier_URIFilter_HostBlacklist()); + $this->registerFilter(new HTMLPurifier_URIFilter_MakeAbsolute()); + $this->registerFilter(new HTMLPurifier_URIFilter_Munge()); + } + + public function registerFilter($filter) { + $this->registeredFilters[$filter->name] = $filter; + } + + public function addFilter($filter, $config) { + $r = $filter->prepare($config); + if ($r === false) return; // null is ok, for backwards compat + if ($filter->post) { + $this->postFilters[$filter->name] = $filter; + } else { + $this->filters[$filter->name] = $filter; + } + } + + protected function doSetup($config) { + $this->setupMemberVariables($config); + $this->setupFilters($config); + } + + protected function setupFilters($config) { + foreach ($this->registeredFilters as $name => $filter) { + $conf = $config->get('URI.' . $name); + if ($conf !== false && $conf !== null) { + $this->addFilter($filter, $config); + } + } + unset($this->registeredFilters); + } + + protected function setupMemberVariables($config) { + $this->host = $config->get('URI.Host'); + $base_uri = $config->get('URI.Base'); + if (!is_null($base_uri)) { + $parser = new HTMLPurifier_URIParser(); + $this->base = $parser->parse($base_uri); + $this->defaultScheme = $this->base->scheme; + if (is_null($this->host)) $this->host = $this->base->host; + } + if (is_null($this->defaultScheme)) $this->defaultScheme = $config->get('URI.DefaultScheme'); + } + + public function filter(&$uri, $config, $context) { + foreach ($this->filters as $name => $f) { + $result = $f->filter($uri, $config, $context); + if (!$result) return false; + } + return true; + } + + public function postFilter(&$uri, $config, $context) { + foreach ($this->postFilters as $name => $f) { + $result = $f->filter($uri, $config, $context); + if (!$result) return false; + } + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIFilter.php b/extlib/HTMLPurifier/HTMLPurifier/URIFilter.php new file mode 100644 index 0000000000..c116f93dff --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIFilter.php @@ -0,0 +1,45 @@ +getDefinition('URI')->host; + if ($our_host !== null) $this->ourHostParts = array_reverse(explode('.', $our_host)); + } + public function filter(&$uri, $config, $context) { + if (is_null($uri->host)) return true; + if ($this->ourHostParts === false) return false; + $host_parts = array_reverse(explode('.', $uri->host)); + foreach ($this->ourHostParts as $i => $x) { + if (!isset($host_parts[$i])) return false; + if ($host_parts[$i] != $this->ourHostParts[$i]) return false; + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php new file mode 100644 index 0000000000..881abc43cf --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php @@ -0,0 +1,12 @@ +get('EmbeddedURI', true)) return true; + return parent::filter($uri, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php new file mode 100644 index 0000000000..045aa0992c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php @@ -0,0 +1,21 @@ +blacklist = $config->get('URI.HostBlacklist'); + return true; + } + public function filter(&$uri, $config, $context) { + foreach($this->blacklist as $blacklisted_host_fragment) { + if (strpos($uri->host, $blacklisted_host_fragment) !== false) { + return false; + } + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php new file mode 100644 index 0000000000..f46ab2630d --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php @@ -0,0 +1,114 @@ +getDefinition('URI'); + $this->base = $def->base; + if (is_null($this->base)) { + trigger_error('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration', E_USER_WARNING); + return false; + } + $this->base->fragment = null; // fragment is invalid for base URI + $stack = explode('/', $this->base->path); + array_pop($stack); // discard last segment + $stack = $this->_collapseStack($stack); // do pre-parsing + $this->basePathStack = $stack; + return true; + } + public function filter(&$uri, $config, $context) { + if (is_null($this->base)) return true; // abort early + if ( + $uri->path === '' && is_null($uri->scheme) && + is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment) + ) { + // reference to current document + $uri = clone $this->base; + return true; + } + if (!is_null($uri->scheme)) { + // absolute URI already: don't change + if (!is_null($uri->host)) return true; + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + // scheme not recognized + return false; + } + if (!$scheme_obj->hierarchical) { + // non-hierarchal URI with explicit scheme, don't change + return true; + } + // special case: had a scheme but always is hierarchical and had no authority + } + if (!is_null($uri->host)) { + // network path, don't bother + return true; + } + if ($uri->path === '') { + $uri->path = $this->base->path; + } elseif ($uri->path[0] !== '/') { + // relative path, needs more complicated processing + $stack = explode('/', $uri->path); + $new_stack = array_merge($this->basePathStack, $stack); + if ($new_stack[0] !== '' && !is_null($this->base->host)) { + array_unshift($new_stack, ''); + } + $new_stack = $this->_collapseStack($new_stack); + $uri->path = implode('/', $new_stack); + } else { + // absolute path, but still we should collapse + $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path))); + } + // re-combine + $uri->scheme = $this->base->scheme; + if (is_null($uri->userinfo)) $uri->userinfo = $this->base->userinfo; + if (is_null($uri->host)) $uri->host = $this->base->host; + if (is_null($uri->port)) $uri->port = $this->base->port; + return true; + } + + /** + * Resolve dots and double-dots in a path stack + */ + private function _collapseStack($stack) { + $result = array(); + $is_folder = false; + for ($i = 0; isset($stack[$i]); $i++) { + $is_folder = false; + // absorb an internally duplicated slash + if ($stack[$i] == '' && $i && isset($stack[$i+1])) continue; + if ($stack[$i] == '..') { + if (!empty($result)) { + $segment = array_pop($result); + if ($segment === '' && empty($result)) { + // error case: attempted to back out too far: + // restore the leading slash + $result[] = ''; + } elseif ($segment === '..') { + $result[] = '..'; // cannot remove .. with .. + } + } else { + // relative path, preserve the double-dots + $result[] = '..'; + } + $is_folder = true; + continue; + } + if ($stack[$i] == '.') { + // silently absorb + $is_folder = true; + continue; + } + $result[] = $stack[$i]; + } + if ($is_folder) $result[] = ''; + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php new file mode 100644 index 0000000000..efa10a6458 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php @@ -0,0 +1,58 @@ +target = $config->get('URI.' . $this->name); + $this->parser = new HTMLPurifier_URIParser(); + $this->doEmbed = $config->get('URI.MungeResources'); + $this->secretKey = $config->get('URI.MungeSecretKey'); + return true; + } + public function filter(&$uri, $config, $context) { + if ($context->get('EmbeddedURI', true) && !$this->doEmbed) return true; + + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) return true; // ignore unknown schemes, maybe another postfilter did it + if (is_null($uri->host) || empty($scheme_obj->browsable)) { + return true; + } + // don't redirect if target host is our host + if ($uri->host === $config->getDefinition('URI')->host) { + return true; + } + + $this->makeReplace($uri, $config, $context); + $this->replace = array_map('rawurlencode', $this->replace); + + $new_uri = strtr($this->target, $this->replace); + $new_uri = $this->parser->parse($new_uri); + // don't redirect if the target host is the same as the + // starting host + if ($uri->host === $new_uri->host) return true; + $uri = $new_uri; // overwrite + return true; + } + + protected function makeReplace($uri, $config, $context) { + $string = $uri->toString(); + // always available + $this->replace['%s'] = $string; + $this->replace['%r'] = $context->get('EmbeddedURI', true); + $token = $context->get('CurrentToken', true); + $this->replace['%n'] = $token ? $token->name : null; + $this->replace['%m'] = $context->get('CurrentAttr', true); + $this->replace['%p'] = $context->get('CurrentCSSProperty', true); + // not always available + if ($this->secretKey) $this->replace['%t'] = sha1($this->secretKey . ':' . $string); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIParser.php b/extlib/HTMLPurifier/HTMLPurifier/URIParser.php new file mode 100644 index 0000000000..7179e4ab89 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIParser.php @@ -0,0 +1,70 @@ +percentEncoder = new HTMLPurifier_PercentEncoder(); + } + + /** + * Parses a URI. + * @param $uri string URI to parse + * @return HTMLPurifier_URI representation of URI. This representation has + * not been validated yet and may not conform to RFC. + */ + public function parse($uri) { + + $uri = $this->percentEncoder->normalize($uri); + + // Regexp is as per Appendix B. + // Note that ["<>] are an addition to the RFC's recommended + // characters, because they represent external delimeters. + $r_URI = '!'. + '(([^:/?#"<>]+):)?'. // 2. Scheme + '(//([^/?#"<>]*))?'. // 4. Authority + '([^?#"<>]*)'. // 5. Path + '(\?([^#"<>]*))?'. // 7. Query + '(#([^"<>]*))?'. // 8. Fragment + '!'; + + $matches = array(); + $result = preg_match($r_URI, $uri, $matches); + + if (!$result) return false; // *really* invalid URI + + // seperate out parts + $scheme = !empty($matches[1]) ? $matches[2] : null; + $authority = !empty($matches[3]) ? $matches[4] : null; + $path = $matches[5]; // always present, can be empty + $query = !empty($matches[6]) ? $matches[7] : null; + $fragment = !empty($matches[8]) ? $matches[9] : null; + + // further parse authority + if ($authority !== null) { + $r_authority = "/^((.+?)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/"; + $matches = array(); + preg_match($r_authority, $authority, $matches); + $userinfo = !empty($matches[1]) ? $matches[2] : null; + $host = !empty($matches[3]) ? $matches[3] : ''; + $port = !empty($matches[4]) ? (int) $matches[5] : null; + } else { + $port = $host = $userinfo = null; + } + + return new HTMLPurifier_URI( + $scheme, $userinfo, $host, $port, $path, $query, $fragment); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIScheme.php b/extlib/HTMLPurifier/HTMLPurifier/URIScheme.php new file mode 100644 index 0000000000..039710fd15 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIScheme.php @@ -0,0 +1,42 @@ +, resolves edge cases + * with making relative URIs absolute + */ + public $hierarchical = false; + + /** + * Validates the components of a URI + * @note This implementation should be called by children if they define + * a default port, as it does port processing. + * @param $uri Instance of HTMLPurifier_URI + * @param $config HTMLPurifier_Config object + * @param $context HTMLPurifier_Context object + * @return Bool success or failure + */ + public function validate(&$uri, $config, $context) { + if ($this->default_port == $uri->port) $uri->port = null; + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php new file mode 100644 index 0000000000..5849bf7ff0 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php @@ -0,0 +1,43 @@ +query = null; + + // typecode check + $semicolon_pos = strrpos($uri->path, ';'); // reverse + if ($semicolon_pos !== false) { + $type = substr($uri->path, $semicolon_pos + 1); // no semicolon + $uri->path = substr($uri->path, 0, $semicolon_pos); + $type_ret = ''; + if (strpos($type, '=') !== false) { + // figure out whether or not the declaration is correct + list($key, $typecode) = explode('=', $type, 2); + if ($key !== 'type') { + // invalid key, tack it back on encoded + $uri->path .= '%3B' . $type; + } elseif ($typecode === 'a' || $typecode === 'i' || $typecode === 'd') { + $type_ret = ";type=$typecode"; + } + } else { + $uri->path .= '%3B' . $type; + } + $uri->path = str_replace(';', '%3B', $uri->path); + $uri->path .= $type_ret; + } + + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIScheme/http.php b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/http.php new file mode 100644 index 0000000000..b097a31d6a --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/http.php @@ -0,0 +1,20 @@ +userinfo = null; + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIScheme/https.php b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/https.php new file mode 100644 index 0000000000..29e380919f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/https.php @@ -0,0 +1,12 @@ +userinfo = null; + $uri->host = null; + $uri->port = null; + // we need to validate path against RFC 2368's addr-spec + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIScheme/news.php b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/news.php new file mode 100644 index 0000000000..f5f54f4f56 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/news.php @@ -0,0 +1,22 @@ +userinfo = null; + $uri->host = null; + $uri->port = null; + $uri->query = null; + // typecode check needed on path + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php new file mode 100644 index 0000000000..5bf93ea784 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php @@ -0,0 +1,20 @@ +userinfo = null; + $uri->query = null; + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php b/extlib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php new file mode 100644 index 0000000000..576bf7b6d1 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php @@ -0,0 +1,68 @@ +get('URI.AllowedSchemes'); + if (!$config->get('URI.OverrideAllowedSchemes') && + !isset($allowed_schemes[$scheme]) + ) { + return; + } + + if (isset($this->schemes[$scheme])) return $this->schemes[$scheme]; + if (!isset($allowed_schemes[$scheme])) return; + + $class = 'HTMLPurifier_URIScheme_' . $scheme; + if (!class_exists($class)) return; + $this->schemes[$scheme] = new $class(); + return $this->schemes[$scheme]; + } + + /** + * Registers a custom scheme to the cache, bypassing reflection. + * @param $scheme Scheme name + * @param $scheme_obj HTMLPurifier_URIScheme object + */ + public function register($scheme, $scheme_obj) { + $this->schemes[$scheme] = $scheme_obj; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/UnitConverter.php b/extlib/HTMLPurifier/HTMLPurifier/UnitConverter.php new file mode 100644 index 0000000000..545d426220 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/UnitConverter.php @@ -0,0 +1,254 @@ + array( + 'px' => 3, // This is as per CSS 2.1 and Firefox. Your mileage may vary + 'pt' => 4, + 'pc' => 48, + 'in' => 288, + self::METRIC => array('pt', '0.352777778', 'mm'), + ), + self::METRIC => array( + 'mm' => 1, + 'cm' => 10, + self::ENGLISH => array('mm', '2.83464567', 'pt'), + ), + ); + + /** + * Minimum bcmath precision for output. + */ + protected $outputPrecision; + + /** + * Bcmath precision for internal calculations. + */ + protected $internalPrecision; + + /** + * Whether or not BCMath is available + */ + private $bcmath; + + public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false) { + $this->outputPrecision = $output_precision; + $this->internalPrecision = $internal_precision; + $this->bcmath = !$force_no_bcmath && function_exists('bcmul'); + } + + /** + * Converts a length object of one unit into another unit. + * @param HTMLPurifier_Length $length + * Instance of HTMLPurifier_Length to convert. You must validate() + * it before passing it here! + * @param string $to_unit + * Unit to convert to. + * @note + * About precision: This conversion function pays very special + * attention to the incoming precision of values and attempts + * to maintain a number of significant figure. Results are + * fairly accurate up to nine digits. Some caveats: + * - If a number is zero-padded as a result of this significant + * figure tracking, the zeroes will be eliminated. + * - If a number contains less than four sigfigs ($outputPrecision) + * and this causes some decimals to be excluded, those + * decimals will be added on. + */ + public function convert($length, $to_unit) { + + if (!$length->isValid()) return false; + + $n = $length->getN(); + $unit = $length->getUnit(); + + if ($n === '0' || $unit === false) { + return new HTMLPurifier_Length('0', false); + } + + $state = $dest_state = false; + foreach (self::$units as $k => $x) { + if (isset($x[$unit])) $state = $k; + if (isset($x[$to_unit])) $dest_state = $k; + } + if (!$state || !$dest_state) return false; + + // Some calculations about the initial precision of the number; + // this will be useful when we need to do final rounding. + $sigfigs = $this->getSigFigs($n); + if ($sigfigs < $this->outputPrecision) $sigfigs = $this->outputPrecision; + + // BCMath's internal precision deals only with decimals. Use + // our default if the initial number has no decimals, or increase + // it by how ever many decimals, thus, the number of guard digits + // will always be greater than or equal to internalPrecision. + $log = (int) floor(log(abs($n), 10)); + $cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision + + for ($i = 0; $i < 2; $i++) { + + // Determine what unit IN THIS SYSTEM we need to convert to + if ($dest_state === $state) { + // Simple conversion + $dest_unit = $to_unit; + } else { + // Convert to the smallest unit, pending a system shift + $dest_unit = self::$units[$state][$dest_state][0]; + } + + // Do the conversion if necessary + if ($dest_unit !== $unit) { + $factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp); + $n = $this->mul($n, $factor, $cp); + $unit = $dest_unit; + } + + // Output was zero, so bail out early. Shouldn't ever happen. + if ($n === '') { + $n = '0'; + $unit = $to_unit; + break; + } + + // It was a simple conversion, so bail out + if ($dest_state === $state) { + break; + } + + if ($i !== 0) { + // Conversion failed! Apparently, the system we forwarded + // to didn't have this unit. This should never happen! + return false; + } + + // Pre-condition: $i == 0 + + // Perform conversion to next system of units + $n = $this->mul($n, self::$units[$state][$dest_state][1], $cp); + $unit = self::$units[$state][$dest_state][2]; + $state = $dest_state; + + // One more loop around to convert the unit in the new system. + + } + + // Post-condition: $unit == $to_unit + if ($unit !== $to_unit) return false; + + // Useful for debugging: + //echo "
    n";
    +        //echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n
    \n"; + + $n = $this->round($n, $sigfigs); + if (strpos($n, '.') !== false) $n = rtrim($n, '0'); + $n = rtrim($n, '.'); + + return new HTMLPurifier_Length($n, $unit); + } + + /** + * Returns the number of significant figures in a string number. + * @param string $n Decimal number + * @return int number of sigfigs + */ + public function getSigFigs($n) { + $n = ltrim($n, '0+-'); + $dp = strpos($n, '.'); // decimal position + if ($dp === false) { + $sigfigs = strlen(rtrim($n, '0')); + } else { + $sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character + if ($dp !== 0) $sigfigs--; + } + return $sigfigs; + } + + /** + * Adds two numbers, using arbitrary precision when available. + */ + private function add($s1, $s2, $scale) { + if ($this->bcmath) return bcadd($s1, $s2, $scale); + else return $this->scale($s1 + $s2, $scale); + } + + /** + * Multiples two numbers, using arbitrary precision when available. + */ + private function mul($s1, $s2, $scale) { + if ($this->bcmath) return bcmul($s1, $s2, $scale); + else return $this->scale($s1 * $s2, $scale); + } + + /** + * Divides two numbers, using arbitrary precision when available. + */ + private function div($s1, $s2, $scale) { + if ($this->bcmath) return bcdiv($s1, $s2, $scale); + else return $this->scale($s1 / $s2, $scale); + } + + /** + * Rounds a number according to the number of sigfigs it should have, + * using arbitrary precision when available. + */ + private function round($n, $sigfigs) { + $new_log = (int) floor(log(abs($n), 10)); // Number of digits left of decimal - 1 + $rp = $sigfigs - $new_log - 1; // Number of decimal places needed + $neg = $n < 0 ? '-' : ''; // Negative sign + if ($this->bcmath) { + if ($rp >= 0) { + $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1); + $n = bcdiv($n, '1', $rp); + } else { + // This algorithm partially depends on the standardized + // form of numbers that comes out of bcmath. + $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0); + $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1); + } + return $n; + } else { + return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1); + } + } + + /** + * Scales a float to $scale digits right of decimal point, like BCMath. + */ + private function scale($r, $scale) { + if ($scale < 0) { + // The f sprintf type doesn't support negative numbers, so we + // need to cludge things manually. First get the string. + $r = sprintf('%.0f', (float) $r); + // Due to floating point precision loss, $r will more than likely + // look something like 4652999999999.9234. We grab one more digit + // than we need to precise from $r and then use that to round + // appropriately. + $precise = (string) round(substr($r, 0, strlen($r) + $scale), -1); + // Now we return it, truncating the zero that was rounded off. + return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); + } + return sprintf('%.' . $scale . 'f', (float) $r); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/VarParser.php b/extlib/HTMLPurifier/HTMLPurifier/VarParser.php new file mode 100644 index 0000000000..68e72ae869 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/VarParser.php @@ -0,0 +1,154 @@ + self::STRING, + 'istring' => self::ISTRING, + 'text' => self::TEXT, + 'itext' => self::ITEXT, + 'int' => self::INT, + 'float' => self::FLOAT, + 'bool' => self::BOOL, + 'lookup' => self::LOOKUP, + 'list' => self::ALIST, + 'hash' => self::HASH, + 'mixed' => self::MIXED + ); + + /** + * Lookup table of types that are string, and can have aliases or + * allowed value lists. + */ + static public $stringTypes = array( + self::STRING => true, + self::ISTRING => true, + self::TEXT => true, + self::ITEXT => true, + ); + + /** + * Validate a variable according to type. Throws + * HTMLPurifier_VarParserException if invalid. + * It may return NULL as a valid type if $allow_null is true. + * + * @param $var Variable to validate + * @param $type Type of variable, see HTMLPurifier_VarParser->types + * @param $allow_null Whether or not to permit null as a value + * @return Validated and type-coerced variable + */ + final public function parse($var, $type, $allow_null = false) { + if (is_string($type)) { + if (!isset(HTMLPurifier_VarParser::$types[$type])) { + throw new HTMLPurifier_VarParserException("Invalid type '$type'"); + } else { + $type = HTMLPurifier_VarParser::$types[$type]; + } + } + $var = $this->parseImplementation($var, $type, $allow_null); + if ($allow_null && $var === null) return null; + // These are basic checks, to make sure nothing horribly wrong + // happened in our implementations. + switch ($type) { + case (self::STRING): + case (self::ISTRING): + case (self::TEXT): + case (self::ITEXT): + if (!is_string($var)) break; + if ($type == self::ISTRING || $type == self::ITEXT) $var = strtolower($var); + return $var; + case (self::INT): + if (!is_int($var)) break; + return $var; + case (self::FLOAT): + if (!is_float($var)) break; + return $var; + case (self::BOOL): + if (!is_bool($var)) break; + return $var; + case (self::LOOKUP): + case (self::ALIST): + case (self::HASH): + if (!is_array($var)) break; + if ($type === self::LOOKUP) { + foreach ($var as $k) if ($k !== true) $this->error('Lookup table contains value other than true'); + } elseif ($type === self::ALIST) { + $keys = array_keys($var); + if (array_keys($keys) !== $keys) $this->error('Indices for list are not uniform'); + } + return $var; + case (self::MIXED): + return $var; + default: + $this->errorInconsistent(get_class($this), $type); + } + $this->errorGeneric($var, $type); + } + + /** + * Actually implements the parsing. Base implementation is to not + * do anything to $var. Subclasses should overload this! + */ + protected function parseImplementation($var, $type, $allow_null) { + return $var; + } + + /** + * Throws an exception. + */ + protected function error($msg) { + throw new HTMLPurifier_VarParserException($msg); + } + + /** + * Throws an inconsistency exception. + * @note This should not ever be called. It would be called if we + * extend the allowed values of HTMLPurifier_VarParser without + * updating subclasses. + */ + protected function errorInconsistent($class, $type) { + throw new HTMLPurifier_Exception("Inconsistency in $class: ".HTMLPurifier_VarParser::getTypeName($type)." not implemented"); + } + + /** + * Generic error for if a type didn't work. + */ + protected function errorGeneric($var, $type) { + $vtype = gettype($var); + $this->error("Expected type ".HTMLPurifier_VarParser::getTypeName($type).", got $vtype"); + } + + static public function getTypeName($type) { + static $lookup; + if (!$lookup) { + // Lazy load the alternative lookup table + $lookup = array_flip(HTMLPurifier_VarParser::$types); + } + if (!isset($lookup[$type])) return 'unknown'; + return $lookup[$type]; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php b/extlib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php new file mode 100644 index 0000000000..c954250e9f --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php @@ -0,0 +1,96 @@ + $j) $var[$i] = trim($j); + if ($type === self::HASH) { + // key:value,key2:value2 + $nvar = array(); + foreach ($var as $keypair) { + $c = explode(':', $keypair, 2); + if (!isset($c[1])) continue; + $nvar[$c[0]] = $c[1]; + } + $var = $nvar; + } + } + if (!is_array($var)) break; + $keys = array_keys($var); + if ($keys === array_keys($keys)) { + if ($type == self::ALIST) return $var; + elseif ($type == self::LOOKUP) { + $new = array(); + foreach ($var as $key) { + $new[$key] = true; + } + return $new; + } else break; + } + if ($type === self::LOOKUP) { + foreach ($var as $key => $value) { + $var[$key] = true; + } + } + return $var; + default: + $this->errorInconsistent(__CLASS__, $type); + } + $this->errorGeneric($var, $type); + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/VarParser/Native.php b/extlib/HTMLPurifier/HTMLPurifier/VarParser/Native.php new file mode 100644 index 0000000000..b02a6de54c --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/VarParser/Native.php @@ -0,0 +1,26 @@ +evalExpression($var); + } + + protected function evalExpression($expr) { + $var = null; + $result = eval("\$var = $expr;"); + if ($result === false) { + throw new HTMLPurifier_VarParserException("Fatal error in evaluated code"); + } + return $var; + } + +} + +// vim: et sw=4 sts=4 diff --git a/extlib/HTMLPurifier/HTMLPurifier/VarParserException.php b/extlib/HTMLPurifier/HTMLPurifier/VarParserException.php new file mode 100644 index 0000000000..5df3414959 --- /dev/null +++ b/extlib/HTMLPurifier/HTMLPurifier/VarParserException.php @@ -0,0 +1,11 @@ + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + vim: et sw=4 sts=4 From ab4ec095e811f86c50fbc1cd71144b11d6b86d50 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 11:38:05 -0500 Subject: [PATCH 054/190] adjust URI, URL, and location in Ostatus_profile::processPost --- plugins/OStatus/classes/Ostatus_profile.php | 27 ++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 9f5c605612..4dd5652886 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -457,28 +457,33 @@ class Ostatus_profile extends Memcached_DataObject $oprofile = $this; } - if ($activity->object->link) { - $sourceUri = $activity->object->link; - } else if (preg_match('!^https?://!', $activity->object->id)) { - $sourceUri = $activity->object->id; - } else { - common_log(LOG_INFO, "OStatus: ignoring post with no source link: id $activity->object->id"); + $sourceUri = $activity->object->id; + + $dupe = Notice::staticGet('uri', $sourceUri); + + if ($dupe) { + common_log(LOG_INFO, "OStatus: ignoring duplicate post: $sourceUri"); return; } - $dupe = Notice::staticGet('uri', $sourceUri); - if ($dupe) { - common_log(LOG_INFO, "OStatus: ignoring duplicate post: $noticeLink"); - return; + $sourceUrl = null; + + if ($activity->object->link) { + $sourceUrl = $activity->object->link; + } else if (preg_match('!^https?://!', $activity->object->id)) { + $sourceUrl = $activity->object->id; } // @fixme sanitize and save HTML content if available + $content = $activity->object->title; $params = array('is_local' => Notice::REMOTE_OMB, + 'url' => $sourceUrl, 'uri' => $sourceUri); - $location = $this->getEntryLocation($activity->entry); + $location = $activity->context->location; + if ($location) { $params['lat'] = $location->lat; $params['lon'] = $location->lon; From 866b6470629b570b9f817553f85f6d8e801f0d43 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 11:48:42 -0500 Subject: [PATCH 055/190] add hooks for OStatus notification on subscribe/unsubscribe --- plugins/OStatus/OStatusPlugin.php | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index e1f3fd9d37..9e6d03177f 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -335,4 +335,48 @@ class OStatusPlugin extends Plugin common_log(LOG_DEBUG, "No ostatus profile for incoming feed $feedsub->uri"); } } + + function onEndSubscribe($subscriber, $other) + { + $user = User::staticGet('id', $subscriber->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + + if (empty($oprofile)) { + return true; + } + + // We have a local user subscribing to a remote profile; make the + // magic happen! + + $oprofile->notify($subscriber, ActivityVerb::FOLLOW); + + return true; + } + + function onEndUnsubscribe($subscriber, $other) + { + $user = User::staticGet('id', $subscriber->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + + if (empty($oprofile)) { + return true; + } + + // We have a local user subscribing to a remote profile; make the + // magic happen! + + $oprofile->notify($subscriber, ActivityVerb::UNFOLLOW); + + return true; + } } From 36d21fa7162ca94ce100433da53439a67e815ba1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 12:03:32 -0500 Subject: [PATCH 056/190] Add events for favor and disfavor Added events to core code for when someone favors or disfavors a notice. --- EVENTS.txt | 19 +++++++++++++++++++ classes/Fave.php | 44 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index 90242fa133..c108606ce2 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -729,3 +729,22 @@ StartGetProfileUri: When determining the canonical URI for a given profile EndGetProfileUri: After determining the canonical URI for a given profile - $profile: the current profile - &$uri: the URI + +StartFavorNotice: Saving a notice as a favorite +- $profile: profile of the person faving (can be remote!) +- $notice: notice being faved +- &$fave: Favor object; null to start off with, but feel free to override. + +EndFavorNotice: After saving a notice as a favorite +- $profile: profile of the person faving (can be remote!) +- $notice: notice being faved + +StartDisfavorNotice: Saving a notice as a favorite +- $profile: profile of the person faving (can be remote!) +- $notice: notice being faved +- &$result: result of the disfavoring (if you override) + +EndDisfavorNotice: After saving a notice as a favorite +- $profile: profile of the person faving (can be remote!) +- $notice: notice being faved + diff --git a/classes/Fave.php b/classes/Fave.php index 8113c8e166..0b6eec2bc4 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -21,17 +21,47 @@ class Fave extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - static function addNew($user, $notice) { - $fave = new Fave(); - $fave->user_id = $user->id; - $fave->notice_id = $notice->id; - if (!$fave->insert()) { - common_log_db_error($fave, 'INSERT', __FILE__); - return false; + static function addNew($profile, $notice) { + + $fave = null; + + if (Event::handle('StartFavorNotice', array($profile, $notice, &$fave))) { + + $fave = new Fave(); + + $fave->user_id = $profile->id; + $fave->notice_id = $notice->id; + + if (!$fave->insert()) { + common_log_db_error($fave, 'INSERT', __FILE__); + return false; + } + + Event::handle('EndFavorNotice', array($profile, $notice)); } + return $fave; } + function delete() + { + $profile = Profile::staticGet('id', $this->user_id); + $notice = Notice::staticGet('id', $this->notice_id); + + $result = null; + + if (Event::handle('StartDisfavorNotice', array($profile, $notice, &$result))) { + + $result = parent::delete(); + + if ($result) { + Event::handle('EndDisfavorNotice', array($profile, $notice)); + } + } + + return $result; + } + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Fave', $kv); From 97b01432e7903797e39205e46a51394feac54292 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 20 Feb 2010 10:06:28 -0800 Subject: [PATCH 057/190] drop no-longer-used XML_Feed_Parser extlib package from OStatus plugin --- plugins/OStatus/extlib/README | 9 - plugins/OStatus/extlib/XML/Feed/Parser.php | 351 ------------- .../OStatus/extlib/XML/Feed/Parser/Atom.php | 365 -------------- .../extlib/XML/Feed/Parser/AtomElement.php | 261 ---------- .../extlib/XML/Feed/Parser/Exception.php | 42 -- .../OStatus/extlib/XML/Feed/Parser/RSS09.php | 214 -------- .../extlib/XML/Feed/Parser/RSS09Element.php | 62 --- .../OStatus/extlib/XML/Feed/Parser/RSS1.php | 277 ----------- .../OStatus/extlib/XML/Feed/Parser/RSS11.php | 276 ----------- .../extlib/XML/Feed/Parser/RSS11Element.php | 151 ------ .../extlib/XML/Feed/Parser/RSS1Element.php | 116 ----- .../OStatus/extlib/XML/Feed/Parser/RSS2.php | 335 ------------- .../extlib/XML/Feed/Parser/RSS2Element.php | 171 ------- .../OStatus/extlib/XML/Feed/Parser/Type.php | 467 ------------------ .../XML/Feed/samples/atom10-entryonly.xml | 28 -- .../XML/Feed/samples/atom10-example1.xml | 20 - .../XML/Feed/samples/atom10-example2.xml | 45 -- .../extlib/XML/Feed/samples/delicious.feed | 177 ------- .../extlib/XML/Feed/samples/flickr.feed | 184 ------- .../extlib/XML/Feed/samples/grwifi-atom.xml | 7 - .../OStatus/extlib/XML/Feed/samples/hoder.xml | 102 ---- .../XML/Feed/samples/illformed_atom10.xml | 13 - .../XML/Feed/samples/rss091-complete.xml | 47 -- .../XML/Feed/samples/rss091-international.xml | 30 -- .../extlib/XML/Feed/samples/rss091-simple.xml | 15 - .../extlib/XML/Feed/samples/rss092-sample.xml | 103 ---- .../XML/Feed/samples/rss10-example1.xml | 62 --- .../XML/Feed/samples/rss10-example2.xml | 67 --- .../extlib/XML/Feed/samples/rss2sample.xml | 42 -- .../extlib/XML/Feed/samples/sixapart-jp.xml | 226 --------- .../extlib/XML/Feed/samples/technorati.feed | 54 -- .../OStatus/extlib/XML/Feed/schemas/atom.rnc | 338 ------------- .../OStatus/extlib/XML/Feed/schemas/rss10.rnc | 113 ----- .../OStatus/extlib/XML/Feed/schemas/rss11.rnc | 218 -------- .../extlib/xml-feed-parser-bug-16416.patch | 14 - plugins/OStatus/tests/FeedMungerTest.php | 147 ------ 36 files changed, 5149 deletions(-) delete mode 100644 plugins/OStatus/extlib/README delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser.php delete mode 100644 plugins/OStatus/extlib/XML/Feed/Parser/Atom.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/AtomElement.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/Exception.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/RSS09.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/RSS09Element.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/RSS1.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/RSS11.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/RSS11Element.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/RSS1Element.php delete mode 100644 plugins/OStatus/extlib/XML/Feed/Parser/RSS2.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/Parser/RSS2Element.php delete mode 100644 plugins/OStatus/extlib/XML/Feed/Parser/Type.php delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/atom10-entryonly.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/atom10-example1.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/atom10-example2.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/delicious.feed delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/flickr.feed delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/grwifi-atom.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/hoder.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/illformed_atom10.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/rss091-complete.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/rss091-international.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/rss091-simple.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/rss092-sample.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/rss10-example1.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/rss10-example2.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/rss2sample.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/sixapart-jp.xml delete mode 100755 plugins/OStatus/extlib/XML/Feed/samples/technorati.feed delete mode 100755 plugins/OStatus/extlib/XML/Feed/schemas/atom.rnc delete mode 100755 plugins/OStatus/extlib/XML/Feed/schemas/rss10.rnc delete mode 100755 plugins/OStatus/extlib/XML/Feed/schemas/rss11.rnc delete mode 100644 plugins/OStatus/extlib/xml-feed-parser-bug-16416.patch delete mode 100644 plugins/OStatus/tests/FeedMungerTest.php diff --git a/plugins/OStatus/extlib/README b/plugins/OStatus/extlib/README deleted file mode 100644 index 799b40c478..0000000000 --- a/plugins/OStatus/extlib/README +++ /dev/null @@ -1,9 +0,0 @@ -XML_Feed_Parser 1.0.3 is not currently actively maintained, and has -a nasty bug which breaks getting the feed target link from WordPress -feeds and possibly others that are RSS2-formatted but include an - self-link element as well. - -Patch from this bug report is included: -http://pear.php.net/bugs/bug.php?id=16416 - -If upgrading, be sure that fix is included with the future upgrade! diff --git a/plugins/OStatus/extlib/XML/Feed/Parser.php b/plugins/OStatus/extlib/XML/Feed/Parser.php deleted file mode 100755 index ffe8220a52..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser.php +++ /dev/null @@ -1,351 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL - * @version CVS: $Id: Parser.php,v 1.24 2006/08/15 13:04:00 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * XML_Feed_Parser_Type is an abstract class required by all of our - * feed types. It makes sense to load it here to keep the other files - * clean. - */ -require_once 'XML/Feed/Parser/Type.php'; - -/** - * We will throw exceptions when errors occur. - */ -require_once 'XML/Feed/Parser/Exception.php'; - -/** - * This is the core of the XML_Feed_Parser package. It identifies feed types - * and abstracts access to them. It is an iterator, allowing for easy access - * to the entire feed. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser implements Iterator -{ - /** - * This is where we hold the feed object - * @var Object - */ - private $feed; - - /** - * To allow for extensions, we make a public reference to the feed model - * @var DOMDocument - */ - public $model; - - /** - * A map between entry ID and offset - * @var array - */ - protected $idMappings = array(); - - /** - * A storage space for Namespace URIs. - * @var array - */ - private $feedNamespaces = array( - 'rss2' => array( - 'http://backend.userland.com/rss', - 'http://backend.userland.com/rss2', - 'http://blogs.law.harvard.edu/tech/rss')); - /** - * Detects feed types and instantiate appropriate objects. - * - * Our constructor takes care of detecting feed types and instantiating - * appropriate classes. For now we're going to treat Atom 0.3 as Atom 1.0 - * but raise a warning. I do not intend to introduce full support for - * Atom 0.3 as it has been deprecated, but others are welcome to. - * - * @param string $feed XML serialization of the feed - * @param bool $strict Whether or not to validate the feed - * @param bool $suppressWarnings Trigger errors for deprecated feed types? - * @param bool $tidy Whether or not to try and use the tidy library on input - */ - function __construct($feed, $strict = false, $suppressWarnings = false, $tidy = false) - { - $this->model = new DOMDocument; - if (! $this->model->loadXML($feed)) { - if (extension_loaded('tidy') && $tidy) { - $tidy = new tidy; - $tidy->parseString($feed, - array('input-xml' => true, 'output-xml' => true)); - $tidy->cleanRepair(); - if (! $this->model->loadXML((string) $tidy)) { - throw new XML_Feed_Parser_Exception('Invalid input: this is not ' . - 'valid XML'); - } - } else { - throw new XML_Feed_Parser_Exception('Invalid input: this is not valid XML'); - } - - } - - /* detect feed type */ - $doc_element = $this->model->documentElement; - $error = false; - - switch (true) { - case ($doc_element->namespaceURI == 'http://www.w3.org/2005/Atom'): - require_once 'XML/Feed/Parser/Atom.php'; - require_once 'XML/Feed/Parser/AtomElement.php'; - $class = 'XML_Feed_Parser_Atom'; - break; - case ($doc_element->namespaceURI == 'http://purl.org/atom/ns#'): - require_once 'XML/Feed/Parser/Atom.php'; - require_once 'XML/Feed/Parser/AtomElement.php'; - $class = 'XML_Feed_Parser_Atom'; - $error = 'Atom 0.3 deprecated, using 1.0 parser which won\'t provide ' . - 'all options'; - break; - case ($doc_element->namespaceURI == 'http://purl.org/rss/1.0/' || - ($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1 - && $doc_element->childNodes->item(1)->namespaceURI == - 'http://purl.org/rss/1.0/')): - require_once 'XML/Feed/Parser/RSS1.php'; - require_once 'XML/Feed/Parser/RSS1Element.php'; - $class = 'XML_Feed_Parser_RSS1'; - break; - case ($doc_element->namespaceURI == 'http://purl.org/rss/1.1/' || - ($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1 - && $doc_element->childNodes->item(1)->namespaceURI == - 'http://purl.org/rss/1.1/')): - require_once 'XML/Feed/Parser/RSS11.php'; - require_once 'XML/Feed/Parser/RSS11Element.php'; - $class = 'XML_Feed_Parser_RSS11'; - break; - case (($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1 - && $doc_element->childNodes->item(1)->namespaceURI == - 'http://my.netscape.com/rdf/simple/0.9/') || - $doc_element->namespaceURI == 'http://my.netscape.com/rdf/simple/0.9/'): - require_once 'XML/Feed/Parser/RSS09.php'; - require_once 'XML/Feed/Parser/RSS09Element.php'; - $class = 'XML_Feed_Parser_RSS09'; - break; - case ($doc_element->tagName == 'rss' and - $doc_element->hasAttribute('version') && - $doc_element->getAttribute('version') == 0.91): - $error = 'RSS 0.91 has been superceded by RSS2.0. Using RSS2.0 parser.'; - require_once 'XML/Feed/Parser/RSS2.php'; - require_once 'XML/Feed/Parser/RSS2Element.php'; - $class = 'XML_Feed_Parser_RSS2'; - break; - case ($doc_element->tagName == 'rss' and - $doc_element->hasAttribute('version') && - $doc_element->getAttribute('version') == 0.92): - $error = 'RSS 0.92 has been superceded by RSS2.0. Using RSS2.0 parser.'; - require_once 'XML/Feed/Parser/RSS2.php'; - require_once 'XML/Feed/Parser/RSS2Element.php'; - $class = 'XML_Feed_Parser_RSS2'; - break; - case (in_array($doc_element->namespaceURI, $this->feedNamespaces['rss2']) - || $doc_element->tagName == 'rss'): - if (! $doc_element->hasAttribute('version') || - $doc_element->getAttribute('version') != 2) { - $error = 'RSS version not specified. Parsing as RSS2.0'; - } - require_once 'XML/Feed/Parser/RSS2.php'; - require_once 'XML/Feed/Parser/RSS2Element.php'; - $class = 'XML_Feed_Parser_RSS2'; - break; - default: - throw new XML_Feed_Parser_Exception('Feed type unknown'); - break; - } - - if (! $suppressWarnings && ! empty($error)) { - trigger_error($error, E_USER_WARNING); - } - - /* Instantiate feed object */ - $this->feed = new $class($this->model, $strict); - } - - /** - * Proxy to allow feed element names to be used as method names - * - * For top-level feed elements we will provide access using methods or - * attributes. This function simply passes on a request to the appropriate - * feed type object. - * - * @param string $call - the method being called - * @param array $attributes - */ - function __call($call, $attributes) - { - $attributes = array_pad($attributes, 5, false); - list($a, $b, $c, $d, $e) = $attributes; - return $this->feed->$call($a, $b, $c, $d, $e); - } - - /** - * Proxy to allow feed element names to be used as attribute names - * - * To allow variable-like access to feed-level data we use this - * method. It simply passes along to __call() which in turn passes - * along to the relevant object. - * - * @param string $val - the name of the variable required - */ - function __get($val) - { - return $this->feed->$val; - } - - /** - * Provides iteration functionality. - * - * Of course we must be able to iterate... This function simply increases - * our internal counter. - */ - function next() - { - if (isset($this->current_item) && - $this->current_item <= $this->feed->numberEntries - 1) { - ++$this->current_item; - } else if (! isset($this->current_item)) { - $this->current_item = 0; - } else { - return false; - } - } - - /** - * Return XML_Feed_Type object for current element - * - * @return XML_Feed_Parser_Type Object - */ - function current() - { - return $this->getEntryByOffset($this->current_item); - } - - /** - * For iteration -- returns the key for the current stage in the array. - * - * @return int - */ - function key() - { - return $this->current_item; - } - - /** - * For iteration -- tells whether we have reached the - * end. - * - * @return bool - */ - function valid() - { - return $this->current_item < $this->feed->numberEntries; - } - - /** - * For iteration -- resets the internal counter to the beginning. - */ - function rewind() - { - $this->current_item = 0; - } - - /** - * Provides access to entries by ID if one is specified in the source feed. - * - * As well as allowing the items to be iterated over we want to allow - * users to be able to access a specific entry. This is one of two ways of - * doing that, the other being by offset. This method can be quite slow - * if dealing with a large feed that hasn't yet been processed as it - * instantiates objects for every entry until it finds the one needed. - * - * @param string $id Valid ID for the given feed format - * @return XML_Feed_Parser_Type|false - */ - function getEntryById($id) - { - if (isset($this->idMappings[$id])) { - return $this->getEntryByOffset($this->idMappings[$id]); - } - - /* - * Since we have not yet encountered that ID, let's go through all the - * remaining entries in order till we find it. - * This is a fairly slow implementation, but it should work. - */ - return $this->feed->getEntryById($id); - } - - /** - * Retrieve entry by numeric offset, starting from zero. - * - * As well as allowing the items to be iterated over we want to allow - * users to be able to access a specific entry. This is one of two ways of - * doing that, the other being by ID. - * - * @param int $offset The position of the entry within the feed, starting from 0 - * @return XML_Feed_Parser_Type|false - */ - function getEntryByOffset($offset) - { - if ($offset < $this->feed->numberEntries) { - if (isset($this->feed->entries[$offset])) { - return $this->feed->entries[$offset]; - } else { - try { - $this->feed->getEntryByOffset($offset); - } catch (Exception $e) { - return false; - } - $id = $this->feed->entries[$offset]->getID(); - $this->idMappings[$id] = $offset; - return $this->feed->entries[$offset]; - } - } else { - return false; - } - } - - /** - * Retrieve version details from feed type class. - * - * @return void - * @author James Stewart - */ - function version() - { - return $this->feed->version; - } - - /** - * Returns a string representation of the feed. - * - * @return String - **/ - function __toString() - { - return $this->feed->__toString(); - } -} -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/Atom.php b/plugins/OStatus/extlib/XML/Feed/Parser/Atom.php deleted file mode 100644 index c7e218a1e6..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/Atom.php +++ /dev/null @@ -1,365 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: Atom.php,v 1.29 2008/03/30 22:00:36 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ -*/ - -/** - * This is the class that determines how we manage Atom 1.0 feeds - * - * How we deal with constructs: - * date - return as unix datetime for use with the 'date' function unless specified otherwise - * text - return as is. optional parameter will give access to attributes - * person - defaults to name, but parameter based access - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_Atom extends XML_Feed_Parser_Type -{ - /** - * The URI of the RelaxNG schema used to (optionally) validate the feed - * @var string - */ - private $relax = 'atom.rnc'; - - /** - * We're likely to use XPath, so let's keep it global - * @var DOMXPath - */ - public $xpath; - - /** - * When performing XPath queries we will use this prefix - * @var string - */ - private $xpathPrefix = '//'; - - /** - * The feed type we are parsing - * @var string - */ - public $version = 'Atom 1.0'; - - /** - * The class used to represent individual items - * @var string - */ - protected $itemClass = 'XML_Feed_Parser_AtomElement'; - - /** - * The element containing entries - * @var string - */ - protected $itemElement = 'entry'; - - /** - * Here we map those elements we're not going to handle individually - * to the constructs they are. The optional second parameter in the array - * tells the parser whether to 'fall back' (not apt. at the feed level) or - * fail if the element is missing. If the parameter is not set, the function - * will simply return false and leave it to the client to decide what to do. - * @var array - */ - protected $map = array( - 'author' => array('Person'), - 'contributor' => array('Person'), - 'icon' => array('Text'), - 'logo' => array('Text'), - 'id' => array('Text', 'fail'), - 'rights' => array('Text'), - 'subtitle' => array('Text'), - 'title' => array('Text', 'fail'), - 'updated' => array('Date', 'fail'), - 'link' => array('Link'), - 'generator' => array('Text'), - 'category' => array('Category')); - - /** - * Here we provide a few mappings for those very special circumstances in - * which it makes sense to map back to the RSS2 spec. Key is RSS2 version - * value is an array consisting of the equivalent in atom and any attributes - * needed to make the mapping. - * @var array - */ - protected $compatMap = array( - 'guid' => array('id'), - 'links' => array('link'), - 'tags' => array('category'), - 'contributors' => array('contributor')); - - /** - * Our constructor does nothing more than its parent. - * - * @param DOMDocument $xml A DOM object representing the feed - * @param bool (optional) $string Whether or not to validate this feed - */ - function __construct(DOMDocument $model, $strict = false) - { - $this->model = $model; - - if ($strict) { - if (! $this->model->relaxNGValidateSource($this->relax)) { - throw new XML_Feed_Parser_Exception('Failed required validation'); - } - } - - $this->xpath = new DOMXPath($this->model); - $this->xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom'); - $this->numberEntries = $this->count('entry'); - } - - /** - * Implement retrieval of an entry based on its ID for atom feeds. - * - * This function uses XPath to get the entry based on its ID. If DOMXPath::evaluate - * is available, we also use that to store a reference to the entry in the array - * used by getEntryByOffset so that method does not have to seek out the entry - * if it's requested that way. - * - * @param string $id any valid Atom ID. - * @return XML_Feed_Parser_AtomElement - */ - function getEntryById($id) - { - if (isset($this->idMappings[$id])) { - return $this->entries[$this->idMappings[$id]]; - } - - $entries = $this->xpath->query("//atom:entry[atom:id='$id']"); - - if ($entries->length > 0) { - $xmlBase = $entries->item(0)->baseURI; - $entry = new $this->itemClass($entries->item(0), $this, $xmlBase); - - if (in_array('evaluate', get_class_methods($this->xpath))) { - $offset = $this->xpath->evaluate("count(preceding-sibling::atom:entry)", $entries->item(0)); - $this->entries[$offset] = $entry; - } - - $this->idMappings[$id] = $entry; - - return $entry; - } - - } - - /** - * Retrieves data from a person construct. - * - * Get a person construct. We default to the 'name' element but allow - * access to any of the elements. - * - * @param string $method The name of the person construct we want - * @param array $arguments An array which we hope gives a 'param' - * @return string|false - */ - protected function getPerson($method, $arguments) - { - $offset = empty($arguments[0]) ? 0 : $arguments[0]; - $parameter = empty($arguments[1]['param']) ? 'name' : $arguments[1]['param']; - $section = $this->model->getElementsByTagName($method); - - if ($parameter == 'url') { - $parameter = 'uri'; - } - - if ($section->length <= $offset) { - return false; - } - - $param = $section->item($offset)->getElementsByTagName($parameter); - if ($param->length == 0) { - return false; - } - return $param->item(0)->nodeValue; - } - - /** - * Retrieves an element's content where that content is a text construct. - * - * Get a text construct. When calling this method, the two arguments - * allowed are 'offset' and 'attribute', so $parser->subtitle() would - * return the content of the element, while $parser->subtitle(false, 'type') - * would return the value of the type attribute. - * - * @todo Clarify overlap with getContent() - * @param string $method The name of the text construct we want - * @param array $arguments An array which we hope gives a 'param' - * @return string - */ - protected function getText($method, $arguments) - { - $offset = empty($arguments[0]) ? 0: $arguments[0]; - $attribute = empty($arguments[1]) ? false : $arguments[1]; - $tags = $this->model->getElementsByTagName($method); - - if ($tags->length <= $offset) { - return false; - } - - $content = $tags->item($offset); - - if (! $content->hasAttribute('type')) { - $content->setAttribute('type', 'text'); - } - $type = $content->getAttribute('type'); - - if (! empty($attribute) and - ! ($method == 'generator' and $attribute == 'name')) { - if ($content->hasAttribute($attribute)) { - return $content->getAttribute($attribute); - } else if ($attribute == 'href' and $content->hasAttribute('uri')) { - return $content->getAttribute('uri'); - } - return false; - } - - return $this->parseTextConstruct($content); - } - - /** - * Extract content appropriately from atom text constructs - * - * Because of different rules applied to the content element and other text - * constructs, they are deployed as separate functions, but they share quite - * a bit of processing. This method performs the core common process, which is - * to apply the rules for different mime types in order to extract the content. - * - * @param DOMNode $content the text construct node to be parsed - * @return String - * @author James Stewart - **/ - protected function parseTextConstruct(DOMNode $content) - { - if ($content->hasAttribute('type')) { - $type = $content->getAttribute('type'); - } else { - $type = 'text'; - } - - if (strpos($type, 'text/') === 0) { - $type = 'text'; - } - - switch ($type) { - case 'text': - case 'html': - return $content->textContent; - break; - case 'xhtml': - $container = $content->getElementsByTagName('div'); - if ($container->length == 0) { - return false; - } - $contents = $container->item(0); - if ($contents->hasChildNodes()) { - /* Iterate through, applying xml:base and store the result */ - $result = ''; - foreach ($contents->childNodes as $node) { - $result .= $this->traverseNode($node); - } - return $result; - } - break; - case preg_match('@^[a-zA-Z]+/[a-zA-Z+]*xml@i', $type) > 0: - return $content; - break; - case 'application/octet-stream': - default: - return base64_decode(trim($content->nodeValue)); - break; - } - return false; - } - /** - * Get a category from the entry. - * - * A feed or entry can have any number of categories. A category can have the - * attributes term, scheme and label. - * - * @param string $method The name of the text construct we want - * @param array $arguments An array which we hope gives a 'param' - * @return string - */ - function getCategory($method, $arguments) - { - $offset = empty($arguments[0]) ? 0: $arguments[0]; - $attribute = empty($arguments[1]) ? 'term' : $arguments[1]; - $categories = $this->model->getElementsByTagName('category'); - if ($categories->length <= $offset) { - $category = $categories->item($offset); - if ($category->hasAttribute($attribute)) { - return $category->getAttribute($attribute); - } - } - return false; - } - - /** - * This element must be present at least once with rel="feed". This element may be - * present any number of further times so long as there is no clash. If no 'rel' is - * present and we're asked for one, we follow the example of the Universal Feed - * Parser and presume 'alternate'. - * - * @param int $offset the position of the link within the container - * @param string $attribute the attribute name required - * @param array an array of attributes to search by - * @return string the value of the attribute - */ - function getLink($offset = 0, $attribute = 'href', $params = false) - { - if (is_array($params) and !empty($params)) { - $terms = array(); - $alt_predicate = ''; - $other_predicate = ''; - - foreach ($params as $key => $value) { - if ($key == 'rel' && $value == 'alternate') { - $alt_predicate = '[not(@rel) or @rel="alternate"]'; - } else { - $terms[] = "@$key='$value'"; - } - } - if (!empty($terms)) { - $other_predicate = '[' . join(' and ', $terms) . ']'; - } - $query = $this->xpathPrefix . 'atom:link' . $alt_predicate . $other_predicate; - $links = $this->xpath->query($query); - } else { - $links = $this->model->getElementsByTagName('link'); - } - if ($links->length > $offset) { - if ($links->item($offset)->hasAttribute($attribute)) { - $value = $links->item($offset)->getAttribute($attribute); - if ($attribute == 'href') { - $value = $this->addBase($value, $links->item($offset)); - } - return $value; - } else if ($attribute == 'rel') { - return 'alternate'; - } - } - return false; - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/AtomElement.php b/plugins/OStatus/extlib/XML/Feed/Parser/AtomElement.php deleted file mode 100755 index 063ecb6177..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/AtomElement.php +++ /dev/null @@ -1,261 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: AtomElement.php,v 1.19 2007/03/26 12:43:11 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * This class provides support for atom entries. It will usually be called by - * XML_Feed_Parser_Atom with which it shares many methods. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_AtomElement extends XML_Feed_Parser_Atom -{ - /** - * This will be a reference to the parent object for when we want - * to use a 'fallback' rule - * @var XML_Feed_Parser_Atom - */ - protected $parent; - - /** - * When performing XPath queries we will use this prefix - * @var string - */ - private $xpathPrefix = ''; - - /** - * xml:base values inherited by the element - * @var string - */ - protected $xmlBase; - - /** - * Here we provide a few mappings for those very special circumstances in - * which it makes sense to map back to the RSS2 spec or to manage other - * compatibilities (eg. with the Univeral Feed Parser). Key is the other version's - * name for the command, value is an array consisting of the equivalent in our atom - * api and any attributes needed to make the mapping. - * @var array - */ - protected $compatMap = array( - 'guid' => array('id'), - 'links' => array('link'), - 'tags' => array('category'), - 'contributors' => array('contributor')); - - /** - * Our specific element map - * @var array - */ - protected $map = array( - 'author' => array('Person', 'fallback'), - 'contributor' => array('Person'), - 'id' => array('Text', 'fail'), - 'published' => array('Date'), - 'updated' => array('Date', 'fail'), - 'title' => array('Text', 'fail'), - 'rights' => array('Text', 'fallback'), - 'summary' => array('Text'), - 'content' => array('Content'), - 'link' => array('Link'), - 'enclosure' => array('Enclosure'), - 'category' => array('Category')); - - /** - * Store useful information for later. - * - * @param DOMElement $element - this item as a DOM element - * @param XML_Feed_Parser_Atom $parent - the feed of which this is a member - */ - function __construct(DOMElement $element, $parent, $xmlBase = '') - { - $this->model = $element; - $this->parent = $parent; - $this->xmlBase = $xmlBase; - $this->xpathPrefix = "//atom:entry[atom:id='" . $this->id . "']/"; - $this->xpath = $this->parent->xpath; - } - - /** - * Provides access to specific aspects of the author data for an atom entry - * - * Author data at the entry level is more complex than at the feed level. - * If atom:author is not present for the entry we need to look for it in - * an atom:source child of the atom:entry. If it's not there either, then - * we look to the parent for data. - * - * @param array - * @return string - */ - function getAuthor($arguments) - { - /* Find out which part of the author data we're looking for */ - if (isset($arguments['param'])) { - $parameter = $arguments['param']; - } else { - $parameter = 'name'; - } - - $test = $this->model->getElementsByTagName('author'); - if ($test->length > 0) { - $item = $test->item(0); - return $item->getElementsByTagName($parameter)->item(0)->nodeValue; - } - - $source = $this->model->getElementsByTagName('source'); - if ($source->length > 0) { - $test = $this->model->getElementsByTagName('author'); - if ($test->length > 0) { - $item = $test->item(0); - return $item->getElementsByTagName($parameter)->item(0)->nodeValue; - } - } - return $this->parent->getAuthor($arguments); - } - - /** - * Returns the content of the content element or info on a specific attribute - * - * This element may or may not be present. It cannot be present more than - * once. It may have a 'src' attribute, in which case there's no content - * If not present, then the entry must have link with rel="alternate". - * If there is content we return it, if not and there's a 'src' attribute - * we return the value of that instead. The method can take an 'attribute' - * argument, in which case we return the value of that attribute if present. - * eg. $item->content("type") will return the type of the content. It is - * recommended that all users check the type before getting the content to - * ensure that their script is capable of handling the type of returned data. - * (data carried in the content element can be either 'text', 'html', 'xhtml', - * or any standard MIME type). - * - * @return string|false - */ - protected function getContent($method, $arguments = array()) - { - $attribute = empty($arguments[0]) ? false : $arguments[0]; - $tags = $this->model->getElementsByTagName('content'); - - if ($tags->length == 0) { - return false; - } - - $content = $tags->item(0); - - if (! $content->hasAttribute('type')) { - $content->setAttribute('type', 'text'); - } - if (! empty($attribute)) { - return $content->getAttribute($attribute); - } - - $type = $content->getAttribute('type'); - - if (! empty($attribute)) { - if ($content->hasAttribute($attribute)) - { - return $content->getAttribute($attribute); - } - return false; - } - - if ($content->hasAttribute('src')) { - return $content->getAttribute('src'); - } - - return $this->parseTextConstruct($content); - } - - /** - * For compatibility, this method provides a mapping to access enclosures. - * - * The Atom spec doesn't provide for an enclosure element, but it is - * generally supported using the link element with rel='enclosure'. - * - * @param string $method - for compatibility with our __call usage - * @param array $arguments - for compatibility with our __call usage - * @return array|false - */ - function getEnclosure($method, $arguments = array()) - { - $offset = isset($arguments[0]) ? $arguments[0] : 0; - $query = "//atom:entry[atom:id='" . $this->getText('id', false) . - "']/atom:link[@rel='enclosure']"; - - $encs = $this->parent->xpath->query($query); - if ($encs->length > $offset) { - try { - if (! $encs->item($offset)->hasAttribute('href')) { - return false; - } - $attrs = $encs->item($offset)->attributes; - $length = $encs->item($offset)->hasAttribute('length') ? - $encs->item($offset)->getAttribute('length') : false; - return array( - 'url' => $attrs->getNamedItem('href')->value, - 'type' => $attrs->getNamedItem('type')->value, - 'length' => $length); - } catch (Exception $e) { - return false; - } - } - return false; - } - - /** - * Get details of this entry's source, if available/relevant - * - * Where an atom:entry is taken from another feed then the aggregator - * is supposed to include an atom:source element which replicates at least - * the atom:id, atom:title, and atom:updated metadata from the original - * feed. Atom:source therefore has a very similar structure to atom:feed - * and if we find it we will return it as an XML_Feed_Parser_Atom object. - * - * @return XML_Feed_Parser_Atom|false - */ - function getSource() - { - $test = $this->model->getElementsByTagName('source'); - if ($test->length == 0) { - return false; - } - $source = new XML_Feed_Parser_Atom($test->item(0)); - } - - /** - * Get the entry as an XML string - * - * Return an XML serialization of the feed, should it be required. Most - * users however, will already have a serialization that they used when - * instantiating the object. - * - * @return string XML serialization of element - */ - function __toString() - { - $simple = simplexml_import_dom($this->model); - return $simple->asXML(); - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/Exception.php b/plugins/OStatus/extlib/XML/Feed/Parser/Exception.php deleted file mode 100755 index 1e76e3f850..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/Exception.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL - * @version CVS: $Id: Exception.php,v 1.3 2005/11/07 01:52:35 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * We are extending PEAR_Exception - */ -require_once 'PEAR/Exception.php'; - -/** - * XML_Feed_Parser_Exception is a simple extension of PEAR_Exception, existing - * to help with identification of the source of exceptions. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_Exception extends PEAR_Exception -{ - -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS09.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS09.php deleted file mode 100755 index 07f38f911e..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS09.php +++ /dev/null @@ -1,214 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS09.php,v 1.5 2006/07/26 21:18:46 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * This class handles RSS0.9 feeds. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - * @todo Find a Relax NG URI we can use - */ -class XML_Feed_Parser_RSS09 extends XML_Feed_Parser_Type -{ - /** - * The URI of the RelaxNG schema used to (optionally) validate the feed - * @var string - */ - private $relax = ''; - - /** - * We're likely to use XPath, so let's keep it global - * @var DOMXPath - */ - protected $xpath; - - /** - * The feed type we are parsing - * @var string - */ - public $version = 'RSS 0.9'; - - /** - * The class used to represent individual items - * @var string - */ - protected $itemClass = 'XML_Feed_Parser_RSS09Element'; - - /** - * The element containing entries - * @var string - */ - protected $itemElement = 'item'; - - /** - * Here we map those elements we're not going to handle individually - * to the constructs they are. The optional second parameter in the array - * tells the parser whether to 'fall back' (not apt. at the feed level) or - * fail if the element is missing. If the parameter is not set, the function - * will simply return false and leave it to the client to decide what to do. - * @var array - */ - protected $map = array( - 'title' => array('Text'), - 'link' => array('Text'), - 'description' => array('Text'), - 'image' => array('Image'), - 'textinput' => array('TextInput')); - - /** - * Here we map some elements to their atom equivalents. This is going to be - * quite tricky to pull off effectively (and some users' methods may vary) - * but is worth trying. The key is the atom version, the value is RSS2. - * @var array - */ - protected $compatMap = array( - 'title' => array('title'), - 'link' => array('link'), - 'subtitle' => array('description')); - - /** - * We will be working with multiple namespaces and it is useful to - * keep them together - * @var array - */ - protected $namespaces = array( - 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); - - /** - * Our constructor does nothing more than its parent. - * - * @todo RelaxNG validation - * @param DOMDocument $xml A DOM object representing the feed - * @param bool (optional) $string Whether or not to validate this feed - */ - function __construct(DOMDocument $model, $strict = false) - { - $this->model = $model; - - $this->xpath = new DOMXPath($model); - foreach ($this->namespaces as $key => $value) { - $this->xpath->registerNamespace($key, $value); - } - $this->numberEntries = $this->count('item'); - } - - /** - * Included for compatibility -- will not work with RSS 0.9 - * - * This is not something that will work with RSS0.9 as it does not have - * clear restrictions on the global uniqueness of IDs. - * - * @param string $id any valid ID. - * @return false - */ - function getEntryById($id) - { - return false; - } - - /** - * Get details of the image associated with the feed. - * - * @return array|false an array simply containing the child elements - */ - protected function getImage() - { - $images = $this->model->getElementsByTagName('image'); - if ($images->length > 0) { - $image = $images->item(0); - $details = array(); - if ($image->hasChildNodes()) { - $details = array( - 'title' => $image->getElementsByTagName('title')->item(0)->value, - 'link' => $image->getElementsByTagName('link')->item(0)->value, - 'url' => $image->getElementsByTagName('url')->item(0)->value); - } else { - $details = array('title' => false, - 'link' => false, - 'url' => $image->attributes->getNamedItem('resource')->nodeValue); - } - $details = array_merge($details, - array('description' => false, 'height' => false, 'width' => false)); - if (! empty($details)) { - return $details; - } - } - return false; - } - - /** - * The textinput element is little used, but in the interests of - * completeness we will support it. - * - * @return array|false - */ - protected function getTextInput() - { - $inputs = $this->model->getElementsByTagName('textinput'); - if ($inputs->length > 0) { - $input = $inputs->item(0); - $results = array(); - $results['title'] = isset( - $input->getElementsByTagName('title')->item(0)->value) ? - $input->getElementsByTagName('title')->item(0)->value : null; - $results['description'] = isset( - $input->getElementsByTagName('description')->item(0)->value) ? - $input->getElementsByTagName('description')->item(0)->value : null; - $results['name'] = isset( - $input->getElementsByTagName('name')->item(0)->value) ? - $input->getElementsByTagName('name')->item(0)->value : null; - $results['link'] = isset( - $input->getElementsByTagName('link')->item(0)->value) ? - $input->getElementsByTagName('link')->item(0)->value : null; - if (empty($results['link']) && - $input->attributes->getNamedItem('resource')) { - $results['link'] = $input->attributes->getNamedItem('resource')->nodeValue; - } - if (! empty($results)) { - return $results; - } - } - return false; - } - - /** - * Get details of a link from the feed. - * - * In RSS1 a link is a text element but in order to ensure that we resolve - * URLs properly we have a special function for them. - * - * @return string - */ - function getLink($offset = 0, $attribute = 'href', $params = false) - { - $links = $this->model->getElementsByTagName('link'); - if ($links->length <= $offset) { - return false; - } - $link = $links->item($offset); - return $this->addBase($link->nodeValue, $link); - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS09Element.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS09Element.php deleted file mode 100755 index d41f36e8d6..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS09Element.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS09Element.php,v 1.4 2006/06/30 17:41:56 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/* - * This class provides support for RSS 0.9 entries. It will usually be called by - * XML_Feed_Parser_RSS09 with which it shares many methods. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_RSS09Element extends XML_Feed_Parser_RSS09 -{ - /** - * This will be a reference to the parent object for when we want - * to use a 'fallback' rule - * @var XML_Feed_Parser_RSS09 - */ - protected $parent; - - /** - * Our specific element map - * @var array - */ - protected $map = array( - 'title' => array('Text'), - 'link' => array('Link')); - - /** - * Store useful information for later. - * - * @param DOMElement $element - this item as a DOM element - * @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member - */ - function __construct(DOMElement $element, $parent, $xmlBase = '') - { - $this->model = $element; - $this->parent = $parent; - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS1.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS1.php deleted file mode 100755 index 60c9938baa..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS1.php +++ /dev/null @@ -1,277 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS1.php,v 1.10 2006/07/27 13:52:05 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * This class handles RSS1.0 feeds. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - * @todo Find a Relax NG URI we can use - */ -class XML_Feed_Parser_RSS1 extends XML_Feed_Parser_Type -{ - /** - * The URI of the RelaxNG schema used to (optionally) validate the feed - * @var string - */ - private $relax = 'rss10.rnc'; - - /** - * We're likely to use XPath, so let's keep it global - * @var DOMXPath - */ - protected $xpath; - - /** - * The feed type we are parsing - * @var string - */ - public $version = 'RSS 1.0'; - - /** - * The class used to represent individual items - * @var string - */ - protected $itemClass = 'XML_Feed_Parser_RSS1Element'; - - /** - * The element containing entries - * @var string - */ - protected $itemElement = 'item'; - - /** - * Here we map those elements we're not going to handle individually - * to the constructs they are. The optional second parameter in the array - * tells the parser whether to 'fall back' (not apt. at the feed level) or - * fail if the element is missing. If the parameter is not set, the function - * will simply return false and leave it to the client to decide what to do. - * @var array - */ - protected $map = array( - 'title' => array('Text'), - 'link' => array('Text'), - 'description' => array('Text'), - 'image' => array('Image'), - 'textinput' => array('TextInput'), - 'updatePeriod' => array('Text'), - 'updateFrequency' => array('Text'), - 'updateBase' => array('Date'), - 'rights' => array('Text'), # dc:rights - 'description' => array('Text'), # dc:description - 'creator' => array('Text'), # dc:creator - 'publisher' => array('Text'), # dc:publisher - 'contributor' => array('Text'), # dc:contributor - 'date' => array('Date') # dc:contributor - ); - - /** - * Here we map some elements to their atom equivalents. This is going to be - * quite tricky to pull off effectively (and some users' methods may vary) - * but is worth trying. The key is the atom version, the value is RSS2. - * @var array - */ - protected $compatMap = array( - 'title' => array('title'), - 'link' => array('link'), - 'subtitle' => array('description'), - 'author' => array('creator'), - 'updated' => array('date')); - - /** - * We will be working with multiple namespaces and it is useful to - * keep them together - * @var array - */ - protected $namespaces = array( - 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - 'rss' => 'http://purl.org/rss/1.0/', - 'dc' => 'http://purl.org/rss/1.0/modules/dc/', - 'content' => 'http://purl.org/rss/1.0/modules/content/', - 'sy' => 'http://web.resource.org/rss/1.0/modules/syndication/'); - - /** - * Our constructor does nothing more than its parent. - * - * @param DOMDocument $xml A DOM object representing the feed - * @param bool (optional) $string Whether or not to validate this feed - */ - function __construct(DOMDocument $model, $strict = false) - { - $this->model = $model; - if ($strict) { - $validate = $this->model->relaxNGValidate(self::getSchemaDir . - DIRECTORY_SEPARATOR . $this->relax); - if (! $validate) { - throw new XML_Feed_Parser_Exception('Failed required validation'); - } - } - - $this->xpath = new DOMXPath($model); - foreach ($this->namespaces as $key => $value) { - $this->xpath->registerNamespace($key, $value); - } - $this->numberEntries = $this->count('item'); - } - - /** - * Allows retrieval of an entry by ID where the rdf:about attribute is used - * - * This is not really something that will work with RSS1 as it does not have - * clear restrictions on the global uniqueness of IDs. We will employ the - * _very_ hit and miss method of selecting entries based on the rdf:about - * attribute. If DOMXPath::evaluate is available, we also use that to store - * a reference to the entry in the array used by getEntryByOffset so that - * method does not have to seek out the entry if it's requested that way. - * - * @param string $id any valid ID. - * @return XML_Feed_Parser_RSS1Element - */ - function getEntryById($id) - { - if (isset($this->idMappings[$id])) { - return $this->entries[$this->idMappings[$id]]; - } - - $entries = $this->xpath->query("//rss:item[@rdf:about='$id']"); - if ($entries->length > 0) { - $classname = $this->itemClass; - $entry = new $classname($entries->item(0), $this); - if (in_array('evaluate', get_class_methods($this->xpath))) { - $offset = $this->xpath->evaluate("count(preceding-sibling::rss:item)", $entries->item(0)); - $this->entries[$offset] = $entry; - } - $this->idMappings[$id] = $entry; - return $entry; - } - return false; - } - - /** - * Get details of the image associated with the feed. - * - * @return array|false an array simply containing the child elements - */ - protected function getImage() - { - $images = $this->model->getElementsByTagName('image'); - if ($images->length > 0) { - $image = $images->item(0); - $details = array(); - if ($image->hasChildNodes()) { - $details = array( - 'title' => $image->getElementsByTagName('title')->item(0)->value, - 'link' => $image->getElementsByTagName('link')->item(0)->value, - 'url' => $image->getElementsByTagName('url')->item(0)->value); - } else { - $details = array('title' => false, - 'link' => false, - 'url' => $image->attributes->getNamedItem('resource')->nodeValue); - } - $details = array_merge($details, array('description' => false, 'height' => false, 'width' => false)); - if (! empty($details)) { - return $details; - } - } - return false; - } - - /** - * The textinput element is little used, but in the interests of - * completeness we will support it. - * - * @return array|false - */ - protected function getTextInput() - { - $inputs = $this->model->getElementsByTagName('textinput'); - if ($inputs->length > 0) { - $input = $inputs->item(0); - $results = array(); - $results['title'] = isset( - $input->getElementsByTagName('title')->item(0)->value) ? - $input->getElementsByTagName('title')->item(0)->value : null; - $results['description'] = isset( - $input->getElementsByTagName('description')->item(0)->value) ? - $input->getElementsByTagName('description')->item(0)->value : null; - $results['name'] = isset( - $input->getElementsByTagName('name')->item(0)->value) ? - $input->getElementsByTagName('name')->item(0)->value : null; - $results['link'] = isset( - $input->getElementsByTagName('link')->item(0)->value) ? - $input->getElementsByTagName('link')->item(0)->value : null; - if (empty($results['link']) and - $input->attributes->getNamedItem('resource')) { - $results['link'] = - $input->attributes->getNamedItem('resource')->nodeValue; - } - if (! empty($results)) { - return $results; - } - } - return false; - } - - /** - * Employs various techniques to identify the author - * - * Dublin Core provides the dc:creator, dc:contributor, and dc:publisher - * elements for defining authorship in RSS1. We will try each of those in - * turn in order to simulate the atom author element and will return it - * as text. - * - * @return array|false - */ - function getAuthor() - { - $options = array('creator', 'contributor', 'publisher'); - foreach ($options as $element) { - $test = $this->model->getElementsByTagName($element); - if ($test->length > 0) { - return $test->item(0)->value; - } - } - return false; - } - - /** - * Retrieve a link - * - * In RSS1 a link is a text element but in order to ensure that we resolve - * URLs properly we have a special function for them. - * - * @return string - */ - function getLink($offset = 0, $attribute = 'href', $params = false) - { - $links = $this->model->getElementsByTagName('link'); - if ($links->length <= $offset) { - return false; - } - $link = $links->item($offset); - return $this->addBase($link->nodeValue, $link); - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS11.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS11.php deleted file mode 100755 index 3cd1ef15d8..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS11.php +++ /dev/null @@ -1,276 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS11.php,v 1.6 2006/07/27 13:52:05 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * This class handles RSS1.1 feeds. RSS1.1 is documented at: - * http://inamidst.com/rss1.1/ - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - * @todo Support for RDF:List - * @todo Ensure xml:lang is accessible to users - */ -class XML_Feed_Parser_RSS11 extends XML_Feed_Parser_Type -{ - /** - * The URI of the RelaxNG schema used to (optionally) validate the feed - * @var string - */ - private $relax = 'rss11.rnc'; - - /** - * We're likely to use XPath, so let's keep it global - * @var DOMXPath - */ - protected $xpath; - - /** - * The feed type we are parsing - * @var string - */ - public $version = 'RSS 1.0'; - - /** - * The class used to represent individual items - * @var string - */ - protected $itemClass = 'XML_Feed_Parser_RSS1Element'; - - /** - * The element containing entries - * @var string - */ - protected $itemElement = 'item'; - - /** - * Here we map those elements we're not going to handle individually - * to the constructs they are. The optional second parameter in the array - * tells the parser whether to 'fall back' (not apt. at the feed level) or - * fail if the element is missing. If the parameter is not set, the function - * will simply return false and leave it to the client to decide what to do. - * @var array - */ - protected $map = array( - 'title' => array('Text'), - 'link' => array('Text'), - 'description' => array('Text'), - 'image' => array('Image'), - 'updatePeriod' => array('Text'), - 'updateFrequency' => array('Text'), - 'updateBase' => array('Date'), - 'rights' => array('Text'), # dc:rights - 'description' => array('Text'), # dc:description - 'creator' => array('Text'), # dc:creator - 'publisher' => array('Text'), # dc:publisher - 'contributor' => array('Text'), # dc:contributor - 'date' => array('Date') # dc:contributor - ); - - /** - * Here we map some elements to their atom equivalents. This is going to be - * quite tricky to pull off effectively (and some users' methods may vary) - * but is worth trying. The key is the atom version, the value is RSS2. - * @var array - */ - protected $compatMap = array( - 'title' => array('title'), - 'link' => array('link'), - 'subtitle' => array('description'), - 'author' => array('creator'), - 'updated' => array('date')); - - /** - * We will be working with multiple namespaces and it is useful to - * keep them together. We will retain support for some common RSS1.0 modules - * @var array - */ - protected $namespaces = array( - 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - 'rss' => 'http://purl.org/net/rss1.1#', - 'dc' => 'http://purl.org/rss/1.0/modules/dc/', - 'content' => 'http://purl.org/rss/1.0/modules/content/', - 'sy' => 'http://web.resource.org/rss/1.0/modules/syndication/'); - - /** - * Our constructor does nothing more than its parent. - * - * @param DOMDocument $xml A DOM object representing the feed - * @param bool (optional) $string Whether or not to validate this feed - */ - function __construct(DOMDocument $model, $strict = false) - { - $this->model = $model; - - if ($strict) { - $validate = $this->model->relaxNGValidate(self::getSchemaDir . - DIRECTORY_SEPARATOR . $this->relax); - if (! $validate) { - throw new XML_Feed_Parser_Exception('Failed required validation'); - } - } - - $this->xpath = new DOMXPath($model); - foreach ($this->namespaces as $key => $value) { - $this->xpath->registerNamespace($key, $value); - } - $this->numberEntries = $this->count('item'); - } - - /** - * Attempts to identify an element by ID given by the rdf:about attribute - * - * This is not really something that will work with RSS1.1 as it does not have - * clear restrictions on the global uniqueness of IDs. We will employ the - * _very_ hit and miss method of selecting entries based on the rdf:about - * attribute. Please note that this is even more hit and miss with RSS1.1 than - * with RSS1.0 since RSS1.1 does not require the rdf:about attribute for items. - * - * @param string $id any valid ID. - * @return XML_Feed_Parser_RSS1Element - */ - function getEntryById($id) - { - if (isset($this->idMappings[$id])) { - return $this->entries[$this->idMappings[$id]]; - } - - $entries = $this->xpath->query("//rss:item[@rdf:about='$id']"); - if ($entries->length > 0) { - $classname = $this->itemClass; - $entry = new $classname($entries->item(0), $this); - return $entry; - } - return false; - } - - /** - * Get details of the image associated with the feed. - * - * @return array|false an array simply containing the child elements - */ - protected function getImage() - { - $images = $this->model->getElementsByTagName('image'); - if ($images->length > 0) { - $image = $images->item(0); - $details = array(); - if ($image->hasChildNodes()) { - $details = array( - 'title' => $image->getElementsByTagName('title')->item(0)->value, - 'url' => $image->getElementsByTagName('url')->item(0)->value); - if ($image->getElementsByTagName('link')->length > 0) { - $details['link'] = - $image->getElementsByTagName('link')->item(0)->value; - } - } else { - $details = array('title' => false, - 'link' => false, - 'url' => $image->attributes->getNamedItem('resource')->nodeValue); - } - $details = array_merge($details, - array('description' => false, 'height' => false, 'width' => false)); - if (! empty($details)) { - return $details; - } - } - return false; - } - - /** - * The textinput element is little used, but in the interests of - * completeness we will support it. - * - * @return array|false - */ - protected function getTextInput() - { - $inputs = $this->model->getElementsByTagName('textinput'); - if ($inputs->length > 0) { - $input = $inputs->item(0); - $results = array(); - $results['title'] = isset( - $input->getElementsByTagName('title')->item(0)->value) ? - $input->getElementsByTagName('title')->item(0)->value : null; - $results['description'] = isset( - $input->getElementsByTagName('description')->item(0)->value) ? - $input->getElementsByTagName('description')->item(0)->value : null; - $results['name'] = isset( - $input->getElementsByTagName('name')->item(0)->value) ? - $input->getElementsByTagName('name')->item(0)->value : null; - $results['link'] = isset( - $input->getElementsByTagName('link')->item(0)->value) ? - $input->getElementsByTagName('link')->item(0)->value : null; - if (empty($results['link']) and - $input->attributes->getNamedItem('resource')) { - $results['link'] = $input->attributes->getNamedItem('resource')->nodeValue; - } - if (! empty($results)) { - return $results; - } - } - return false; - } - - /** - * Attempts to discern authorship - * - * Dublin Core provides the dc:creator, dc:contributor, and dc:publisher - * elements for defining authorship in RSS1. We will try each of those in - * turn in order to simulate the atom author element and will return it - * as text. - * - * @return array|false - */ - function getAuthor() - { - $options = array('creator', 'contributor', 'publisher'); - foreach ($options as $element) { - $test = $this->model->getElementsByTagName($element); - if ($test->length > 0) { - return $test->item(0)->value; - } - } - return false; - } - - /** - * Retrieve a link - * - * In RSS1 a link is a text element but in order to ensure that we resolve - * URLs properly we have a special function for them. - * - * @return string - */ - function getLink($offset = 0, $attribute = 'href', $params = false) - { - $links = $this->model->getElementsByTagName('link'); - if ($links->length <= $offset) { - return false; - } - $link = $links->item($offset); - return $this->addBase($link->nodeValue, $link); - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS11Element.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS11Element.php deleted file mode 100755 index 75918beda9..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS11Element.php +++ /dev/null @@ -1,151 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS11Element.php,v 1.4 2006/06/30 17:41:56 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/* - * This class provides support for RSS 1.1 entries. It will usually be called by - * XML_Feed_Parser_RSS11 with which it shares many methods. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_RSS11Element extends XML_Feed_Parser_RSS11 -{ - /** - * This will be a reference to the parent object for when we want - * to use a 'fallback' rule - * @var XML_Feed_Parser_RSS1 - */ - protected $parent; - - /** - * Our specific element map - * @var array - */ - protected $map = array( - 'id' => array('Id'), - 'title' => array('Text'), - 'link' => array('Link'), - 'description' => array('Text'), # or dc:description - 'category' => array('Category'), - 'rights' => array('Text'), # dc:rights - 'creator' => array('Text'), # dc:creator - 'publisher' => array('Text'), # dc:publisher - 'contributor' => array('Text'), # dc:contributor - 'date' => array('Date'), # dc:date - 'content' => array('Content') - ); - - /** - * Here we map some elements to their atom equivalents. This is going to be - * quite tricky to pull off effectively (and some users' methods may vary) - * but is worth trying. The key is the atom version, the value is RSS1. - * @var array - */ - protected $compatMap = array( - 'content' => array('content'), - 'updated' => array('lastBuildDate'), - 'published' => array('pubdate'), - 'subtitle' => array('description'), - 'updated' => array('date'), - 'author' => array('creator'), - 'contributor' => array('contributor') - ); - - /** - * Store useful information for later. - * - * @param DOMElement $element - this item as a DOM element - * @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member - */ - function __construct(DOMElement $element, $parent, $xmlBase = '') - { - $this->model = $element; - $this->parent = $parent; - } - - /** - * If an rdf:about attribute is specified, return that as an ID - * - * There is no established way of showing an ID for an RSS1 entry. We will - * simulate it using the rdf:about attribute of the entry element. This cannot - * be relied upon for unique IDs but may prove useful. - * - * @return string|false - */ - function getId() - { - if ($this->model->attributes->getNamedItem('about')) { - return $this->model->attributes->getNamedItem('about')->nodeValue; - } - return false; - } - - /** - * Return the entry's content - * - * The official way to include full content in an RSS1 entry is to use - * the content module's element 'encoded'. Often, however, the 'description' - * element is used instead. We will offer that as a fallback. - * - * @return string|false - */ - function getContent() - { - $options = array('encoded', 'description'); - foreach ($options as $element) { - $test = $this->model->getElementsByTagName($element); - if ($test->length == 0) { - continue; - } - if ($test->item(0)->hasChildNodes()) { - $value = ''; - foreach ($test->item(0)->childNodes as $child) { - if ($child instanceof DOMText) { - $value .= $child->nodeValue; - } else { - $simple = simplexml_import_dom($child); - $value .= $simple->asXML(); - } - } - return $value; - } else if ($test->length > 0) { - return $test->item(0)->nodeValue; - } - } - return false; - } - - /** - * How RSS1.1 should support for enclosures is not clear. For now we will return - * false. - * - * @return false - */ - function getEnclosure() - { - return false; - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS1Element.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS1Element.php deleted file mode 100755 index 8e36d5a9b9..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS1Element.php +++ /dev/null @@ -1,116 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS1Element.php,v 1.6 2006/06/30 17:41:56 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/* - * This class provides support for RSS 1.0 entries. It will usually be called by - * XML_Feed_Parser_RSS1 with which it shares many methods. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_RSS1Element extends XML_Feed_Parser_RSS1 -{ - /** - * This will be a reference to the parent object for when we want - * to use a 'fallback' rule - * @var XML_Feed_Parser_RSS1 - */ - protected $parent; - - /** - * Our specific element map - * @var array - */ - protected $map = array( - 'id' => array('Id'), - 'title' => array('Text'), - 'link' => array('Link'), - 'description' => array('Text'), # or dc:description - 'category' => array('Category'), - 'rights' => array('Text'), # dc:rights - 'creator' => array('Text'), # dc:creator - 'publisher' => array('Text'), # dc:publisher - 'contributor' => array('Text'), # dc:contributor - 'date' => array('Date'), # dc:date - 'content' => array('Content') - ); - - /** - * Here we map some elements to their atom equivalents. This is going to be - * quite tricky to pull off effectively (and some users' methods may vary) - * but is worth trying. The key is the atom version, the value is RSS1. - * @var array - */ - protected $compatMap = array( - 'content' => array('content'), - 'updated' => array('lastBuildDate'), - 'published' => array('pubdate'), - 'subtitle' => array('description'), - 'updated' => array('date'), - 'author' => array('creator'), - 'contributor' => array('contributor') - ); - - /** - * Store useful information for later. - * - * @param DOMElement $element - this item as a DOM element - * @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member - */ - function __construct(DOMElement $element, $parent, $xmlBase = '') - { - $this->model = $element; - $this->parent = $parent; - } - - /** - * If an rdf:about attribute is specified, return it as an ID - * - * There is no established way of showing an ID for an RSS1 entry. We will - * simulate it using the rdf:about attribute of the entry element. This cannot - * be relied upon for unique IDs but may prove useful. - * - * @return string|false - */ - function getId() - { - if ($this->model->attributes->getNamedItem('about')) { - return $this->model->attributes->getNamedItem('about')->nodeValue; - } - return false; - } - - /** - * How RSS1 should support for enclosures is not clear. For now we will return - * false. - * - * @return false - */ - function getEnclosure() - { - return false; - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS2.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS2.php deleted file mode 100644 index 0936bd2f5e..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS2.php +++ /dev/null @@ -1,335 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS2.php,v 1.12 2008/03/08 18:16:45 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * This class handles RSS2 feeds. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_RSS2 extends XML_Feed_Parser_Type -{ - /** - * The URI of the RelaxNG schema used to (optionally) validate the feed - * @var string - */ - private $relax = 'rss20.rnc'; - - /** - * We're likely to use XPath, so let's keep it global - * @var DOMXPath - */ - protected $xpath; - - /** - * The feed type we are parsing - * @var string - */ - public $version = 'RSS 2.0'; - - /** - * The class used to represent individual items - * @var string - */ - protected $itemClass = 'XML_Feed_Parser_RSS2Element'; - - /** - * The element containing entries - * @var string - */ - protected $itemElement = 'item'; - - /** - * Here we map those elements we're not going to handle individually - * to the constructs they are. The optional second parameter in the array - * tells the parser whether to 'fall back' (not apt. at the feed level) or - * fail if the element is missing. If the parameter is not set, the function - * will simply return false and leave it to the client to decide what to do. - * @var array - */ - protected $map = array( - 'ttl' => array('Text'), - 'pubDate' => array('Date'), - 'lastBuildDate' => array('Date'), - 'title' => array('Text'), - 'link' => array('Link'), - 'description' => array('Text'), - 'language' => array('Text'), - 'copyright' => array('Text'), - 'managingEditor' => array('Text'), - 'webMaster' => array('Text'), - 'category' => array('Text'), - 'generator' => array('Text'), - 'docs' => array('Text'), - 'ttl' => array('Text'), - 'image' => array('Image'), - 'skipDays' => array('skipDays'), - 'skipHours' => array('skipHours')); - - /** - * Here we map some elements to their atom equivalents. This is going to be - * quite tricky to pull off effectively (and some users' methods may vary) - * but is worth trying. The key is the atom version, the value is RSS2. - * @var array - */ - protected $compatMap = array( - 'title' => array('title'), - 'rights' => array('copyright'), - 'updated' => array('lastBuildDate'), - 'subtitle' => array('description'), - 'date' => array('pubDate'), - 'author' => array('managingEditor')); - - protected $namespaces = array( - 'dc' => 'http://purl.org/rss/1.0/modules/dc/', - 'content' => 'http://purl.org/rss/1.0/modules/content/'); - - /** - * Our constructor does nothing more than its parent. - * - * @param DOMDocument $xml A DOM object representing the feed - * @param bool (optional) $string Whether or not to validate this feed - */ - function __construct(DOMDocument $model, $strict = false) - { - $this->model = $model; - - if ($strict) { - if (! $this->model->relaxNGValidate($this->relax)) { - throw new XML_Feed_Parser_Exception('Failed required validation'); - } - } - - $this->xpath = new DOMXPath($this->model); - foreach ($this->namespaces as $key => $value) { - $this->xpath->registerNamespace($key, $value); - } - $this->numberEntries = $this->count('item'); - } - - /** - * Retrieves an entry by ID, if the ID is specified with the guid element - * - * This is not really something that will work with RSS2 as it does not have - * clear restrictions on the global uniqueness of IDs. But we can emulate - * it by allowing access based on the 'guid' element. If DOMXPath::evaluate - * is available, we also use that to store a reference to the entry in the array - * used by getEntryByOffset so that method does not have to seek out the entry - * if it's requested that way. - * - * @param string $id any valid ID. - * @return XML_Feed_Parser_RSS2Element - */ - function getEntryById($id) - { - if (isset($this->idMappings[$id])) { - return $this->entries[$this->idMappings[$id]]; - } - - $entries = $this->xpath->query("//item[guid='$id']"); - if ($entries->length > 0) { - $entry = new $this->itemElement($entries->item(0), $this); - if (in_array('evaluate', get_class_methods($this->xpath))) { - $offset = $this->xpath->evaluate("count(preceding-sibling::item)", $entries->item(0)); - $this->entries[$offset] = $entry; - } - $this->idMappings[$id] = $entry; - return $entry; - } - } - - /** - * Get a category from the element - * - * The category element is a simple text construct which can occur any number - * of times. We allow access by offset or access to an array of results. - * - * @param string $call for compatibility with our overloading - * @param array $arguments - arg 0 is the offset, arg 1 is whether to return as array - * @return string|array|false - */ - function getCategory($call, $arguments = array()) - { - $categories = $this->model->getElementsByTagName('category'); - $offset = empty($arguments[0]) ? 0 : $arguments[0]; - $array = empty($arguments[1]) ? false : true; - if ($categories->length <= $offset) { - return false; - } - if ($array) { - $list = array(); - foreach ($categories as $category) { - array_push($list, $category->nodeValue); - } - return $list; - } - return $categories->item($offset)->nodeValue; - } - - /** - * Get details of the image associated with the feed. - * - * @return array|false an array simply containing the child elements - */ - protected function getImage() - { - $images = $this->xpath->query("//image"); - if ($images->length > 0) { - $image = $images->item(0); - $desc = $image->getElementsByTagName('description'); - $description = $desc->length ? $desc->item(0)->nodeValue : false; - $heigh = $image->getElementsByTagName('height'); - $height = $heigh->length ? $heigh->item(0)->nodeValue : false; - $widt = $image->getElementsByTagName('width'); - $width = $widt->length ? $widt->item(0)->nodeValue : false; - return array( - 'title' => $image->getElementsByTagName('title')->item(0)->nodeValue, - 'link' => $image->getElementsByTagName('link')->item(0)->nodeValue, - 'url' => $image->getElementsByTagName('url')->item(0)->nodeValue, - 'description' => $description, - 'height' => $height, - 'width' => $width); - } - return false; - } - - /** - * The textinput element is little used, but in the interests of - * completeness... - * - * @return array|false - */ - function getTextInput() - { - $inputs = $this->model->getElementsByTagName('input'); - if ($inputs->length > 0) { - $input = $inputs->item(0); - return array( - 'title' => $input->getElementsByTagName('title')->item(0)->value, - 'description' => - $input->getElementsByTagName('description')->item(0)->value, - 'name' => $input->getElementsByTagName('name')->item(0)->value, - 'link' => $input->getElementsByTagName('link')->item(0)->value); - } - return false; - } - - /** - * Utility function for getSkipDays and getSkipHours - * - * This is a general function used by both getSkipDays and getSkipHours. It simply - * returns an array of the values of the children of the appropriate tag. - * - * @param string $tagName The tag name (getSkipDays or getSkipHours) - * @return array|false - */ - protected function getSkips($tagName) - { - $hours = $this->model->getElementsByTagName($tagName); - if ($hours->length == 0) { - return false; - } - $skipHours = array(); - foreach($hours->item(0)->childNodes as $hour) { - if ($hour instanceof DOMElement) { - array_push($skipHours, $hour->nodeValue); - } - } - return $skipHours; - } - - /** - * Retrieve skipHours data - * - * The skiphours element provides a list of hours on which this feed should - * not be checked. We return an array of those hours (integers, 24 hour clock) - * - * @return array - */ - function getSkipHours() - { - return $this->getSkips('skipHours'); - } - - /** - * Retrieve skipDays data - * - * The skipdays element provides a list of days on which this feed should - * not be checked. We return an array of those days. - * - * @return array - */ - function getSkipDays() - { - return $this->getSkips('skipDays'); - } - - /** - * Return content of the little-used 'cloud' element - * - * The cloud element is rarely used. It is designed to provide some details - * of a location to update the feed. - * - * @return array an array of the attributes of the element - */ - function getCloud() - { - $cloud = $this->model->getElementsByTagName('cloud'); - if ($cloud->length == 0) { - return false; - } - $cloudData = array(); - foreach ($cloud->item(0)->attributes as $attribute) { - $cloudData[$attribute->name] = $attribute->value; - } - return $cloudData; - } - - /** - * Get link URL - * - * In RSS2 a link is a text element but in order to ensure that we resolve - * URLs properly we have a special function for them. We maintain the - * parameter used by the atom getLink method, though we only use the offset - * parameter. - * - * @param int $offset The position of the link within the feed. Starts from 0 - * @param string $attribute The attribute of the link element required - * @param array $params An array of other parameters. Not used. - * @return string - */ - function getLink($offset, $attribute = 'href', $params = array()) - { - $xPath = new DOMXPath($this->model); - $links = $xPath->query('//link'); - - if ($links->length <= $offset) { - return false; - } - $link = $links->item($offset); - return $this->addBase($link->nodeValue, $link); - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/RSS2Element.php b/plugins/OStatus/extlib/XML/Feed/Parser/RSS2Element.php deleted file mode 100755 index 6edf910dc4..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/RSS2Element.php +++ /dev/null @@ -1,171 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: RSS2Element.php,v 1.11 2006/07/26 21:18:47 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * This class provides support for RSS 2.0 entries. It will usually be - * called by XML_Feed_Parser_RSS2 with which it shares many methods. - * - * @author James Stewart - * @version Release: 1.0.3 - * @package XML_Feed_Parser - */ -class XML_Feed_Parser_RSS2Element extends XML_Feed_Parser_RSS2 -{ - /** - * This will be a reference to the parent object for when we want - * to use a 'fallback' rule - * @var XML_Feed_Parser_RSS2 - */ - protected $parent; - - /** - * Our specific element map - * @var array - */ - protected $map = array( - 'title' => array('Text'), - 'guid' => array('Guid'), - 'description' => array('Text'), - 'author' => array('Text'), - 'comments' => array('Text'), - 'enclosure' => array('Enclosure'), - 'pubDate' => array('Date'), - 'source' => array('Source'), - 'link' => array('Text'), - 'content' => array('Content')); - - /** - * Here we map some elements to their atom equivalents. This is going to be - * quite tricky to pull off effectively (and some users' methods may vary) - * but is worth trying. The key is the atom version, the value is RSS2. - * @var array - */ - protected $compatMap = array( - 'id' => array('guid'), - 'updated' => array('lastBuildDate'), - 'published' => array('pubdate'), - 'guidislink' => array('guid', 'ispermalink'), - 'summary' => array('description')); - - /** - * Store useful information for later. - * - * @param DOMElement $element - this item as a DOM element - * @param XML_Feed_Parser_RSS2 $parent - the feed of which this is a member - */ - function __construct(DOMElement $element, $parent, $xmlBase = '') - { - $this->model = $element; - $this->parent = $parent; - } - - /** - * Get the value of the guid element, if specified - * - * guid is the closest RSS2 has to atom's ID. It is usually but not always a - * URI. The one attribute that RSS2 can posess is 'ispermalink' which specifies - * whether the guid is itself dereferencable. Use of guid is not obligatory, - * but is advisable. To get the guid you would call $item->id() (for atom - * compatibility) or $item->guid(). To check if this guid is a permalink call - * $item->guid("ispermalink"). - * - * @param string $method - the method name being called - * @param array $params - parameters required - * @return string the guid or value of ispermalink - */ - protected function getGuid($method, $params) - { - $attribute = (isset($params[0]) and $params[0] == 'ispermalink') ? - true : false; - $tag = $this->model->getElementsByTagName('guid'); - if ($tag->length > 0) { - if ($attribute) { - if ($tag->hasAttribute("ispermalink")) { - return $tag->getAttribute("ispermalink"); - } - } - return $tag->item(0)->nodeValue; - } - return false; - } - - /** - * Access details of file enclosures - * - * The RSS2 spec is ambiguous as to whether an enclosure element must be - * unique in a given entry. For now we will assume it needn't, and allow - * for an offset. - * - * @param string $method - the method being called - * @param array $parameters - we expect the first of these to be our offset - * @return array|false - */ - protected function getEnclosure($method, $parameters) - { - $encs = $this->model->getElementsByTagName('enclosure'); - $offset = isset($parameters[0]) ? $parameters[0] : 0; - if ($encs->length > $offset) { - try { - if (! $encs->item($offset)->hasAttribute('url')) { - return false; - } - $attrs = $encs->item($offset)->attributes; - return array( - 'url' => $attrs->getNamedItem('url')->value, - 'length' => $attrs->getNamedItem('length')->value, - 'type' => $attrs->getNamedItem('type')->value); - } catch (Exception $e) { - return false; - } - } - return false; - } - - /** - * Get the entry source if specified - * - * source is an optional sub-element of item. Like atom:source it tells - * us about where the entry came from (eg. if it's been copied from another - * feed). It is not a rich source of metadata in the same way as atom:source - * and while it would be good to maintain compatibility by returning an - * XML_Feed_Parser_RSS2 element, it makes a lot more sense to return an array. - * - * @return array|false - */ - protected function getSource() - { - $get = $this->model->getElementsByTagName('source'); - if ($get->length) { - $source = $get->item(0); - $array = array( - 'content' => $source->nodeValue); - foreach ($source->attributes as $attribute) { - $array[$attribute->name] = $attribute->value; - } - return $array; - } - return false; - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/Parser/Type.php b/plugins/OStatus/extlib/XML/Feed/Parser/Type.php deleted file mode 100644 index 75052619bd..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/Parser/Type.php +++ /dev/null @@ -1,467 +0,0 @@ - - * @copyright 2005 James Stewart - * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1 - * @version CVS: $Id: Type.php,v 1.25 2008/03/08 18:39:09 jystewart Exp $ - * @link http://pear.php.net/package/XML_Feed_Parser/ - */ - -/** - * This abstract class provides some general methods that are likely to be - * implemented exactly the same way for all feed types. - * - * @package XML_Feed_Parser - * @author James Stewart - * @version Release: 1.0.3 - */ -abstract class XML_Feed_Parser_Type -{ - /** - * Where we store our DOM object for this feed - * @var DOMDocument - */ - public $model; - - /** - * For iteration we'll want a count of the number of entries - * @var int - */ - public $numberEntries; - - /** - * Where we store our entry objects once instantiated - * @var array - */ - public $entries = array(); - - /** - * Store mappings between entry IDs and their position in the feed - */ - public $idMappings = array(); - - /** - * Proxy to allow use of element names as method names - * - * We are not going to provide methods for every entry type so this - * function will allow for a lot of mapping. We rely pretty heavily - * on this to handle our mappings between other feed types and atom. - * - * @param string $call - the method attempted - * @param array $arguments - arguments to that method - * @return mixed - */ - function __call($call, $arguments = array()) - { - if (! is_array($arguments)) { - $arguments = array(); - } - - if (isset($this->compatMap[$call])) { - $tempMap = $this->compatMap; - $tempcall = array_pop($tempMap[$call]); - if (! empty($tempMap)) { - $arguments = array_merge($arguments, $tempMap[$call]); - } - $call = $tempcall; - } - - /* To be helpful, we allow a case-insensitive search for this method */ - if (! isset($this->map[$call])) { - foreach (array_keys($this->map) as $key) { - if (strtoupper($key) == strtoupper($call)) { - $call = $key; - break; - } - } - } - - if (empty($this->map[$call])) { - return false; - } - - $method = 'get' . $this->map[$call][0]; - if ($method == 'getLink') { - $offset = empty($arguments[0]) ? 0 : $arguments[0]; - $attribute = empty($arguments[1]) ? 'href' : $arguments[1]; - $params = isset($arguments[2]) ? $arguments[2] : array(); - return $this->getLink($offset, $attribute, $params); - } - if (method_exists($this, $method)) { - return $this->$method($call, $arguments); - } - - return false; - } - - /** - * Proxy to allow use of element names as attribute names - * - * For many elements variable-style access will be desirable. This function - * provides for that. - * - * @param string $value - the variable required - * @return mixed - */ - function __get($value) - { - return $this->__call($value, array()); - } - - /** - * Utility function to help us resolve xml:base values - * - * We have other methods which will traverse the DOM and work out the different - * xml:base declarations we need to be aware of. We then need to combine them. - * If a declaration starts with a protocol then we restart the string. If it - * starts with a / then we add on to the domain name. Otherwise we simply tag - * it on to the end. - * - * @param string $base - the base to add the link to - * @param string $link - */ - function combineBases($base, $link) - { - if (preg_match('/^[A-Za-z]+:\/\//', $link)) { - return $link; - } else if (preg_match('/^\//', $link)) { - /* Extract domain and suffix link to that */ - preg_match('/^([A-Za-z]+:\/\/.*)?\/*/', $base, $results); - $firstLayer = $results[0]; - return $firstLayer . "/" . $link; - } else if (preg_match('/^\.\.\//', $base)) { - /* Step up link to find place to be */ - preg_match('/^((\.\.\/)+)(.*)$/', $link, $bases); - $suffix = $bases[3]; - $count = preg_match_all('/\.\.\//', $bases[1], $steps); - $url = explode("/", $base); - for ($i = 0; $i <= $count; $i++) { - array_pop($url); - } - return implode("/", $url) . "/" . $suffix; - } else if (preg_match('/^(?!\/$)/', $base)) { - $base = preg_replace('/(.*\/).*$/', '$1', $base) ; - return $base . $link; - } else { - /* Just stick it on the end */ - return $base . $link; - } - } - - /** - * Determine whether we need to apply our xml:base rules - * - * Gets us the xml:base data and then processes that with regard - * to our current link. - * - * @param string - * @param DOMElement - * @return string - */ - function addBase($link, $element) - { - if (preg_match('/^[A-Za-z]+:\/\//', $link)) { - return $link; - } - - return $this->combineBases($element->baseURI, $link); - } - - /** - * Get an entry by its position in the feed, starting from zero - * - * As well as allowing the items to be iterated over we want to allow - * users to be able to access a specific entry. This is one of two ways of - * doing that, the other being by ID. - * - * @param int $offset - * @return XML_Feed_Parser_RSS1Element - */ - function getEntryByOffset($offset) - { - if (! isset($this->entries[$offset])) { - $entries = $this->model->getElementsByTagName($this->itemElement); - if ($entries->length > $offset) { - $xmlBase = $entries->item($offset)->baseURI; - $this->entries[$offset] = new $this->itemClass( - $entries->item($offset), $this, $xmlBase); - if ($id = $this->entries[$offset]->id) { - $this->idMappings[$id] = $this->entries[$offset]; - } - } else { - throw new XML_Feed_Parser_Exception('No entries found'); - } - } - - return $this->entries[$offset]; - } - - /** - * Return a date in seconds since epoch. - * - * Get a date construct. We use PHP's strtotime to return it as a unix datetime, which - * is the number of seconds since 1970-01-01 00:00:00. - * - * @link http://php.net/strtotime - * @param string $method The name of the date construct we want - * @param array $arguments Included for compatibility with our __call usage - * @return int|false datetime - */ - protected function getDate($method, $arguments) - { - $time = $this->model->getElementsByTagName($method); - if ($time->length == 0 || empty($time->item(0)->nodeValue)) { - return false; - } - return strtotime($time->item(0)->nodeValue); - } - - /** - * Get a text construct. - * - * @param string $method The name of the text construct we want - * @param array $arguments Included for compatibility with our __call usage - * @return string - */ - protected function getText($method, $arguments = array()) - { - $tags = $this->model->getElementsByTagName($method); - if ($tags->length > 0) { - $value = $tags->item(0)->nodeValue; - return $value; - } - return false; - } - - /** - * Apply various rules to retrieve category data. - * - * There is no single way of declaring a category in RSS1/1.1 as there is in RSS2 - * and Atom. Instead the usual approach is to use the dublin core namespace to - * declare categories. For example delicious use both: - * PEAR and: - * - * to declare a categorisation of 'PEAR'. - * - * We need to be sensitive to this where possible. - * - * @param string $call for compatibility with our overloading - * @param array $arguments - arg 0 is the offset, arg 1 is whether to return as array - * @return string|array|false - */ - protected function getCategory($call, $arguments) - { - $categories = $this->model->getElementsByTagName('subject'); - $offset = empty($arguments[0]) ? 0 : $arguments[0]; - $array = empty($arguments[1]) ? false : true; - if ($categories->length <= $offset) { - return false; - } - if ($array) { - $list = array(); - foreach ($categories as $category) { - array_push($list, $category->nodeValue); - } - return $list; - } - return $categories->item($offset)->nodeValue; - } - - /** - * Count occurrences of an element - * - * This function will tell us how many times the element $type - * appears at this level of the feed. - * - * @param string $type the element we want to get a count of - * @return int - */ - protected function count($type) - { - if ($tags = $this->model->getElementsByTagName($type)) { - return $tags->length; - } - return 0; - } - - /** - * Part of our xml:base processing code - * - * We need a couple of methods to access XHTML content stored in feeds. - * This is because we dereference all xml:base references before returning - * the element. This method handles the attributes. - * - * @param DOMElement $node The DOM node we are iterating over - * @return string - */ - function processXHTMLAttributes($node) { - $return = ''; - foreach ($node->attributes as $attribute) { - if ($attribute->name == 'src' or $attribute->name == 'href') { - $attribute->value = $this->addBase(htmlentities($attribute->value, NULL, 'utf-8'), $attribute); - } - if ($attribute->name == 'base') { - continue; - } - $return .= $attribute->name . '="' . htmlentities($attribute->value, NULL, 'utf-8') .'" '; - } - if (! empty($return)) { - return ' ' . trim($return); - } - return ''; - } - - /** - * Convert HTML entities based on the current character set. - * - * @param String - * @return String - */ - function processEntitiesForNodeValue($node) - { - if (function_exists('iconv')) { - $current_encoding = $node->ownerDocument->encoding; - $value = iconv($current_encoding, 'UTF-8', $node->nodeValue); - } else if ($current_encoding == 'iso-8859-1') { - $value = utf8_encode($node->nodeValue); - } else { - $value = $node->nodeValue; - } - - $decoded = html_entity_decode($value, NULL, 'UTF-8'); - return htmlentities($decoded, NULL, 'UTF-8'); - } - - /** - * Part of our xml:base processing code - * - * We need a couple of methods to access XHTML content stored in feeds. - * This is because we dereference all xml:base references before returning - * the element. This method recurs through the tree descending from the node - * and builds our string. - * - * @param DOMElement $node The DOM node we are processing - * @return string - */ - function traverseNode($node) - { - $content = ''; - - /* Add the opening of this node to the content */ - if ($node instanceof DOMElement) { - $content .= '<' . $node->tagName . - $this->processXHTMLAttributes($node) . '>'; - } - - /* Process children */ - if ($node->hasChildNodes()) { - foreach ($node->childNodes as $child) { - $content .= $this->traverseNode($child); - } - } - - if ($node instanceof DOMText) { - $content .= $this->processEntitiesForNodeValue($node); - } - - /* Add the closing of this node to the content */ - if ($node instanceof DOMElement) { - $content .= 'tagName . '>'; - } - - return $content; - } - - /** - * Get content from RSS feeds (atom has its own implementation) - * - * The official way to include full content in an RSS1 entry is to use - * the content module's element 'encoded', and RSS2 feeds often duplicate that. - * Often, however, the 'description' element is used instead. We will offer that - * as a fallback. Atom uses its own approach and overrides this method. - * - * @return string|false - */ - protected function getContent() - { - $options = array('encoded', 'description'); - foreach ($options as $element) { - $test = $this->model->getElementsByTagName($element); - if ($test->length == 0) { - continue; - } - if ($test->item(0)->hasChildNodes()) { - $value = ''; - foreach ($test->item(0)->childNodes as $child) { - if ($child instanceof DOMText) { - $value .= $child->nodeValue; - } else { - $simple = simplexml_import_dom($child); - $value .= $simple->asXML(); - } - } - return $value; - } else if ($test->length > 0) { - return $test->item(0)->nodeValue; - } - } - return false; - } - - /** - * Checks if this element has a particular child element. - * - * @param String - * @param Integer - * @return bool - **/ - function hasKey($name, $offset = 0) - { - $search = $this->model->getElementsByTagName($name); - return $search->length > $offset; - } - - /** - * Return an XML serialization of the feed, should it be required. Most - * users however, will already have a serialization that they used when - * instantiating the object. - * - * @return string XML serialization of element - */ - function __toString() - { - $simple = simplexml_import_dom($this->model); - return $simple->asXML(); - } - - /** - * Get directory holding RNG schemas. Method is based on that - * found in Contact_AddressBook. - * - * @return string PEAR data directory. - * @access public - * @static - */ - static function getSchemaDir() - { - require_once 'PEAR/Config.php'; - $config = new PEAR_Config; - return $config->get('data_dir') . '/XML_Feed_Parser/schemas'; - } -} - -?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/atom10-entryonly.xml b/plugins/OStatus/extlib/XML/Feed/samples/atom10-entryonly.xml deleted file mode 100755 index 02e1c58002..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/atom10-entryonly.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - Atom draft-07 snapshot - - - tag:example.org,2003:3.2397 - 2005-07-10T12:29:29Z - 2003-12-13T08:29:29-04:00 - - Mark Pilgrim - http://example.org/ - f8dy@example.com - - - Sam Ruby - - - Joe Gregorio - - -
    -

    [Update: The Atom draft is finished.]

    -
    -
    -
    \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/atom10-example1.xml b/plugins/OStatus/extlib/XML/Feed/samples/atom10-example1.xml deleted file mode 100755 index d181d2b6f8..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/atom10-example1.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - Example Feed - - 2003-12-13T18:30:02Z - - John Doe - - urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 - - - Atom-Powered Robots Run Amok - - urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a - 2003-12-13T18:30:02Z - Some text. - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/atom10-example2.xml b/plugins/OStatus/extlib/XML/Feed/samples/atom10-example2.xml deleted file mode 100755 index 98abf9d54f..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/atom10-example2.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - dive into mark - - A <em>lot</em> of effort - went into making this effortless - - 2005-07-31T12:29:29Z - tag:example.org,2003:3 - - - Copyright (c) 2003, Mark Pilgrim - - Example Toolkit - - - Atom draft-07 snapshot - - - tag:example.org,2003:3.2397 - 2005-07-31T12:29:29Z - 2003-12-13T08:29:29-04:00 - - Mark Pilgrim - http://example.org/ - f8dy@example.com - - - Sam Ruby - - - Joe Gregorio - - -
    -

    [Update: The Atom draft is finished.]

    -
    -
    -
    -
    \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/delicious.feed b/plugins/OStatus/extlib/XML/Feed/samples/delicious.feed deleted file mode 100755 index 32f9fa4935..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/delicious.feed +++ /dev/null @@ -1,177 +0,0 @@ - - - - -del.icio.us/tag/greenbelt -http://del.icio.us/tag/greenbelt -Text - - - - - - - - - - - - - - - - -Greenbelt - Homepage Section -http://www.greenbelt.org.uk/ -jonnybaker -2005-05-16T16:30:38Z -greenbelt - - - - - - - - -Greenbelt festival (uk) -http://www.greenbelt.org.uk/ -sssshhhh -2005-05-14T18:19:40Z -audiology festival gigs greenbelt - - - - - - - - - - - -Natuerlichwien.at - Rundumadum -http://www.natuerlichwien.at/rundumadum/dergruenguertel/ -egmilman47 -2005-05-06T21:33:41Z -Austria Vienna Wien greenbelt nature walking - - - - - - - - - - - - - -Tank - GBMediaWiki -http://www.flickerweb.co.uk/wiki/index.php/Tank#Seminars -jystewart -2005-03-21T22:44:11Z -greenbelt - - - - - - - - -Greenbelt homepage -http://www.greenbelt.ca/home.htm -Gooberoo -2005-03-01T22:43:17Z -greenbelt ontario - - - - - - - - - -Pip Wilson bhp ...... blog -http://pipwilsonbhp.blogspot.com/ -sssshhhh -2004-12-27T11:20:51Z -Greenbelt friend ideas links thinking weblog - - - - - - - - - - - - - -maggi dawn -http://maggidawn.typepad.com/maggidawn/ -sssshhhh -2004-12-27T11:20:11Z -Greenbelt ideas links thinking weblog - - - - - - - - - - - - -John Davies -http://www.johndavies.org/ -sssshhhh -2004-12-27T11:18:37Z -Greenbelt ideas links thinking weblog - - - - - - - - - - - - -jonnybaker -http://jonnybaker.blogs.com/ -sssshhhh -2004-12-27T11:18:17Z -Greenbelt event ideas links resources thinking weblog youth - - - - - - - - - - - - - - - diff --git a/plugins/OStatus/extlib/XML/Feed/samples/flickr.feed b/plugins/OStatus/extlib/XML/Feed/samples/flickr.feed deleted file mode 100755 index 57e83af572..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/flickr.feed +++ /dev/null @@ -1,184 +0,0 @@ - - - - jamesstewart - Everyone's Tagged Photos - - - A feed of jamesstewart - Everyone's Tagged Photos - 2005-08-01T18:50:26Z - Flickr - - - Oma and James - - - tag:flickr.com,2004:/photo/30367516 - 2005-08-01T18:50:26Z - 2005-08-01T18:50:26Z - <p><a href="http://www.flickr.com/people/30484029@N00/">kstewart</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/30484029@N00/30367516/" title="Oma and James"><img src="http://photos23.flickr.com/30367516_1f685a16e8_m.jpg" width="240" height="180" alt="Oma and James" style="border: 1px solid #000000;" /></a></p> - -<p>I have a beautiful Oma and a gorgeous husband.</p> - - kstewart - http://www.flickr.com/people/30484029@N00/ - - jamesstewart oma stoelfamily - - - - - tag:flickr.com,2004:/photo/21376174 - 2005-06-25T02:00:35Z - 2005-06-25T02:00:35Z - <p><a href="http://www.flickr.com/people/buddscreek/">Lan Rover</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/buddscreek/21376174/" title=""><img src="http://photos17.flickr.com/21376174_4314fd8d5c_m.jpg" width="240" height="160" alt="" style="border: 1px solid #000000;" /></a></p> - -<p>AMA Motocross Championship 2005, Budds Creek, Maryland</p> - - Lan Rover - http://www.flickr.com/people/buddscreek/ - - amamotocrosschampionship buddscreek maryland 2005 fathersday motocrossnational rickycarmichael 259 jamesstewart 4 - - - - - tag:flickr.com,2004:/photo/21375650 - 2005-06-25T01:56:24Z - 2005-06-25T01:56:24Z - <p><a href="http://www.flickr.com/people/buddscreek/">Lan Rover</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/buddscreek/21375650/" title=""><img src="http://photos16.flickr.com/21375650_5c60e0dab1_m.jpg" width="240" height="160" alt="" style="border: 1px solid #000000;" /></a></p> - - - - Lan Rover - http://www.flickr.com/people/buddscreek/ - - amamotocrosschampionship buddscreek maryland 2005 fathersday motocrossnational 259 jamesstewart - - - - - tag:flickr.com,2004:/photo/21375345 - 2005-06-25T01:54:11Z - 2005-06-25T01:54:11Z - <p><a href="http://www.flickr.com/people/buddscreek/">Lan Rover</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/buddscreek/21375345/" title=""><img src="http://photos15.flickr.com/21375345_4205fdd22b_m.jpg" width="160" height="240" alt="" style="border: 1px solid #000000;" /></a></p> - - - - Lan Rover - http://www.flickr.com/people/buddscreek/ - - amamotocrosschampionship buddscreek maryland 2005 fathersday motocrossnational 259 jamesstewart - - - Lunch with Kari & James, café in the crypt of St Martin in the fields - - tag:flickr.com,2004:/photo/16516618 - 2005-05-30T21:56:39Z - 2005-05-30T21:56:39Z - <p><a href="http://www.flickr.com/people/fidothe/">fidothe</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/fidothe/16516618/" title="Lunch with Kari &amp; James, café in the crypt of St Martin in the fields"><img src="http://photos14.flickr.com/16516618_afaa4a395e_m.jpg" width="240" height="180" alt="Lunch with Kari &amp; James, café in the crypt of St Martin in the fields" style="border: 1px solid #000000;" /></a></p> - - - - fidothe - http://www.flickr.com/people/fidothe/ - - nokia7610 london stmartininthefields clarepatterson jamesstewart parvinstewart jimstewart susanstewart - - - Stewart keeping it low over the obstacle. - - tag:flickr.com,2004:/photo/10224728 - 2005-04-21T07:30:29Z - 2005-04-21T07:30:29Z - <p><a href="http://www.flickr.com/people/pqbon/">pqbon</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/pqbon/10224728/" title="Stewart keeping it low over the obstacle."><img src="http://photos7.flickr.com/10224728_b756341957_m.jpg" width="240" height="180" alt="Stewart keeping it low over the obstacle." style="border: 1px solid #000000;" /></a></p> - - - - pqbon - http://www.flickr.com/people/pqbon/ - - ama hangtown motocross jamesstewart bubba - - - king james stewart - - tag:flickr.com,2004:/photo/7152910 - 2005-03-22T21:53:37Z - 2005-03-22T21:53:37Z - <p><a href="http://www.flickr.com/people/jjlook/">jj look</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/jjlook/7152910/" title="king james stewart"><img src="http://photos7.flickr.com/7152910_a02ab5a750_m.jpg" width="180" height="240" alt="king james stewart" style="border: 1px solid #000000;" /></a></p> - -<p>11th</p> - - jj look - http://www.flickr.com/people/jjlook/ - - dilomar05 eastside austin texas 78702 kingjames stewart jamesstewart borrowed - - - It's a Grind, downtown Grand Rapids (James, Susan, Jim, Harv, Lawson) - - tag:flickr.com,2004:/photo/1586562 - 2004-11-20T09:34:28Z - 2004-11-20T09:34:28Z - <p><a href="http://www.flickr.com/people/fidothe/">fidothe</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/fidothe/1586562/" title="It's a Grind, downtown Grand Rapids (James, Susan, Jim, Harv, Lawson)"><img src="http://photos2.flickr.com/1586562_0bc5313a3e_m.jpg" width="240" height="180" alt="It's a Grind, downtown Grand Rapids (James, Susan, Jim, Harv, Lawson)" style="border: 1px solid #000000;" /></a></p> - - - - fidothe - http://www.flickr.com/people/fidothe/ - - holiday grandrapids jamesstewart - - - It's a Grind, downtown Grand Rapids (James, Susan, Jim, Harv, Lawson) - - tag:flickr.com,2004:/photo/1586539 - 2004-11-20T09:28:16Z - 2004-11-20T09:28:16Z - <p><a href="http://www.flickr.com/people/fidothe/">fidothe</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/fidothe/1586539/" title="It's a Grind, downtown Grand Rapids (James, Susan, Jim, Harv, Lawson)"><img src="http://photos2.flickr.com/1586539_c51e5f2e7a_m.jpg" width="240" height="180" alt="It's a Grind, downtown Grand Rapids (James, Susan, Jim, Harv, Lawson)" style="border: 1px solid #000000;" /></a></p> - - - - fidothe - http://www.flickr.com/people/fidothe/ - - holiday grandrapids jamesstewart - - - It's a Grind, James and Jim can't decide) - - tag:flickr.com,2004:/photo/1586514 - 2004-11-20T09:25:05Z - 2004-11-20T09:25:05Z - <p><a href="http://www.flickr.com/people/fidothe/">fidothe</a> posted a photo:</p> - -<p><a href="http://www.flickr.com/photos/fidothe/1586514/" title="It's a Grind, James and Jim can't decide)"><img src="http://photos2.flickr.com/1586514_733c2dfa3e_m.jpg" width="240" height="180" alt="It's a Grind, James and Jim can't decide)" style="border: 1px solid #000000;" /></a></p> - - - - fidothe - http://www.flickr.com/people/fidothe/ - - holiday grandrapids jamesstewart johnkentish - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/grwifi-atom.xml b/plugins/OStatus/extlib/XML/Feed/samples/grwifi-atom.xml deleted file mode 100755 index c351d3c164..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/grwifi-atom.xml +++ /dev/null @@ -1,7 +0,0 @@ - Updates to Grand Rapids WiFi hotspot details 2005-09-01T15:43:01-05:00 WiFi Hotspots in Grand Rapids, MI http://grwifi.net/atom/locations Creative Commons Attribution-NonCommercial-ShareAlike 2.0 http://creativecommons.org/licenses/by-nc-sa/2.0/ Hotspot Details Updated: Sweetwaters http://grwifi.net/location/sweetwaters 2005-09-01T15:43:01-05:00 The details of the WiFi hotspot at: Sweetwaters have been updated. Find out more at: -http://grwifi.net/location/sweetwaters James http://jystewart.net james@jystewart.net wifi hotspot Hotspot Details Updated: Common Ground Coffee Shop http://grwifi.net/location/common-ground 2005-09-01T15:42:39-05:00 The details of the WiFi hotspot at: Common Ground Coffee Shop have been updated. Find out more at: -http://grwifi.net/location/common-ground James http://jystewart.net james@jystewart.net wifi hotspot Hotspot Details Updated: Grand Rapids Public Library, Main Branch http://grwifi.net/location/grpl-main-branch 2005-09-01T15:42:20-05:00 The details of the WiFi hotspot at: Grand Rapids Public Library, Main Branch have been updated. Find out more at: -http://grwifi.net/location/grpl-main-branch James http://jystewart.net james@jystewart.net wifi hotspot Hotspot Details Updated: Four Friends Coffee House http://grwifi.net/location/four-friends 2005-09-01T15:41:35-05:00 The details of the WiFi hotspot at: Four Friends Coffee House have been updated. Find out more at: -http://grwifi.net/location/four-friends James http://jystewart.net james@jystewart.net wifi hotspot Hotspot Details Updated: Barnes and Noble, Rivertown Crossings http://grwifi.net/location/barnes-noble-rivertown 2005-09-01T15:40:41-05:00 The details of the WiFi hotspot at: Barnes and Noble, Rivertown Crossings have been updated. Find out more at: -http://grwifi.net/location/barnes-noble-rivertown James http://jystewart.net james@jystewart.net wifi hotspot Hotspot Details Updated: The Boss Sports Bar & Grille http://grwifi.net/location/boss-sports-bar 2005-09-01T15:40:19-05:00 The details of the WiFi hotspot at: The Boss Sports Bar & Grille have been updated. Find out more at: -http://grwifi.net/location/boss-sports-bar James http://jystewart.net james@jystewart.net wifi hotspot \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/hoder.xml b/plugins/OStatus/extlib/XML/Feed/samples/hoder.xml deleted file mode 100755 index 0994635707..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/hoder.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - -Editor: Myself (Persian) -http://editormyself.info -This is a Persian (Farsi) weblog, written by Hossein Derakhshan (aka, Hoder), an Iranian Multimedia designer and a journalist who lives in Toronto since Dec 2000. He also keeps an English weblog with the same name. -en-us -hoder@hotmail.com -2005-10-12T19:45:32-05:00 - -hourly -1 -2000-01-01T12:00+00:00 - - - -لينکدونی‌ | جلسه‌ی امریکن انترپرایز برای تقسیم قومی ایران -http://www.aei.org/events/type.upcoming,eventID.1166,filter.all/event_detail.asp -چطور بعضی‌ها فکر می‌کنند دست راستی‌های آمریکا از خامنه‌ای ملی‌گراترند -14645@http://i.hoder.com/ -iran -2005-10-12T19:45:32-05:00 - - - -لينکدونی‌ | به صبحانه آگهی بدهید -http://www.adbrite.com/mb/commerce/purchase_form.php?opid=24346&afsid=1 -خیلی ارزان و راحت است -14644@http://i.hoder.com/ -media/journalism -2005-10-12T17:23:15-05:00 - - - -لينکدونی‌ | نیروی انتظامی چگونه تابوهای هم‌جنس‌گرایانه را می‌شکند؛ فرنگوپولیس -http://farangeopolis.blogspot.com/2005/10/blog-post_08.html -از پس و پیش و حاشیه‌ی این ماجرا می‌توان یک مستند بی‌نظیر ساخت -14643@http://i.hoder.com/ -soc_popculture -2005-10-12T17:06:40-05:00 - - - -لينکدونی‌ | بازتاب توقیف شد -http://www.baztab.com/news/30201.php -اگر گفتید یک وب‌سایت را چطور توقیف می‌کنند؟ لابد ماوس‌شان را قایم می‌کنند. -14642@http://i.hoder.com/ -media/journalism -2005-10-12T14:41:57-05:00 - - - -لينکدونی‌ | رشد وب در سال 2005 از همیشه بیشتر بوده است" بی.بی.سی -http://news.bbc.co.uk/2/hi/technology/4325918.stm - -14640@http://i.hoder.com/ -tech -2005-10-12T13:04:46-05:00 - - - - - -==قرعه کشی گرین کارد به زودی شروع می‌شود== -http://nice.newsxphotos.biz/05/09/2007_dv_lottery_registration_to_begin_oct_5_14589.php - -14613@http://vagrantly.com -ads03 -2005-09-27T04:49:22-05:00 - - - - - - - - -پروژه‌ی هاروارد، قدم دوم -http://editormyself.info/archives/2005/10/051012_014641.shtml -اگر یادتان باشد چند وقت پیش نوشتم که دانشگاه هاروارد پروژه‌ای دارد با نام آواهای جهانی که در آن به وبلاگ‌های غیر انگلیسی‌زبان می‌پردازد. خواشتم که اگر کسی علاقه دارد ایمیل بزند. تعداد زیادی جواب دادند و ابراز علاقه کردند. حالا وقت قدم دوم است.

    - -

    قدم دوم این است که برای اینکه مسوولین پروژه بتوانند تصمیم بگیرند که با چه کسی کار کنند، می‌خواهند نمونه‌ی کارهای علاقمندان مشارکت در این پرزو‌ه را ببینند.

    - -

    برای همین از همه‌ی علاقماندان، حتی کسانی که قبلا اعلام آمادگی نکرده بودند، می‌‌خواهم که یک موضوع رایج این روزهای وبلاگستان فارسی را انتخاب کنند و در هفتصد کلمه، به انگلیسی، بنویسند که وبلاگ‌دارهای درباره‌اش چه می‌گویند. لینک به پنج، شش وبلاگ و بازنویسی آنچه آنها از جنبه‌های گوناگون درباره‌ی آن موضوع نوشته‌اند با نقل قول مستقیم از آنها (البته ترجمه شده از فارسی) کافی است. دو سه جمله هم اول کار توضیح دهید که چرا این موضوع مهم است.

    - -

    متن نمونه را به آدرس ایمیل من hoder@hoder.com و نیز برای افراد زیر تا روز دوشنبه بفرستید:
    -ربکا : rmackinnon@cyber.law.harvard.edu
    -هیثم: haitham.sabbah@gmail.com

    ]]>
    -14641@http://editormyself.info -weblog -2005-10-12T14:04:23-05:00 -
    - - - -
    -
    \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/illformed_atom10.xml b/plugins/OStatus/extlib/XML/Feed/samples/illformed_atom10.xml deleted file mode 100755 index 612186897d..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/illformed_atom10.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Example author - me@example.com - http://example.com/ - - - - - - -Copyright 1997-1999 UserLand Software, Inc. -Thu, 08 Jul 1999 07:00:00 GMT -Thu, 08 Jul 1999 16:20:26 GMT -http://my.userland.com/stories/storyReader$11 -News and commentary from the cross-platform scripting community. -http://www.scripting.com/ -Scripting News - -http://www.scripting.com/ -Scripting News -http://www.scripting.com/gifs/tinyScriptingNews.gif -40 -78 -What is this used for? - -dave@userland.com (Dave Winer) -dave@userland.com (Dave Winer) -en-us - -6 -7 -8 -9 -10 -11 - - -Sunday - -(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0)) - -stuff -http://bar -This is an article about some stuff - - -Search Now! -Enter your search <terms> -find -http://my.site.com/search.cgi - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/rss091-international.xml b/plugins/OStatus/extlib/XML/Feed/samples/rss091-international.xml deleted file mode 100755 index cfe91691f4..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/rss091-international.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - -膮ŸÛë´é´Ì´×´è´ŒÁ¹´Õ -http://www.mozilla.org -膮ŸÛë´é´Ì´×´è´ŒÁ¹´Õ -ja - -NYÒ™Á¢¸»ÌêÛì15285.25´ƒ´‘Á£´Û´—´ÀÁ¹´ê´Ì´éÒ™Ûì¡êçÒÕ‰ÌêÁ£ -http://www.mozilla.org/status/ -This is an item description... - - -‚§±Çç¡ËßÛÂҏéøÓ¸Á£Ë²®Ÿè†Ûè危ÇÌ’¡Íæ—éøë‡Á£ -http://www.mozilla.org/status/ -This is an item description... - - -ËÜË”ïÌëÈšÁ¢È†Ë§æàÀ豎ˉۂÁ¢Ë‚åܼšÛ˜íËüËÁ£ -http://www.mozilla.org/status/ -This is an item description... - - -2000‚øíŠåÁ¢«‘¦éÛ빏ېçéÛ§ÛÂè†ÒæÓ¸Á£Ì¾«…æ—ÕÝéøƒ¸Á£ -http://www.mozilla.org/status/ -This is an item description... - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/rss091-simple.xml b/plugins/OStatus/extlib/XML/Feed/samples/rss091-simple.xml deleted file mode 100755 index f0964a2278..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/rss091-simple.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - -en -News and commentary from the cross-platform scripting community. -http://www.scripting.com/ -Scripting News - -http://www.scripting.com/ -Scripting News -http://www.scripting.com/gifs/tinyScriptingNews.gif - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/rss092-sample.xml b/plugins/OStatus/extlib/XML/Feed/samples/rss092-sample.xml deleted file mode 100755 index 5d75c352bd..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/rss092-sample.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Dave Winer: Grateful Dead - http://www.scripting.com/blog/categories/gratefulDead.html - A high-fidelity Grateful Dead song every day. This is where we're experimenting with enclosures on RSS news items that download when you're not using your computer. If it works (it will) it will be the end of the Click-And-Wait multimedia experience on the Internet. - Fri, 13 Apr 2001 19:23:02 GMT - http://backend.userland.com/rss092 - dave@userland.com (Dave Winer) - dave@userland.com (Dave Winer) - - - It's been a few days since I added a song to the Grateful Dead channel. Now that there are all these new Radio users, many of whom are tuned into this channel (it's #16 on the hotlist of upstreaming Radio users, there's no way of knowing how many non-upstreaming users are subscribing, have to do something about this..). Anyway, tonight's song is a live version of Weather Report Suite from Dick's Picks Volume 7. It's wistful music. Of course a beautiful song, oft-quoted here on Scripting News. <i>A little change, the wind and rain.</i> - - - - - Kevin Drennan started a <a href="http://deadend.editthispage.com/">Grateful Dead Weblog</a>. Hey it's cool, he even has a <a href="http://deadend.editthispage.com/directory/61">directory</a>. <i>A Frontier 7 feature.</i> - Scripting News - - - <a href="http://arts.ucsc.edu/GDead/AGDL/other1.html">The Other One</a>, live instrumental, One From The Vault. Very rhythmic very spacy, you can listen to it many times, and enjoy something new every time. - - - - This is a test of a change I just made. Still diggin.. - - - The HTML rendering almost <a href="http://validator.w3.org/check/referer">validates</a>. Close. Hey I wonder if anyone has ever published a style guide for ALT attributes on images? What are you supposed to say in the ALT attribute? I sure don't know. If you're blind send me an email if u cn rd ths. - - - <a href="http://www.cs.cmu.edu/~mleone/gdead/dead-lyrics/Franklin's_Tower.txt">Franklin's Tower</a>, a live version from One From The Vault. - - - - Moshe Weitzman says Shakedown Street is what I'm lookin for for tonight. I'm listening right now. It's one of my favorites. "Don't tell me this town ain't got no heart." Too bright. I like the jazziness of Weather Report Suite. Dreamy and soft. How about The Other One? "Spanish lady come to me.." - Scripting News - - - <a href="http://www.scripting.com/mp3s/youWinAgain.mp3">The news is out</a>, all over town..<p> -You've been seen, out runnin round. <p> -The lyrics are <a href="http://www.cs.cmu.edu/~mleone/gdead/dead-lyrics/You_Win_Again.txt">here</a>, short and sweet. <p> -<i>You win again!</i> - - - - - <a href="http://www.getlyrics.com/lyrics/grateful-dead/wake-of-the-flood/07.htm">Weather Report Suite</a>: "Winter rain, now tell me why, summers fade, and roses die? The answer came. The wind and rain. Golden hills, now veiled in grey, summer leaves have blown away. Now what remains? The wind and rain." - - - - <a href="http://arts.ucsc.edu/gdead/agdl/darkstar.html">Dark Star</a> crashes, pouring its light into ashes. - - - - DaveNet: <a href="http://davenet.userland.com/2001/01/21/theUsBlues">The U.S. Blues</a>. - - - Still listening to the US Blues. <i>"Wave that flag, wave it wide and high.."</i> Mistake made in the 60s. We gave our country to the assholes. Ah ah. Let's take it back. Hey I'm still a hippie. <i>"You could call this song The United States Blues."</i> - - - <a href="http://www.sixties.com/html/garcia_stack_0.html"><img src="http://www.scripting.com/images/captainTripsSmall.gif" height="51" width="42" border="0" hspace="10" vspace="10" align="right"></a>In celebration of today's inauguration, after hearing all those great patriotic songs, America the Beautiful, even The Star Spangled Banner made my eyes mist up. It made my choice of Grateful Dead song of the night realllly easy. Here are the <a href="http://searchlyrics2.homestead.com/gd_usblues.html">lyrics</a>. Click on the audio icon to the left to give it a listen. "Red and white, blue suede shoes, I'm Uncle Sam, how do you do?" It's a different kind of patriotic music, but man I love my country and I love Jerry and the band. <i>I truly do!</i> - - - - Grateful Dead: "Tennessee, Tennessee, ain't no place I'd rather be." - - - - Ed Cone: "Had a nice Deadhead experience with my wife, who never was one but gets the vibe and knows and likes a lot of the music. Somehow she made it to the age of 40 without ever hearing Wharf Rat. We drove to Jersey and back over Christmas with the live album commonly known as Skull and Roses in the CD player much of the way, and it was cool to see her discover one the band's finest moments. That song is unique and underappreciated. Fun to hear that disc again after a few years off -- you get Jerry as blues-guitar hero on Big Railroad Blues and a nice version of Bertha." - - - - <a href="http://arts.ucsc.edu/GDead/AGDL/fotd.html">Tonight's Song</a>: "If I get home before daylight I just might get some sleep tonight." - - - - <a href="http://arts.ucsc.edu/GDead/AGDL/uncle.html">Tonight's song</a>: "Come hear Uncle John's Band by the river side. Got some things to talk about here beside the rising tide." - - - - <a href="http://www.cs.cmu.edu/~mleone/gdead/dead-lyrics/Me_and_My_Uncle.txt">Me and My Uncle</a>: "I loved my uncle, God rest his soul, taught me good, Lord, taught me all I know. Taught me so well, I grabbed that gold and I left his dead ass there by the side of the road." - - - - - Truckin, like the doo-dah man, once told me gotta play your hand. Sometimes the cards ain't worth a dime, if you don't lay em down. - - - - Two-Way-Web: <a href="http://www.thetwowayweb.com/payloadsForRss">Payloads for RSS</a>. "When I started talking with Adam late last year, he wanted me to think about high quality video on the Internet, and I totally didn't want to hear about it." - - - A touch of gray, kinda suits you anyway.. - - - - <a href="http://www.sixties.com/html/garcia_stack_0.html"><img src="http://www.scripting.com/images/captainTripsSmall.gif" height="51" width="42" border="0" hspace="10" vspace="10" align="right"></a>In celebration of today's inauguration, after hearing all those great patriotic songs, America the Beautiful, even The Star Spangled Banner made my eyes mist up. It made my choice of Grateful Dead song of the night realllly easy. Here are the <a href="http://searchlyrics2.homestead.com/gd_usblues.html">lyrics</a>. Click on the audio icon to the left to give it a listen. "Red and white, blue suede shoes, I'm Uncle Sam, how do you do?" It's a different kind of patriotic music, but man I love my country and I love Jerry and the band. <i>I truly do!</i> - - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/rss10-example1.xml b/plugins/OStatus/extlib/XML/Feed/samples/rss10-example1.xml deleted file mode 100755 index 0edecf58e9..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/rss10-example1.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - XML.com - http://xml.com/pub - - XML.com features a rich mix of information and services - for the XML community. - - - - - - - - - - - - - - - - - XML.com - http://www.xml.com - http://xml.com/universal/images/xml_tiny.gif - - - - Processing Inclusions with XSLT - http://xml.com/pub/2000/08/09/xslt/xslt.html - - Processing document inclusions with general XML tools can be - problematic. This article proposes a way of preserving inclusion - information through SAX-based processing. - - - - - Putting RDF to Work - http://xml.com/pub/2000/08/09/rdfdb/index.html - - Tool and API support for the Resource Description Framework - is slowly coming of age. Edd Dumbill takes a look at RDFDB, - one of the most exciting new RDF toolkits. - - - - - Search XML.com - Search XML.com's XML collection - s - http://search.xml.com - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/rss10-example2.xml b/plugins/OStatus/extlib/XML/Feed/samples/rss10-example2.xml deleted file mode 100755 index 26235f78ff..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/rss10-example2.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - Meerkat - http://meerkat.oreillynet.com - Meerkat: An Open Wire Service - The O'Reilly Network - Rael Dornfest (mailto:rael@oreilly.com) - Copyright © 2000 O'Reilly & Associates, Inc. - 2000-01-01T12:00+00:00 - hourly - 2 - 2000-01-01T12:00+00:00 - - - - - - - - - - - - - - - Meerkat Powered! - http://meerkat.oreillynet.com/icons/meerkat-powered.jpg - http://meerkat.oreillynet.com - - - - XML: A Disruptive Technology - http://c.moreover.com/click/here.pl?r123 - - XML is placing increasingly heavy loads on the existing technical - infrastructure of the Internet. - - The O'Reilly Network - Simon St.Laurent (mailto:simonstl@simonstl.com) - Copyright © 2000 O'Reilly & Associates, Inc. - XML - XML.com - NASDAQ - XML - - - - Search Meerkat - Search Meerkat's RSS Database... - s - http://meerkat.oreillynet.com/ - search - regex - - - \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/rss2sample.xml b/plugins/OStatus/extlib/XML/Feed/samples/rss2sample.xml deleted file mode 100755 index 53483cc518..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/rss2sample.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - Liftoff News - http://liftoff.msfc.nasa.gov/ - Liftoff to Space Exploration. - en-us - Tue, 10 Jun 2003 04:00:00 GMT - Tue, 10 Jun 2003 09:41:01 GMT - http://blogs.law.harvard.edu/tech/rss - Weblog Editor 2.0 - editor@example.com - webmaster@example.com - - Star City - http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp - How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia's <a href="http://howe.iki.rssi.ru/GCTC/gctc_e.htm">Star City</a>. - Tue, 03 Jun 2003 09:39:21 GMT - http://liftoff.msfc.nasa.gov/2003/06/03.html#item573 - - - Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a <a href="http://science.nasa.gov/headlines/y2003/30may_solareclipse.htm">partial eclipse of the Sun</a> on Saturday, May 31st. - Fri, 30 May 2003 11:06:42 GMT - http://liftoff.msfc.nasa.gov/2003/05/30.html#item572 - - - The Engine That Does More - http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp - Before man travels to Mars, NASA hopes to design new engines that will let us fly through the Solar System more quickly. The proposed VASIMR engine would do that. - Tue, 27 May 2003 08:37:32 GMT - http://liftoff.msfc.nasa.gov/2003/05/27.html#item571 - Test content

    ]]>
    -
    - - Astronauts' Dirty Laundry - http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp - Compared to earlier spacecraft, the International Space Station has many luxuries, but laundry facilities are not one of them. Instead, astronauts have other options. - Tue, 20 May 2003 08:56:02 GMT - http://liftoff.msfc.nasa.gov/2003/05/20.html#item570 - -
    -
    \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/sixapart-jp.xml b/plugins/OStatus/extlib/XML/Feed/samples/sixapart-jp.xml deleted file mode 100755 index f8a04bba5c..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/sixapart-jp.xml +++ /dev/null @@ -1,226 +0,0 @@ - - - -Six Apart - News -http://www.sixapart.jp/ - -ja -Copyright 2005 -Fri, 07 Oct 2005 19:09:34 +0900 -http://www.movabletype.org/?v=3.2-ja -http://blogs.law.harvard.edu/tech/rss - - -ファイブ・ディーが、Movable Typeでブログプロモーションをスタート -MIYAZAWAblog_banner.jpg
    -ファイブ・ディーは、Movable Typeで構築したプロモーション ブログ『宮沢和史 中南米ツアーblog Latin America 2005』を開設しました。

    - -

    9月21日に開設されたこのブログは、ブラジル、ホンジュラス、ニカラグア、メキシコ、キューバの5か国を巡る「Latin America 2005」ツアーに合わせ、そのツアーの模様を同行マネージャーがレポートしていきます。
    -さらに今月2日からは宮沢和史自身が日々録音した声をPodcastingするという点でも、ブログを使ったユニークなプロモーションとなっています。

    - -

    「宮沢和史 中南米ツアーblog Latin America 2005」

    - -

    ※シックス・アパートではこうしたブログを使ったプロモーションに最適な製品をご用意しております。
    -

    ]]>
    -http://www.sixapart.jp/news/2005/10/07-1909.html -http://www.sixapart.jp/news/2005/10/07-1909.html -news -Fri, 07 Oct 2005 19:09:34 +0900 -
    - -Movable Type 3.2日本語版の提供を開始 -Movable Type Logo

    -

    シックス・アパートは、Movable Type 3.2日本語版の提供を開始いたしました。
    -ベータテストにご協力いただいた多くの皆様に、スタッフ一同、心から感謝いたします。

    -

    製品概要など、詳しくはプレスリリースをご参照下さい。

    -

    ご購入のご検討は、Movable Typeのご購入からどうぞ。

    ]]>
    -http://www.sixapart.jp/news/2005/09/29-1530.html -http://www.sixapart.jp/news/2005/09/29-1530.html -news -Thu, 29 Sep 2005 15:30:00 +0900 -
    - -シックス・アパートが、スパム対策強化の「Movable Type 3.2 日本語版」を提供開始 -<プレスリリース資料>

    - -

    シックス・アパートが、スパム対策強化の「Movable Type 3.2 日本語版」を提供開始 ~ スパムの自動判別機能や新ユーザー・インターフェースで、運用管理の機能を強化 ~

    -

    2005年9月29日
    -シックス・アパート株式会社

    -

    ブログ・ソフトウェア大手のシックス・アパート株式会社(本社:東京都港区、代表取締役:関 信浩)は、「Movable Type(ムーバブル・タイプ) 3.2 日本語版」(URL:http://www.sixapart.jp/movabletype/)を9月29日より提供開始いたします。

    ]]>
    -http://www.sixapart.jp/press_releases/2005/09/29-1529.html -http://www.sixapart.jp/press_releases/2005/09/29-1529.html -Press Releases -Thu, 29 Sep 2005 15:29:00 +0900 -
    - -スタッフを募集しています -シックス・アパートはMovable TypeやTypePadの開発エンジニアなど、スタッフを広く募集しています。具体的な募集職種は次の通りです。

    - - - -

    拡大を続ける、日本のブログ市場を積極的にリードする人材を、シックス・アパートは募集しています。上記以外の職種につきましても、お気軽にお問い合わせください。詳しい募集要項や応募方法については、求人情報のページをご覧ください。
    -

    ]]>
    -http://www.sixapart.jp/news/2005/09/27-0906.html -http://www.sixapart.jp/news/2005/09/27-0906.html -news -Tue, 27 Sep 2005 09:06:10 +0900 -
    - -サイト接続不具合に関するお詫びと復旧のお知らせ -9月24日(土)の14:45ごろから、同日18:30ごろまで、シックス・アパート社のウェブサイトが不安定になっており、断続的に接続できない不具合が発生しておりました。このため、この期間中にウェブサイトの閲覧や製品のダウンロードができませんでした。

    - -

    なお現在は不具合は解消しております。みなさまにご迷惑をおかけしたことをお詫びいたします。

    ]]>
    -http://www.sixapart.jp/news/2005/09/26-1000.html -http://www.sixapart.jp/news/2005/09/26-1000.html -news -Mon, 26 Sep 2005 10:00:56 +0900 -
    - -企業ブログ向けパッケージ「TypePad Promotion」を新発売 -シックス・アパートは、ウェブログ・サービスTypePadの企業ブログ向けパッケージ「TypePad Promotion」(タイプパッド・プロモーションの発売を10月下旬から開始いたします。

    - -

    詳しくは、プレスリリースをご参照下さい。

    ]]>
    -http://www.sixapart.jp/news/2005/09/20-1500.html -http://www.sixapart.jp/news/2005/09/20-1500.html -news -Tue, 20 Sep 2005 15:00:01 +0900 -
    - -シックス・アパートが、法人向けブログパッケージ「TypePad Promotion」を発売 -<プレスリリース資料>
    -印刷用(PDF版)

    - -


    -シックス・アパートが、法人向けブログパッケージ「TypePad Promotion」を発売
    -~PR/IRサイトやキャンペーンサイトなど企業のプロモーションニーズに特化~
    -

    -2005年9月20日
    -シックス・アパート株式会社

    - -

    ブログ・サービス大手のシックス・アパート株式会社(本社:東京都港区、代表取締役:関 信浩)は、法人向けプロモーションブログ・パッケージ「TypePad Promotion(タイプパッド・プロモーション)」(URL:http://www.sixapart.jp/typepad/typepad_promotion.html)を10月下旬より販売開始いたします。

    ]]>
    -http://www.sixapart.jp/press_releases/2005/09/20-1500.html -http://www.sixapart.jp/press_releases/2005/09/20-1500.html -Press Releases -Tue, 20 Sep 2005 15:00:00 +0900 -
    - -Six [days] Apart Week -本日、9月16日はSix Apartの創業者ミナ・トロットの誕生日です。
    -私たちの会社は、創業者のトロット夫妻(ベンとミナ)の誕生日が、6日離れていることからSix [days] Apart →Six Apartという風に名付けられています。本日から22日までの6日間を社名の由来となる Six [days] Apart Weekとして、私たちのプロダクトをご紹介させていただきます。

    - -

    今日は、ブログ・サービスのTypePad(タイプパッド)をご紹介します。
    -tp-logo.gif

    - -

    TypePadは、米国PC MAGAZINE誌の2003年EDITOR'S CHOICE とBEST OF THE YEARに選ばれております。
    -pcmag-ad.gif
    -

    ]]>
    -http://www.sixapart.jp/news/2005/09/16-1941.html -http://www.sixapart.jp/news/2005/09/16-1941.html -news -Fri, 16 Sep 2005 19:41:47 +0900 -
    - -ハイパーワークスが商用フォントを利用できるMovable Typeホスティングサービスを開始 -ソフト開発会社の有限会社ハイパーワークスは、商用フォントなど多彩なフォントをブログ上で利用できるブログ・サービス「Glyph-On!(グリフォン) Movable Type ホスティング サービス」の提供を開始しました。
    -

    ]]>
    -http://www.sixapart.jp/news/2005/09/14-1700.html -http://www.sixapart.jp/news/2005/09/14-1700.html -news -Wed, 14 Sep 2005 17:00:00 +0900 -
    - -Movable Type開発エンジニアの募集 - -勤務形態: フルタイム
    -勤務地: 東京 (赤坂)
    -職種: ソフトウェア・エンジニア
    -職務内容: Movable Typeの開発業務全般
    -募集人数: 若干名 -

    ]]>
    -http://www.sixapart.jp/jobs/2005/09/13-0007.html -http://www.sixapart.jp/jobs/2005/09/13-0007.html -Jobs -Tue, 13 Sep 2005 00:07:00 +0900 -
    - -TypePad開発エンジニアの募集 - -勤務形態: フルタイム
    -勤務地: 東京 (赤坂)
    -職種: アプリケーション・エンジニア
    -職務内容: TypePadのカスタマイズ、周辺開発
    -募集人数: 若干名 -

    ]]>
    -http://www.sixapart.jp/jobs/2005/09/13-0004.html -http://www.sixapart.jp/jobs/2005/09/13-0004.html -Jobs -Tue, 13 Sep 2005 00:04:00 +0900 -
    - -カスタマーサポート・ディレクターの募集 -勤務形態: フルタイム
    -勤務地: 東京(赤坂)
    -職種: カスタマーサポート・ディレクター
    -職務内容: TypePadやMovable Typeのカスタマーサポート業務の統括
    -募集人数: 若干名 -

    -]]>
    -http://www.sixapart.jp/jobs/2005/09/13-0003.html -http://www.sixapart.jp/jobs/2005/09/13-0003.html -Jobs -Tue, 13 Sep 2005 00:03:30 +0900 -
    - -アルバイト(マーケティング・広報アシスタント)の募集 -勤務形態: アルバイト
    -勤務地: 東京(港区)
    -職種:マーケティング・PRのアシスタント業務
    -募集人数: 若干名
    -時給:1000円~(但し、試用期間終了後に応相談)。交通費支給
    -時間:平日10時30分~18時30分まで。週3日以上(応相談)
    -

    ]]>
    -http://www.sixapart.jp/jobs/2005/09/13-0002.html -http://www.sixapart.jp/jobs/2005/09/13-0002.html -Jobs -Tue, 13 Sep 2005 00:02:00 +0900 -
    - -アルバイト(開発アシスタント)の募集 -勤務形態: アルバイト
    -勤務地: 東京(港区)
    -職種: アプリケーション開発のアシスタント業務
    -募集人数: 若干名
    -時給:1000円~(但し、試用期間終了後に応相談)。交通費支給
    -時間:平日10時30分~18時30分まで。週3日以上(応相談) -

    ]]>
    -http://www.sixapart.jp/jobs/2005/09/13-0001.html -http://www.sixapart.jp/jobs/2005/09/13-0001.html -Jobs -Tue, 13 Sep 2005 00:01:00 +0900 -
    - -TypePad Japan がバージョンアップしました。 -「TypePad Japan(タイプパッドジャパン)」において、本日、「TypePad 1.6 日本語版」へのバージョンアップを行いました。最新版となる「TypePad 1.6 日本語版」では、ブログデザインの機能強化、ポッドキャスティング対応、モブログ対応に加え、今回新たに大幅な容量アップが行われております。皆様、新しくなったTypePad Japanにどうぞご期待ください。

    - -

    なお、TypePadの携帯対応強化に関しましては、本日よりTypePad Japanのお客様を対象にオープン・ベータを開始しております。

    - -

    2005年9月5日発表のTypePad日本語版 1.6プレスリリースはこちらをご覧下さい。

    ]]>
    -http://www.sixapart.jp/news/2005/09/12-1953.html -http://www.sixapart.jp/news/2005/09/12-1953.html -news -Mon, 12 Sep 2005 19:53:07 +0900 -
    - - -
    -
    \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/samples/technorati.feed b/plugins/OStatus/extlib/XML/Feed/samples/technorati.feed deleted file mode 100755 index 6274a32cda..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/samples/technorati.feed +++ /dev/null @@ -1,54 +0,0 @@ - - - - [Technorati] Tag results for greenbelt - http://www.technorati.com/tag/greenbelt - Posts tagged with "greenbelt" on Technorati. - Mon, 08 Aug 2005 15:15:08 GMT - greenbelt - 2 - 2 - - Technorati v1.0 - - http://static.technorati.com/pix/logos/logo_reverse_sm.gif - Technorati logo - http://www.technorati.com - - - 1 - 7 - 9 - - support@technorati.com (Technorati Support) - http://blogs.law.harvad.edu/tech/rss - 60 - - Greenbelt - http://maggidawn.typepad.com/maggidawn/2005/07/greenbelt.html - So if the plan goes according to plan (!)... I'll be speaking at Greenbelt at these times: Slot 1... - http://maggidawn.typepad.com/maggidawn/2005/07/greenbelt.html - Mon, 18 Jul 2005 02:11:42 GMT - James - 2005-07-11 02:08:12 - http://www.technorati.com/cosmos/search.html?url=http%3A%2F%2Fmaggidawn.typepad.com%2Fmaggidawn%2F2005%2F07%2Fgreenbelt.html - 190 - 237 - maggi dawn - - - - Walking along the Greenbelt - http://pictureshomeless.blogspot.com/2005/06/walking-along-greenbelt.html - [IMG] Photo of homeless man walking near the greenbelt in Boise, Idaho Tags: photo homeless greenbelt Boise Idaho picture - http://pictureshomeless.blogspot.com/2005/06/walking-along-greenbelt.html - Tue, 28 Jun 2005 01:41:24 GMT - 2005-06-26 17:24:03 - http://www.technorati.com/cosmos/search.html?url=http%3A%2F%2Fpictureshomeless.blogspot.com%2F2005%2F06%2Fwalking-along-greenbelt.html - 2 - 2 - - - - diff --git a/plugins/OStatus/extlib/XML/Feed/schemas/atom.rnc b/plugins/OStatus/extlib/XML/Feed/schemas/atom.rnc deleted file mode 100755 index e662d2626c..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/schemas/atom.rnc +++ /dev/null @@ -1,338 +0,0 @@ -# -*- rnc -*- -# RELAX NG Compact Syntax Grammar for the -# Atom Format Specification Version 11 - -namespace atom = "http://www.w3.org/2005/Atom" -namespace xhtml = "http://www.w3.org/1999/xhtml" -namespace s = "http://www.ascc.net/xml/schematron" -namespace local = "" - -start = atomFeed | atomEntry - -# Common attributes - -atomCommonAttributes = - attribute xml:base { atomUri }?, - attribute xml:lang { atomLanguageTag }?, - undefinedAttribute* - -# Text Constructs - -atomPlainTextConstruct = - atomCommonAttributes, - attribute type { "text" | "html" }?, - text - -atomXHTMLTextConstruct = - atomCommonAttributes, - attribute type { "xhtml" }, - xhtmlDiv - -atomTextConstruct = atomPlainTextConstruct | atomXHTMLTextConstruct - -# Person Construct - -atomPersonConstruct = - atomCommonAttributes, - (element atom:name { text } - & element atom:uri { atomUri }? - & element atom:email { atomEmailAddress }? - & extensionElement*) - -# Date Construct - -atomDateConstruct = - atomCommonAttributes, - xsd:dateTime - -# atom:feed - -atomFeed = - [ - s:rule [ - context = "atom:feed" - s:assert [ - test = "atom:author or not(atom:entry[not(atom:author)])" - "An atom:feed must have an atom:author unless all " - ~ "of its atom:entry children have an atom:author." - ] - ] - ] - element atom:feed { - atomCommonAttributes, - (atomAuthor* - & atomCategory* - & atomContributor* - & atomGenerator? - & atomIcon? - & atomId - & atomLink* - & atomLogo? - & atomRights? - & atomSubtitle? - & atomTitle - & atomUpdated - & extensionElement*), - atomEntry* - } - -# atom:entry - -atomEntry = - [ - s:rule [ - context = "atom:entry" - s:assert [ - test = "atom:link[@rel='alternate'] " - ~ "or atom:link[not(@rel)] " - ~ "or atom:content" - "An atom:entry must have at least one atom:link element " - ~ "with a rel attribute of 'alternate' " - ~ "or an atom:content." - ] - ] - s:rule [ - context = "atom:entry" - s:assert [ - test = "atom:author or " - ~ "../atom:author or atom:source/atom:author" - "An atom:entry must have an atom:author " - ~ "if its feed does not." - ] - ] - ] - element atom:entry { - atomCommonAttributes, - (atomAuthor* - & atomCategory* - & atomContent? - & atomContributor* - & atomId - & atomLink* - & atomPublished? - & atomRights? - & atomSource? - & atomSummary? - & atomTitle - & atomUpdated - & extensionElement*) - } - -# atom:content - -atomInlineTextContent = - element atom:content { - atomCommonAttributes, - attribute type { "text" | "html" }?, - (text)* - } - -atomInlineXHTMLContent = - element atom:content { - atomCommonAttributes, - attribute type { "xhtml" }, - xhtmlDiv - } - -atomInlineOtherContent = - element atom:content { - atomCommonAttributes, - attribute type { atomMediaType }?, - (text|anyElement)* - } - -atomOutOfLineContent = - element atom:content { - atomCommonAttributes, - attribute type { atomMediaType }?, - attribute src { atomUri }, - empty - } - -atomContent = atomInlineTextContent - | atomInlineXHTMLContent - | atomInlineOtherContent - | atomOutOfLineContent - -# atom:author - -atomAuthor = element atom:author { atomPersonConstruct } - -# atom:category - -atomCategory = - element atom:category { - atomCommonAttributes, - attribute term { text }, - attribute scheme { atomUri }?, - attribute label { text }?, - undefinedContent - } - -# atom:contributor - -atomContributor = element atom:contributor { atomPersonConstruct } - -# atom:generator - -atomGenerator = element atom:generator { - atomCommonAttributes, - attribute uri { atomUri }?, - attribute version { text }?, - text -} - -# atom:icon - -atomIcon = element atom:icon { - atomCommonAttributes, - (atomUri) -} - -# atom:id - -atomId = element atom:id { - atomCommonAttributes, - (atomUri) -} - -# atom:logo - -atomLogo = element atom:logo { - atomCommonAttributes, - (atomUri) -} - -# atom:link - -atomLink = - element atom:link { - atomCommonAttributes, - attribute href { atomUri }, - attribute rel { atomNCName | atomUri }?, - attribute type { atomMediaType }?, - attribute hreflang { atomLanguageTag }?, - attribute title { text }?, - attribute length { text }?, - undefinedContent - } - -# atom:published - -atomPublished = element atom:published { atomDateConstruct } - -# atom:rights - -atomRights = element atom:rights { atomTextConstruct } - -# atom:source - -atomSource = - element atom:source { - atomCommonAttributes, - (atomAuthor* - & atomCategory* - & atomContributor* - & atomGenerator? - & atomIcon? - & atomId? - & atomLink* - & atomLogo? - & atomRights? - & atomSubtitle? - & atomTitle? - & atomUpdated? - & extensionElement*) - } - -# atom:subtitle - -atomSubtitle = element atom:subtitle { atomTextConstruct } - -# atom:summary - -atomSummary = element atom:summary { atomTextConstruct } - -# atom:title - -atomTitle = element atom:title { atomTextConstruct } - -# atom:updated - -atomUpdated = element atom:updated { atomDateConstruct } - -# Low-level simple types - -atomNCName = xsd:string { minLength = "1" pattern = "[^:]*" } - -# Whatever a media type is, it contains at least one slash -atomMediaType = xsd:string { pattern = ".+/.+" } - -# As defined in RFC 3066 -atomLanguageTag = xsd:string { - pattern = "[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*" -} - -# Unconstrained; it's not entirely clear how IRI fit into -# xsd:anyURI so let's not try to constrain it here -atomUri = text - -# Whatever an email address is, it contains at least one @ -atomEmailAddress = xsd:string { pattern = ".+@.+" } - -# Simple Extension - -simpleExtensionElement = - element * - atom:* { - text - } - -# Structured Extension - -structuredExtensionElement = - element * - atom:* { - (attribute * { text }+, - (text|anyElement)*) - | (attribute * { text }*, - (text?, anyElement+, (text|anyElement)*)) - } - -# Other Extensibility - -extensionElement = - simpleExtensionElement | structuredExtensionElement - -undefinedAttribute = - attribute * - (xml:base | xml:lang | local:*) { text } - -undefinedContent = (text|anyForeignElement)* - -anyElement = - element * { - (attribute * { text } - | text - | anyElement)* - } - -anyForeignElement = - element * - atom:* { - (attribute * { text } - | text - | anyElement)* - } - -# XHTML - -anyXHTML = element xhtml:* { - (attribute * { text } - | text - | anyXHTML)* -} - -xhtmlDiv = element xhtml:div { - (attribute * { text } - | text - | anyXHTML)* -} - -# EOF \ No newline at end of file diff --git a/plugins/OStatus/extlib/XML/Feed/schemas/rss10.rnc b/plugins/OStatus/extlib/XML/Feed/schemas/rss10.rnc deleted file mode 100755 index 7250947887..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/schemas/rss10.rnc +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/OStatus/extlib/XML/Feed/schemas/rss11.rnc b/plugins/OStatus/extlib/XML/Feed/schemas/rss11.rnc deleted file mode 100755 index c8633766f6..0000000000 --- a/plugins/OStatus/extlib/XML/Feed/schemas/rss11.rnc +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - - - http://purl.org/net/rss1.1#Channel - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - http://purl.org/net/rss1.1#title - - - - - - - - - - - - - - http://purl.org/net/rss1.1#link - - - - - - - - - - http://purl.org/net/rss1.1#description - - - - - - - - - - - - - http://purl.org/net/rss1.1#image - - - - - - - - - - - - - - - - - - - - - - - - - http://purl.org/net/rss1.1#url - - - - - - - - - - http://purl.org/net/rss1.1#items - - - - - - - - - - - - - - - - - http://purl.org/net/rss1.1#item - - - - - - - - - - - - - - - - - - - - - - - - - - - - http://purl.org/net/rss1.1#Any - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Resource - - - - - Collection - - - - diff --git a/plugins/OStatus/extlib/xml-feed-parser-bug-16416.patch b/plugins/OStatus/extlib/xml-feed-parser-bug-16416.patch deleted file mode 100644 index c53bd97374..0000000000 --- a/plugins/OStatus/extlib/xml-feed-parser-bug-16416.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/htdocs/lib/pear/XML/Feed/Parser/RSS2.php b/htdocs/lib/pear/XML/Feed/Parser/RSS2.php -index c5d79d1..308a4ab 100644 ---- a/htdocs/lib/pear/XML/Feed/Parser/RSS2.php -+++ b/htdocs/lib/pear/XML/Feed/Parser/RSS2.php -@@ -321,7 +321,8 @@ class XML_Feed_Parser_RSS2 extends XML_Feed_Parser_Type - */ - function getLink($offset, $attribute = 'href', $params = array()) - { -- $links = $this->model->getElementsByTagName('link'); -+ $xPath = new DOMXPath($this->model); -+ $links = $xPath->query('//link'); - - if ($links->length <= $offset) { - return false; diff --git a/plugins/OStatus/tests/FeedMungerTest.php b/plugins/OStatus/tests/FeedMungerTest.php deleted file mode 100644 index 0ce24c9fb8..0000000000 --- a/plugins/OStatus/tests/FeedMungerTest.php +++ /dev/null @@ -1,147 +0,0 @@ -profile(); - - foreach ($expected as $field => $val) { - $this->assertEquals($expected[$field], $profile->$field, "profile->$field"); - } - } - - static public function profileProvider() - { - return array( - array(self::samplefeed(), - array('nickname' => 'leŭksman', // @todo does this need to be asciified? - 'fullname' => 'leŭksman', - 'bio' => 'reticula, electronica, & oddities', - 'homepage' => 'http://leuksman.com/log'))); - } - - /** - * @dataProvider noticeProvider - * - */ - public function testNotices($xml, $entryIndex, $expected) - { - $feed = new XML_Feed_Parser($xml, false, false, true); - $entry = $feed->getEntryByOffset($entryIndex); - - $munger = new FeedMunger($feed); - $notice = $munger->noticeFromEntry($entry); - - $this->assertTrue(mb_strlen($notice) <= Notice::maxContent()); - $this->assertEquals($expected, $notice); - } - - static public function noticeProvider() - { - return array( - array('A fairly short titlehttp://example.com/short/link', 0, - 'New post: "A fairly short title" http://example.com/short/link'), - // Requires URL shortening ... - array('A fairly short titlehttp://example.com/but/a/very/long/link/indeed/this/is/far/too/long/for/mere/humans/to/comprehend/oh/my/gosh', 0, - 'New post: "A fairly short title" http://ur1.ca/g2o1'), - array('A fairly long title in this case, which will have to get cut down at some point alongside its very long link. Really who even makes titles this long? It\'s just ridiculous imo...http://example.com/but/a/very/long/link/indeed/this/is/far/too/long/for/mere/humans/to/comprehend/oh/my/gosh', 0, - 'New post: "A fairly long title in this case, which will have to get cut down at some point alongside its very long li…" http://ur1.ca/g2o1'), - // Some real sample feeds - array(self::samplefeed(), 0, - 'New post: "Compiling PHP on Snow Leopard" http://leuksman.com/log/2009/11/12/compiling-php-on-snow-leopard/'), - array(self::samplefeedBlogspot(), 0, - 'New post: "I love posting" http://briontest.blogspot.com/2009/11/i-love-posting.html'), - array(self::samplefeedBlogspot(), 1, - 'New post: "Hey dude" http://briontest.blogspot.com/2009/11/hey-dude.html'), - ); - } - - static protected function samplefeed() - { - $xml = '<' . '?xml version="1.0" encoding="UTF-8"?' . ">\n"; - $samplefeed = $xml . << - - - leŭksman - - http://leuksman.com/log - reticula, electronica, & oddities - - Thu, 12 Nov 2009 17:44:42 +0000 - http://wordpress.org/?v=2.8.6 - en - hourly - 1 - - - Compiling PHP on Snow Leopard - http://leuksman.com/log/2009/11/12/compiling-php-on-snow-leopard/ - http://leuksman.com/log/2009/11/12/compiling-php-on-snow-leopard/#comments - Thu, 12 Nov 2009 17:44:42 +0000 - brion - - - - - http://leuksman.com/log/?p=649 - - If you’ve been having trouble compiling your own PHP installations on Mac OS X 10.6, here’s the secret to making it not suck! After running the configure script, edit the generated Makefile and make these fixes:

    -
      -
    • Find the EXTRA_LIBS definition and add -lresolv to the end
    • -
    • Find the EXE_EXT definition and remove .dSYM
    • -
    -

    Standard make and make install should work from here…

    -

    For reference, here’s the whole configure line I currently use; MySQL is installed from the downloadable installer; other deps from MacPorts:

    -

    ‘./configure’ ‘–prefix=/opt/php52′ ‘–with-mysql=/usr/local/mysql’ ‘–with-zlib’ ‘–with-bz2′ ‘–enable-mbstring’ ‘–enable-exif’ ‘–enable-fastcgi’ ‘–with-xmlrpc’ ‘–with-xsl’ ‘–with-readline=/opt/local’ –without-iconv –with-gd –with-png-dir=/opt/local –with-jpeg-dir=/opt/local –with-curl –with-gettext=/opt/local –with-mysqli=/usr/local/mysql/bin/mysql_config –with-tidy=/opt/local –enable-pcntl –with-openssl

    -]]>
    - http://leuksman.com/log/2009/11/12/compiling-php-on-snow-leopard/feed/ - 0 -
    -
    - -END; - return $samplefeed; - } - - static protected function samplefeedBlogspot() - { - return <<tag:blogger.com,1999:blog-77800835085316971672009-11-19T12:56:11.233-08:00Brion's Cool Test Blogbrionhttp://www.blogger.com/profile/12932299467049762017noreply@blogger.comBlogger2125tag:blogger.com,1999:blog-7780083508531697167.post-84566718790002906772009-11-19T12:55:00.000-08:002009-11-19T12:56:11.241-08:00I love postingIt's pretty awesome, if you like that sort of thing.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7780083508531697167-8456671879000290677?l=briontest.blogspot.com' alt='' /></div>brionhttp://www.blogger.com/profile/12932299467049762017noreply@blogger.com0tag:blogger.com,1999:blog-7780083508531697167.post-82022969178973466332009-11-18T13:52:00.001-08:002009-11-18T13:52:48.444-08:00Hey dudetestingggggggggg<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7780083508531697167-8202296917897346633?l=briontest.blogspot.com' alt='' /></div>brionhttp://www.blogger.com/profile/12932299467049762017noreply@blogger.com0 -END; - } -} From 61a072b3c492fd1b336e84655ffb6a28547acba7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 13:23:08 -0500 Subject: [PATCH 058/190] Add a library to mint tag URIs We've been making pretty crummy tag: URIs for a while. We should continue to favor HTTP URIs, since it's nice to be able to discover things about an object you've shared the ID of. Where that's not possible, this makes nicer tag URIs. --- lib/default.php | 2 +- lib/taguri.php | 96 ++++++++++++++++++++++++++++++++++++++++++++ tests/TagURITest.php | 36 +++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 lib/taguri.php create mode 100644 tests/TagURITest.php diff --git a/lib/default.php b/lib/default.php index 4f3ea00f2a..bb7708bfcd 100644 --- a/lib/default.php +++ b/lib/default.php @@ -175,7 +175,7 @@ $default = array('enabled' => false), 'integration' => array('source' => 'StatusNet', # source attribute for Twitter - 'taguri' => $_server.',2009'), # base for tag URIs + 'taguri' => null), # base for tag URIs 'twitter' => array('enabled' => true, 'consumer_key' => null, diff --git a/lib/taguri.php b/lib/taguri.php new file mode 100644 index 0000000000..d8398eded5 --- /dev/null +++ b/lib/taguri.php @@ -0,0 +1,96 @@ +. + * + * @category URI + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Mint tag: URIs + * + * tag: URIs are unique identifiers according to http://tools.ietf.org/html/rfc4151. + * + * We use them for creating URIs for things that can't be HTTP retrieved. + * + * @category URI + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +class TagURI +{ + /** + * Return the base part of a tag URI + * + * Note: use mint() instead. + * + * @return string Tag URI base to use + */ + + static function base() + { + $base = common_config('integration', 'taguri'); + + if (empty($base)) { + + $base = common_config('site', 'server').','.date('Y-m-d'); + + $pathPart = trim(common_config('site', 'path'), '/'); + + if (!empty($pathPart)) { + $base .= ':'.str_replace('/', ':', $pathPart); + } + } + + return $base; + } + + /** + * Make a new tag URI + * + * Builds the proper base and creates all the parts + * + * @return string minted URI + */ + + static function mint() + { + $base = self::base(); + + $args = func_get_args(); + + $format = array_shift($args); + + $extra = vsprintf($format, $args); + + return 'tag:'.$base.':'.$extra; + } +} diff --git a/tests/TagURITest.php b/tests/TagURITest.php new file mode 100644 index 0000000000..d23f8bfe66 --- /dev/null +++ b/tests/TagURITest.php @@ -0,0 +1,36 @@ +assertEquals($uri, $minted); + } + + static public function provider() + { + return array(array('favorite:%d:%d', + array(1, 3), + 'tag:example.net,'.date('Y-m-d').':apps:statusnet:favorite:1:3')); + } +} + From f891b135fbbf79bee6f9753e6a9cded65f219ab7 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 20 Feb 2010 10:20:42 -0800 Subject: [PATCH 059/190] OStatus: fix regressions in plugin & usersalmon action. Sub/unsub notifications are working again. --- plugins/OStatus/OStatusPlugin.php | 22 --- plugins/OStatus/actions/usersalmon.php | 189 +++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 22 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 9e6d03177f..e78e658a6c 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -357,26 +357,4 @@ class OStatusPlugin extends Plugin return true; } - - function onEndUnsubscribe($subscriber, $other) - { - $user = User::staticGet('id', $subscriber->id); - - if (empty($user)) { - return true; - } - - $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); - - if (empty($oprofile)) { - return true; - } - - // We have a local user subscribing to a remote profile; make the - // magic happen! - - $oprofile->notify($subscriber, ActivityVerb::UNFOLLOW); - - return true; - } } diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index e69de29bb2..4363488ddc 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -0,0 +1,189 @@ +. + */ + +/** + * @package OStatusPlugin + * @author James Walker + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class UsersalmonAction extends SalmonAction +{ + function prepare($args) + { + parent::prepare($args); + + $id = $this->trimmed('id'); + + if (!$id) { + $this->clientError(_('No ID.')); + } + + $this->user = User::staticGet('id', $id); + + if (empty($this->user)) { + $this->clientError(_('No such user.')); + } + + return true; + } + + /** + * We've gotten a post event on the Salmon backchannel, probably a reply. + * + * @todo validate if we need to handle this post, then call into + * ostatus_profile's general incoming-post handling. + */ + function handlePost() + { + switch ($this->act->object->type) { + case ActivityObject::ARTICLE: + case ActivityObject::BLOGENTRY: + case ActivityObject::NOTE: + case ActivityObject::STATUS: + case ActivityObject::COMMENT: + break; + default: + throw new ClientException("Can't handle that kind of post."); + } + + // Notice must either be a) in reply to a notice by this user + // or b) to the attention of this user + + $context = $this->act->context; + + if (!empty($context->replyToID)) { + $notice = Notice::staticGet('uri', $context->replyToID); + if (empty($notice)) { + throw new ClientException("In reply to unknown notice"); + } + if ($notice->profile_id != $this->user->id) { + throw new ClientException("In reply to a notice not by this user"); + } + } else if (!empty($context->attention)) { + if (!in_array($context->attention, $this->user->uri)) { + throw new ClientException("To the attention of user(s) not including this one!"); + } + } else { + throw new ClientException("Not to anyone in reply to anything!"); + } + + $profile = $this->ensureProfile(); + // @fixme do something with the post + } + + /** + * We've gotten a follow/subscribe notification from a remote user. + * Save a subscription relationship for them. + */ + + function handleFollow() + { + $oprofile = $this->ensureProfile(); + if ($oprofile) { + common_log(LOG_INFO, "Setting up subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); + $oprofile->subscribeRemoteToLocal($this->user); + } else { + common_log(LOG_INFO, "Can't set up subscription from remote; missing profile."); + } + } + + /** + * We've gotten an unfollow/unsubscribe notification from a remote user. + * Check if we have a subscription relationship for them and kill it. + * + * @fixme probably catch exceptions on fail? + */ + function handleUnfollow() + { + $oprofile = $this->ensureProfile(); + if ($oprofile) { + common_log(LOG_INFO, "Canceling subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); + Subscription::cancel($oprofile->localProfile(), $this->user->getProfile()); + } else { + common_log(LOG_ERR, "Can't cancel subscription from remote, didn't find the profile"); + } + } + + /** + * Remote user likes one of our posts. + * Confirm the post is ours, and save a local favorite event. + */ + + function handleFavorite() + { + // WORST VARIABLE NAME EVER + $object = $this->act->object; + + switch ($this->act->object->type) { + case ActivityObject::ARTICLE: + case ActivityObject::BLOGENTRY: + case ActivityObject::NOTE: + case ActivityObject::STATUS: + case ActivityObject::COMMENT: + break; + default: + throw new ClientException("Can't handle that kind of object for liking/faving."); + } + + $notice = Notice::staticGet('uri', $object->id); + + if (empty($notice)) { + throw new ClientException("Notice with ID $object->id unknown."); + } + + if ($notice->profile_id != $this->user->id) { + throw new ClientException("Notice with ID $object->id not posted by $this->user->id."); + } + + $profile = $this->ensureProfile(); + + $old = Fave::pkeyGet(array('user_id' => $profile->id, + 'notice_id' => $notice->id)); + + if (!empty($old)) { + throw new ClientException("We already know that's a fave!"); + } + + $fave = new Fave(); + + // @fixme need to change this attribute name, maybe references + $fave->user_id = $profile->id; + $fave->notice_id = $notice->id; + + $result = $fave->insert(); + + if (!$result) { + common_log_db_error($fave, 'INSERT', __FILE__); + throw new ServerException('Could not save new favorite.'); + } + } + + /** + * Remote user doesn't like one of our posts after all! + * Confirm the post is ours, and save a local favorite event. + */ + function handleUnfavorite() + { + } + +} From f3b08461bd476d368d444d48025709fb6a111b7d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 13:31:20 -0500 Subject: [PATCH 060/190] Change to use TagURI::base() instead of common_config() I changed the way that tag: URIs are minted, so we now use the right base. Ideally most of these would use HTTP URIs instead, but for now at least they use the right base. --- actions/apidirectmessage.php | 2 +- actions/apigrouplist.php | 2 +- actions/apigrouplistall.php | 2 +- actions/apitimelinefavorites.php | 2 +- actions/apitimelinefriends.php | 2 +- actions/apitimelinegroup.php | 2 +- actions/apitimelinehome.php | 2 +- actions/apitimelinementions.php | 2 +- actions/apitimelinepublic.php | 2 +- actions/apitimelineretweetedtome.php | 2 +- actions/apitimelineretweetsofme.php | 2 +- actions/apitimelinetag.php | 2 +- actions/apitimelineuser.php | 2 +- actions/twitapisearchatom.php | 4 ++-- lib/api.php | 4 ++-- 15 files changed, 17 insertions(+), 17 deletions(-) diff --git a/actions/apidirectmessage.php b/actions/apidirectmessage.php index 5fbc46518b..5355acf825 100644 --- a/actions/apidirectmessage.php +++ b/actions/apidirectmessage.php @@ -79,7 +79,7 @@ class ApiDirectMessageAction extends ApiAuthAction } $server = common_root_url(); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); if ($this->arg('sent')) { diff --git a/actions/apigrouplist.php b/actions/apigrouplist.php index 66b67a030e..605b382326 100644 --- a/actions/apigrouplist.php +++ b/actions/apigrouplist.php @@ -93,7 +93,7 @@ class ApiGroupListAction extends ApiBareAuthAction $sitename = common_config('site', 'name'); $title = sprintf(_("%s's groups"), $this->user->nickname); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:Groups"; $link = common_local_url( 'usergroups', diff --git a/actions/apigrouplistall.php b/actions/apigrouplistall.php index 1921c1f193..d2ef2978aa 100644 --- a/actions/apigrouplistall.php +++ b/actions/apigrouplistall.php @@ -88,7 +88,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction $sitename = common_config('site', 'name'); $title = sprintf(_("%s groups"), $sitename); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:Groups"; $link = common_local_url('groups'); $subtitle = sprintf(_("groups on %s"), $sitename); diff --git a/actions/apitimelinefavorites.php b/actions/apitimelinefavorites.php index f7f900ddfb..c89d02247a 100644 --- a/actions/apitimelinefavorites.php +++ b/actions/apitimelinefavorites.php @@ -110,7 +110,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction $this->user->nickname ); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:Favorites:" . $this->user->id; $subtitle = sprintf( diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php index 0af04fe4fb..2db76857e3 100644 --- a/actions/apitimelinefriends.php +++ b/actions/apitimelinefriends.php @@ -112,7 +112,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); $sitename = common_config('site', 'name'); $title = sprintf(_("%s and friends"), $this->user->nickname); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:FriendsTimeline:" . $this->user->id; $subtitle = sprintf( diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index 3c74e36b56..1d0c4afdd0 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -107,7 +107,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction $sitename = common_config('site', 'name'); $avatar = $this->group->homepage_logo; $title = sprintf(_("%s timeline"), $this->group->nickname); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:GroupTimeline:" . $this->group->id; $subtitle = sprintf( diff --git a/actions/apitimelinehome.php b/actions/apitimelinehome.php index ae41680702..0c72f4020c 100644 --- a/actions/apitimelinehome.php +++ b/actions/apitimelinehome.php @@ -113,7 +113,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); $sitename = common_config('site', 'name'); $title = sprintf(_("%s and friends"), $this->user->nickname); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:HomeTimeline:" . $this->user->id; $subtitle = sprintf( diff --git a/actions/apitimelinementions.php b/actions/apitimelinementions.php index d2e31d0bdd..a39c63346a 100644 --- a/actions/apitimelinementions.php +++ b/actions/apitimelinementions.php @@ -117,7 +117,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction _('%1$s / Updates mentioning %2$s'), $sitename, $this->user->nickname ); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:Mentions:" . $this->user->id; $link = common_local_url( 'replies', diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php index c1fa72a3ee..1ff0fd2617 100644 --- a/actions/apitimelinepublic.php +++ b/actions/apitimelinepublic.php @@ -109,7 +109,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction $sitename = common_config('site', 'name'); $sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'); $title = sprintf(_("%s public timeline"), $sitename); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:PublicTimeline"; $link = common_root_url(); $subtitle = sprintf(_("%s updates from everyone!"), $sitename); diff --git a/actions/apitimelineretweetedtome.php b/actions/apitimelineretweetedtome.php index e47bc30b85..73e35c86bf 100644 --- a/actions/apitimelineretweetedtome.php +++ b/actions/apitimelineretweetedtome.php @@ -109,7 +109,7 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction $profile = $this->auth_user->getProfile(); $title = sprintf(_("Repeated to %s"), $this->auth_user->nickname); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id; $link = common_local_url('all', array('nickname' => $this->auth_user->nickname)); diff --git a/actions/apitimelineretweetsofme.php b/actions/apitimelineretweetsofme.php index 26706a75e7..c77912fd0f 100644 --- a/actions/apitimelineretweetsofme.php +++ b/actions/apitimelineretweetsofme.php @@ -112,7 +112,7 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction $profile = $this->auth_user->getProfile(); $title = sprintf(_("Repeats of %s"), $this->auth_user->nickname); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:RepeatsOfMe:" . $this->auth_user->id; header('Content-Type: application/atom+xml; charset=utf-8'); diff --git a/actions/apitimelinetag.php b/actions/apitimelinetag.php index 5b6ded4c04..a29061fccf 100644 --- a/actions/apitimelinetag.php +++ b/actions/apitimelinetag.php @@ -105,7 +105,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction $this->tag, $sitename ); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:TagTimeline:".$tag; switch($this->format) { diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index 9f7ec4c236..3e849cc786 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -116,7 +116,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction $sitename = common_config('site', 'name'); $title = sprintf(_("%s timeline"), $this->user->nickname); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $id = "tag:$taguribase:UserTimeline:" . $this->user->id; $link = common_local_url( 'showstream', diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index baed2a0c7c..e389ddec84 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -245,7 +245,7 @@ class TwitapisearchatomAction extends ApiAction 'xmlns:twitter' => 'http://api.twitter.com/', 'xml:lang' => 'en-US')); // XXX Other locales ? - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $this->element('id', null, "tag:$taguribase:search/$server"); $site_uri = common_path(false); @@ -329,7 +329,7 @@ class TwitapisearchatomAction extends ApiAction $this->elementStart('entry'); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $this->element('id', null, "tag:$taguribase:$notice->id"); $this->element('published', null, common_date_w3dtf($notice->created)); diff --git a/lib/api.php b/lib/api.php index 22eef7436d..0bcf4cc21a 100644 --- a/lib/api.php +++ b/lib/api.php @@ -358,7 +358,7 @@ class ApiAction extends Action $entry['link'] = common_local_url('shownotice', array('notice' => $notice->id)); $entry['published'] = common_date_iso8601($notice->created); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $entry['id'] = "tag:$taguribase:$entry[link]"; $entry['updated'] = $entry['published']; @@ -802,7 +802,7 @@ class ApiAction extends Action $entry['link'] = common_local_url('showmessage', array('message' => $message->id)); $entry['published'] = common_date_iso8601($message->created); - $taguribase = common_config('integration', 'taguri'); + $taguribase = TagURI::base(); $entry['id'] = "tag:$taguribase:$entry[link]"; $entry['updated'] = $entry['published']; From ea9d6f21ecaff6e26ebe30775d1ddcd6d68d0a11 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 20 Feb 2010 12:46:48 -0800 Subject: [PATCH 061/190] OStatus subscription page fixups; works but needs lots of UI loving! - ostatussub via subscribe button now works again (changed to take profile instead of feed, patched up to the new discovery) - added a quickie hack to allow putting your remote profile URI in place of webfinger acct through the remote-sub button (needs to be patched up to do proper discovery via XRDS or a link or something) --- plugins/OStatus/actions/ostatusinit.php | 88 ++++++---- plugins/OStatus/actions/ostatussub.php | 218 ++++++++++++++---------- plugins/OStatus/actions/webfinger.php | 2 +- 3 files changed, 186 insertions(+), 122 deletions(-) diff --git a/plugins/OStatus/actions/ostatusinit.php b/plugins/OStatus/actions/ostatusinit.php index d21774420d..4afde2c36e 100644 --- a/plugins/OStatus/actions/ostatusinit.php +++ b/plugins/OStatus/actions/ostatusinit.php @@ -37,7 +37,7 @@ class OStatusInitAction extends Action parent::prepare($args); if (common_logged_in()) { - $this->clientError(_('You can use the local subscription!')); + $this->clientError(_m('You can use the local subscription!')); return false; } @@ -55,7 +55,7 @@ class OStatusInitAction extends Action /* Use a session token for CSRF protection. */ $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. '. + $this->showForm(_m('There was a problem with your session token. '. 'Try again, please.')); return; } @@ -73,7 +73,7 @@ class OStatusInitAction extends Action $this->xw->startDocument('1.0', 'UTF-8'); $this->elementStart('html'); $this->elementStart('head'); - $this->element('title', null, _('Subscribe to user')); + $this->element('title', null, _m('Subscribe to user')); $this->elementEnd('head'); $this->elementStart('body'); $this->showContent(); @@ -91,50 +91,78 @@ class OStatusInitAction extends Action 'class' => 'form_settings', 'action' => common_local_url('ostatusinit'))); $this->elementStart('fieldset'); - $this->element('legend', null, sprintf(_('Subscribe to %s'), $this->nickname)); + $this->element('legend', null, sprintf(_m('Subscribe to %s'), $this->nickname)); $this->hidden('token', common_session_token()); $this->elementStart('ul', 'form_data'); $this->elementStart('li', array('id' => 'ostatus_nickname')); - $this->input('nickname', _('User nickname'), $this->nickname, - _('Nickname of the user you want to follow')); + $this->input('nickname', _m('User nickname'), $this->nickname, + _m('Nickname of the user you want to follow')); $this->elementEnd('li'); $this->elementStart('li', array('id' => 'ostatus_profile')); - $this->input('acct', _('Profile Account'), $this->acct, - _('Your account id (i.e. user@identi.ca)')); + $this->input('acct', _m('Profile Account'), $this->acct, + _m('Your account id (i.e. user@identi.ca)')); $this->elementEnd('li'); $this->elementEnd('ul'); - $this->submit('submit', _('Subscribe')); + $this->submit('submit', _m('Subscribe')); $this->elementEnd('fieldset'); $this->elementEnd('form'); } function ostatusConnect() { - $w = new Webfinger; - - $result = $w->lookup($this->acct); - foreach ($result->links as $link) { - if ($link['rel'] == 'http://ostatus.org/schema/1.0/subscribe') { - // We found a URL - let's redirect! - - $user = User::staticGet('nickname', $this->nickname); - - $feed_url = common_local_url('ApiTimelineUser', - array('id' => $user->id, - 'format' => 'atom')); - $url = $w->applyTemplate($link['template'], $feed_url); - - common_redirect($url, 303); - } - - } - + $opts = array('allowed_schemes' => array('http', 'https', 'acct')); + if (Validate::uri($this->acct, $opts)) { + $bits = parse_url($this->acct); + if ($bits['scheme'] == 'acct') { + $this->connectWebfinger($bits['path']); + } else { + $this->connectProfile($this->acct); + } + } elseif (strpos('@', $this->acct) !== false) { + $this->connectWebfinger($this->acct); + } } - + + function connectWebfinger($acct) + { + $w = new Webfinger; + + $result = $w->lookup($acct); + if (!$result) { + $this->clientError(_m("Couldn't look up OStatus account profile.")); + } + foreach ($result->links as $link) { + if ($link['rel'] == 'http://ostatus.org/schema/1.0/subscribe') { + // We found a URL - let's redirect! + + $user = User::staticGet('nickname', $this->nickname); + $target_profile = common_local_url('userbyid', array('id' => $user->id)); + + $url = $w->applyTemplate($link['template'], $feed_url); + + common_redirect($url, 303); + } + + } + + } + + function connectProfile($subscriber_profile) + { + $user = User::staticGet('nickname', $this->nickname); + $target_profile = common_local_url('userbyid', array('id' => $user->id)); + + // @fixme hack hack! We should look up the remote sub URL from XRDS + $suburl = preg_replace('!^(.*)/(.*?)$!', '$1/main/ostatussub', $subscriber_profile); + $suburl .= '?profile=' . urlencode($target_profile); + + common_redirect($suburl, 303); + } + function title() { - return _('OStatus Connect'); + return _m('OStatus Connect'); } } diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 2391225016..5244031437 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -1,7 +1,7 @@ + * @maintainer Brion Vibber */ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } class OStatusSubAction extends Action { + protected $profile_uri; + protected $preview; + protected $munger; + + /** + * Title of the page + * + * @return string Title of the page + */ - protected $feedurl; - function title() { - return _m("OStatus Subscribe"); + return _m('Authorize subscription'); } - function handle($args) + /** + * Instructions for use + * + * @return instructions for use + */ + + function getInstructions() { - if ($this->validateFeed()) { - $this->showForm(); - } - - return true; - + return _m('You can subscribe to users from other supported sites. Paste their address or profile URI below:'); } - function showForm($err = null) + function showForm($error=null) { - $this->err = $err; + $this->error = $error; $this->showPage(); } + /** + * Content area of the page + * + * Shows a form for associating a remote OStatus account with this + * StatusNet account. + * + * @return void + */ + function showContent() { + // @fixme is this right place? + if ($this->error) { + $this->text($this->error); + } + $user = common_current_user(); $profile = $user->getProfile(); - $fuser = null; - - $flink = Foreign_link::getByUserID($user->id, FEEDSUB_SERVICE); - - if (!empty($flink)) { - $fuser = $flink->getForeignUser(); - } - $this->elementStart('form', array('method' => 'post', - 'id' => 'form_settings_feedsub', + 'id' => 'ostatus_sub', 'class' => 'form_settings', 'action' => - common_local_url('feedsubsettings'))); + common_local_url('ostatussub'))); $this->hidden('token', common_session_token()); @@ -77,17 +91,47 @@ class OStatusSubAction extends Action $this->elementStart('ul', 'form_data'); $this->elementStart('li'); - $this->input('feedurl', _('Feed URL'), $this->feedurl, _('Enter the URL of a PubSubHubbub-enabled feed')); + $this->input('profile', + _m('Address or profile URL'), + $this->profile_uri, + _m('Enter the profile URL of a PubSubHubbub-enabled feed')); $this->elementEnd('li'); $this->elementEnd('ul'); - $this->submit('subscribe', _m('Subscribe')); + if ($this->preview) { + $this->submit('subscribe', _m('Subscribe')); + } else { + $this->submit('validate', _m('Continue')); + } $this->elementEnd('fieldset'); $this->elementEnd('form'); - $this->previewFeed(); + if ($this->preview) { + $this->previewFeed(); + } + } + + function prepare($args) + { + parent::prepare($args); + $this->profile_uri = $this->arg('profile'); + return true; + } + + function handle($args) + { + parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->handlePost(); + } else { + if ($this->profile_uri) { + $this->validateAndPreview(); + } else { + $this->showPage(); + } + } } /** @@ -111,14 +155,15 @@ class OStatusSubAction extends Action return; } - if ($this->arg('subscribe')) { + if ($this->arg('validate')) { + $this->validateAndPreview(); + } else if ($this->arg('subscribe')) { $this->saveFeed(); } else { $this->showForm(_('Unexpected form submission.')); } } - /** * Set up and add a feed * @@ -127,100 +172,91 @@ class OStatusSubAction extends Action */ function validateFeed() { - $feedurl = $this->trimmed('feed'); + $profile_uri = trim($this->arg('profile')); - if ($feedurl == '') { - $this->showForm(_m('Empty feed URL!')); + if ($profile_uri == '') { + $this->showForm(_m('Empty remote profile URL!')); return; } - $this->feedurl = $feedurl; + $this->profile_uri = $profile_uri; - // Get the canonical feed URI and check it + // @fixme validate, normalize bla bla try { - $discover = new FeedDiscovery(); - $uri = $discover->discoverFromURL($feedurl); + $oprofile = Ostatus_profile::ensureProfile($this->profile_uri); + $this->oprofile = $oprofile; + return true; } catch (FeedSubBadURLException $e) { - $this->showForm(_m('Invalid URL or could not reach server.')); - return false; + $err = _m('Invalid URL or could not reach server.'); } catch (FeedSubBadResponseException $e) { - $this->showForm(_m('Cannot read feed; server returned error.')); - return false; + $err = _m('Cannot read feed; server returned error.'); } catch (FeedSubEmptyException $e) { - $this->showForm(_m('Cannot read feed; server returned an empty page.')); - return false; + $err = _m('Cannot read feed; server returned an empty page.'); } catch (FeedSubBadHTMLException $e) { - $this->showForm(_m('Bad HTML, could not find feed link.')); - return false; + $err = _m('Bad HTML, could not find feed link.'); } catch (FeedSubNoFeedException $e) { - $this->showForm(_m('Could not find a feed linked from this URL.')); - return false; + $err = _m('Could not find a feed linked from this URL.'); } catch (FeedSubUnrecognizedTypeException $e) { - $this->showForm(_m('Not a recognized feed type.')); - return false; + $err = _m('Not a recognized feed type.'); } catch (FeedSubException $e) { // Any new ones we forgot about - $this->showForm(_m('Bad feed URL.')); - return false; + $err = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage()); } - - $this->munger = $discover->feedMunger(); - $this->profile = $this->munger->ostatusProfile(); - if ($this->profile->huburi == '') { - $this->showForm(_m('Feed is not PuSH-enabled; cannot subscribe.')); - return false; - } - - return true; + $this->showForm($err); + return false; } function saveFeed() { if ($this->validateFeed()) { $this->preview = true; - $this->profile = Ostatus_profile::ensureProfile($this->munger); - // If not already in use, subscribe to updates via the hub - if ($this->profile->sub_start) { - common_log(LOG_INFO, __METHOD__ . ": double the fun! new sub for {$this->profile->feeduri} last subbed {$this->profile->sub_start}"); - } else { - $ok = $this->profile->subscribe(); - common_log(LOG_INFO, __METHOD__ . ": sub was $ok"); - if (!$ok) { - $this->showForm(_m('Feed subscription failed! Bad response from hub.')); - return; - } - } - // And subscribe the current user to the local profile $user = common_current_user(); - $profile = $this->profile->getProfile(); - - if ($user->isSubscribed($profile)) { - $this->showForm(_m('Already subscribed!')); - } elseif ($user->subscribeTo($profile)) { - $this->showForm(_m('Feed subscribed!')); + + if (!$this->oprofile->subscribe()) { + $this->showForm(_m("Failed to set up server-to-server subscription.")); + return; + } + + if ($this->oprofile->isGroup()) { + $group = $this->oprofile->localGroup(); + if ($user->isMember($group)) { + $this->showForm(_m('Already a member!')); + } elseif (Group_member::join($this->profile->group_id, $user->id)) { + $this->showForm(_m('Joined remote group!')); + } else { + $this->showForm(_m('Remote group join failed!')); + } } else { - $this->showForm(_m('Feed subscription failed!')); + $local = $this->oprofile->localProfile(); + if ($user->isSubscribed($local)) { + $this->showForm(_m('Already subscribed!')); + } elseif ($this->oprofile->subscribeLocalToRemote($user)) { + $this->showForm(_m('Remote user subscribed!')); + } else { + $this->showForm(_m('Remote subscription failed!')); + } } } } - - function previewFeed() + function validateAndPreview() { - $profile = $this->munger->ostatusProfile(); - $notice = $this->munger->notice(0, true); // preview - - if ($notice) { - $this->element('b', null, 'Preview of latest post from this feed:'); - - $item = new NoticeList($notice, $this); - $item->show(); - } else { - $this->element('b', null, 'No posts in this feed yet.'); + if ($this->validateFeed()) { + $this->preview = true; + $this->showForm(_m('Previewing feed:')); } } + function previewFeed() + { + $this->text('Profile preview should go here'); + } + function showScripts() + { + parent::showScripts(); + $this->autofocus('feedurl'); + } } diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php index 75ba16638b..f4dc61b7d1 100644 --- a/plugins/OStatus/actions/webfinger.php +++ b/plugins/OStatus/actions/webfinger.php @@ -66,7 +66,7 @@ class WebfingerAction extends Action 'href' => $salmon_url); // TODO - finalize where the redirect should go on the publisher - $url = common_local_url('ostatussub') . '?feed={uri}'; + $url = common_local_url('ostatussub') . '?profile={uri}'; $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe', 'template' => $url ); From 86f2f530ef60fdb601720885d493cf5b2a446e6b Mon Sep 17 00:00:00 2001 From: Eric Helgeson Date: Sat, 20 Feb 2010 21:57:05 +0000 Subject: [PATCH 062/190] Fixed incorrect link on registration successful page --- plugins/OpenID/OpenIDPlugin.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/OpenID/OpenIDPlugin.php b/plugins/OpenID/OpenIDPlugin.php index 248afe3fa8..6b35ec3e14 100644 --- a/plugins/OpenID/OpenIDPlugin.php +++ b/plugins/OpenID/OpenIDPlugin.php @@ -235,9 +235,14 @@ class OpenIDPlugin extends Plugin switch ($name) { case 'register': - $instr = '(Have an [OpenID](http://openid.net/)? ' . - 'Try our [OpenID registration]'. - '(%%action.openidlogin%%)!)'; + if (common_logged_in()) { + $instr = '(Have an [OpenID](http://openid.net/)? ' . + '[Add an OpenID to your account](%%action.openidsettings%%)!'; + } else { + $instr = '(Have an [OpenID](http://openid.net/)? ' . + 'Try our [OpenID registration]'. + '(%%action.openidlogin%%)!)'; + } break; case 'login': $instr = '(Have an [OpenID](http://openid.net/)? ' . From 9c2fe8492f7dae183e0369f8d43f124fd80e4433 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 20 Feb 2010 15:56:36 -0800 Subject: [PATCH 063/190] OStatus: send favorite/unfavorite notifications to remote authors --- classes/Notice.php | 32 ++++++++++++++++++++++++++++ plugins/OStatus/OStatusPlugin.php | 35 +++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/classes/Notice.php b/classes/Notice.php index a52cfed70c..8b8f90474d 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1104,6 +1104,38 @@ class Notice extends Memcached_DataObject return $xs->getString(); } + /** + * Returns an XML string fragment with a reference to a notice as an + * Activity Streams noun object with the given element type. + * + * Assumes that 'activity' namespace has been previously defined. + * + * @param string $element one of 'subject', 'object', 'target' + * @return string + */ + function asActivityNoun($element) + { + $xs = new XMLStringer(true); + + $xs->elementStart('activity:' . $element); + $xs->element('activity:object-type', + null, + 'http://activitystrea.ms/schema/1.0/note'); + $xs->element('id', + null, + $this->uri); + $xs->element('content', + array('type' => 'text/html'), + $this->rendered); + $xs->element('link', + array('type' => 'text/html', + 'rel' => 'permalink', + 'href' => $this->bestUrl())); + $xs->elementEnd('activity:' . $element); + + return $xs->getString(); + } + function bestUrl() { if (!empty($this->url)) { diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index e78e658a6c..4cbf78e638 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -357,4 +357,39 @@ class OStatusPlugin extends Plugin return true; } + + /** + * Notify remote users when their notices get favorited. + * + * @param Profile or User $profile of local user doing the faving + * @param Notice $notice being favored + * @return hook return value + */ + function onEndFavorNotice($profile, Notice $notice) + { + if ($profile instanceof User) { + // @fixme upstream function should clarify its parameters + $profile = $profile->getProfile(); + } + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); + if ($oprofile) { + $oprofile->notify($profile, ActivityVerb::FAVORITE, $notice); + } + } + + /** + * Notify remote users when their notices get de-favorited. + * + * @param Profile or User $profile of local user doing the de-faving + * @param Notice $notice being favored + * @return hook return value + */ + function onEndDisfavorNotice(Profile $profile, Notice $notice) + { + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); + if ($oprofile) { + $oprofile->notify($profile, ActivityVerb::UNFAVORITE, $notice); + } + } + } From 145a19954f6f993714cb8b65aaf9d54996503664 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 20 Feb 2010 16:45:30 -0800 Subject: [PATCH 064/190] OStatus: Salmon favorite & unfavorite events now handled --- plugins/OStatus/actions/usersalmon.php | 77 +++++++++++++++----------- plugins/OStatus/lib/salmonaction.php | 3 + 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 4363488ddc..20c6c2942a 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -131,10 +131,51 @@ class UsersalmonAction extends SalmonAction function handleFavorite() { - // WORST VARIABLE NAME EVER - $object = $this->act->object; + $notice = $this->getNotice($this->act->object); + $profile = $this->ensureProfile()->localProfile(); - switch ($this->act->object->type) { + $old = Fave::pkeyGet(array('user_id' => $profile->id, + 'notice_id' => $notice->id)); + + if (!empty($old)) { + throw new ClientException("We already know that's a fave!"); + } + + if (!Fave::addNew($profile, $notice)) { + throw new ClientException("Could not save new favorite."); + } + } + + /** + * Remote user doesn't like one of our posts after all! + * Confirm the post is ours, and save a local favorite event. + */ + function handleUnfavorite() + { + $notice = $this->getNotice($this->act->object); + $profile = $this->ensureProfile()->localProfile(); + + $fave = Fave::pkeyGet(array('user_id' => $profile->id, + 'notice_id' => $notice->id)); + if (empty($fave)) { + throw new ClientException("Notice wasn't favorited!"); + } + + $fave->delete(); + } + + /** + * @param ActivityObject $object + * @return Notice + * @throws ClientException on invalid input + */ + function getNotice($object) + { + if (!$object) { + throw new ClientException("Can't favorite/unfavorite without an object."); + } + + switch ($object->type) { case ActivityObject::ARTICLE: case ActivityObject::BLOGENTRY: case ActivityObject::NOTE: @@ -155,35 +196,7 @@ class UsersalmonAction extends SalmonAction throw new ClientException("Notice with ID $object->id not posted by $this->user->id."); } - $profile = $this->ensureProfile(); - - $old = Fave::pkeyGet(array('user_id' => $profile->id, - 'notice_id' => $notice->id)); - - if (!empty($old)) { - throw new ClientException("We already know that's a fave!"); - } - - $fave = new Fave(); - - // @fixme need to change this attribute name, maybe references - $fave->user_id = $profile->id; - $fave->notice_id = $notice->id; - - $result = $fave->insert(); - - if (!$result) { - common_log_db_error($fave, 'INSERT', __FILE__); - throw new ServerException('Could not save new favorite.'); - } - } - - /** - * Remote user doesn't like one of our posts after all! - * Confirm the post is ours, and save a local favorite event. - */ - function handleUnfavorite() - { + return $notice; } } diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 7085e4583e..c838905077 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -81,6 +81,9 @@ class SalmonAction extends Action case ActivityVerb::FAVORITE: $this->handleFavorite(); break; + case ActivityVerb::UNFAVORITE: + $this->handleUnfavorite(); + break; case ActivityVerb::FOLLOW: case ActivityVerb::FRIEND: $this->handleFollow(); From 96c6019638f6407b38fbc5a45485a3797af47adb Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 19:58:20 -0500 Subject: [PATCH 065/190] Add support for favor and disfavor notification Added support for favoring and disfavoring in OStatusPlugin. Needed to represent the Notice as an activity:object, so added some code for that in lib/activity.php. Also, made some small changes to OStatusPlugin so it handled having a non-default argument $object correctly. --- plugins/OStatus/OStatusPlugin.php | 50 ++++++++++++++++--- plugins/OStatus/classes/Ostatus_profile.php | 6 +-- plugins/OStatus/lib/activity.php | 55 ++++++++++++++++++++- 3 files changed, 98 insertions(+), 13 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 9e6d03177f..98e048c14c 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -255,7 +255,7 @@ class OStatusPlugin extends Plugin { if ($user instanceof Profile) { $profile = $user; - } else if ($user instanceof Profile) { + } else if ($user instanceof User) { $profile = $user->getProfile(); } $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); @@ -353,30 +353,64 @@ class OStatusPlugin extends Plugin // We have a local user subscribing to a remote profile; make the // magic happen! - $oprofile->notify($subscriber, ActivityVerb::FOLLOW); + $oprofile->notify($subscriber, ActivityVerb::FOLLOW, $oprofile); return true; } - function onEndUnsubscribe($subscriber, $other) + function onEndFavor($profile, $notice) { - $user = User::staticGet('id', $subscriber->id); + // is the favorer a local user? + + $user = User::staticGet('id', $profile->id); if (empty($user)) { return true; } - $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + // is the author an OStatus remote user? + + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); if (empty($oprofile)) { return true; } - // We have a local user subscribing to a remote profile; make the - // magic happen! + // Local user faved an Ostatus profile's notice; notify them! - $oprofile->notify($subscriber, ActivityVerb::UNFOLLOW); + $obj = ActivityObject::fromNotice($notice); + $oprofile->notify($profile, + ActivityVerb::FAVORITE, + $obj->asString()); + return true; + } + + function onEndDisfavor($profile, $notice) + { + // is the favorer a local user? + + $user = User::staticGet('id', $profile->id); + + if (empty($user)) { + return true; + } + + // is the author an OStatus remote user? + + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); + + if (empty($oprofile)) { + return true; + } + + // Local user faved an Ostatus profile's notice; notify them! + + $obj = ActivityObject::fromNotice($notice); + + $oprofile->notify($profile, + ActivityVerb::UNFAVORITE, + $obj->asString()); return true; } } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 4dd5652886..5bd899bc46 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -307,7 +307,7 @@ class Ostatus_profile extends Memcached_DataObject * * @param Profile $actor * @param $verb eg Activity::SUBSCRIBE or Activity::JOIN - * @param $object object of the action; if null, the remote entity itself is assumed + * @param string $object object of the action; if null, the remote entity itself is assumed */ public function notify($actor, $verb, $object=null) { @@ -319,7 +319,7 @@ class Ostatus_profile extends Memcached_DataObject throw new ServerException("Invalid actor passed to " . __METHOD__ . ": " . $type); } if ($object == null) { - $object = $this; + $object = $this->asActivityNoun('object'); } if ($this->salmonuri) { $text = 'update'; // @fixme @@ -345,7 +345,7 @@ class Ostatus_profile extends Memcached_DataObject $entry->element('activity:verb', null, $verb); $entry->raw($actor->asAtomAuthor()); $entry->raw($actor->asActivityActor()); - $entry->raw($object->asActivityNoun('object')); + $entry->raw($object); $entry->elementEnd('entry'); $xml = $entry->getString(); diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 5bc8f78e52..6d15f85b0d 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -199,7 +199,7 @@ class ActivityObject public $link; public $source; - /** + /** * Constructor * * This probably needs to be refactored @@ -209,8 +209,12 @@ class ActivityObject * @param DOMElement $element DOM thing to turn into an Activity thing */ - function __construct($element) + function __construct($element = null) { + if (empty($element)) { + return; + } + $this->element = $element; if ($element->tagName == 'author') { @@ -279,6 +283,53 @@ class ActivityObject } } } + + static fromNotice($notice) + { + $object = new ActivityObject(); + + $object->type = ActivityObject::NOTE; + + $object->id = $notice->uri; + $object->title = $notice->content; + $object->content = $notice->rendered; + $object->link = $notice->bestUrl(); + + return $object; + } + + function asString($tag='activity:object') + { + $xs = new XMLStringer(true); + + $xs->elementStart($tag); + + $xs->element('activity:object-type', null, $this->type); + + $xs->element(self::ID, null, $this->id); + + if (!empty($this->title)) { + $xs->element(self::TITLE, null, $this->title); + } + + if (!empty($this->summary)) { + $xs->element(self::SUMMARY, null, $this->summary); + } + + if (!empty($this->content)) { + // XXX: assuming HTML content here + $xs->element(self::CONTENT, array('type' => 'html'), $this->content); + } + + if (!empty($this->link)) { + $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html'), + $this->content); + } + + $xs->elementEnd($tag); + + return $xs->getString(); + } } /** From a3de4caf497b5d4a4d34477279fefe4c4d7ad8e2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 20:31:06 -0500 Subject: [PATCH 066/190] make sure argument to Fave::addNew() is a profile --- actions/favor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/favor.php b/actions/favor.php index 2aeb1da613..afca9768ae 100644 --- a/actions/favor.php +++ b/actions/favor.php @@ -79,7 +79,7 @@ class FavorAction extends Action $this->clientError(_('This notice is already a favorite!')); return; } - $fave = Fave::addNew($user, $notice); + $fave = Fave::addNew($user->getProfile(), $notice); if (!$fave) { $this->serverError(_('Could not create favorite.')); return; From 0c62c686756de0752cdd44b63c10cf6e4047860f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 20:34:29 -0500 Subject: [PATCH 067/190] do some double-checks on favor and disfavor handlers in OStatusPlugin --- plugins/OStatus/OStatusPlugin.php | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 5081c4d983..29799b0dc1 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -365,16 +365,21 @@ class OStatusPlugin extends Plugin * @param Notice $notice being favored * @return hook return value */ - function onEndFavorNotice($profile, Notice $notice) + function onEndFavorNotice(Profile $profile, Notice $notice) { - if ($profile instanceof User) { - // @fixme upstream function should clarify its parameters - $profile = $profile->getProfile(); + $user = User::staticGet('id', $profile->id); + + if (empty($user)) { + return true; } + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); + if ($oprofile) { $oprofile->notify($profile, ActivityVerb::FAVORITE, $notice); } + + return true; } /** @@ -386,10 +391,18 @@ class OStatusPlugin extends Plugin */ function onEndDisfavorNotice(Profile $profile, Notice $notice) { + $user = User::staticGet('id', $profile->id); + + if (empty($user)) { + return true; + } + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); + if ($oprofile) { $oprofile->notify($profile, ActivityVerb::UNFAVORITE, $notice); } - } + return true; + } } From 6f1ccfc5770776c39bfe28543629e63a566ab541 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Feb 2010 20:36:54 -0500 Subject: [PATCH 068/190] Subscription::start() should be enough, right? --- plugins/OStatus/actions/usersalmon.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 20c6c2942a..020ca597cd 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -101,7 +101,8 @@ class UsersalmonAction extends SalmonAction $oprofile = $this->ensureProfile(); if ($oprofile) { common_log(LOG_INFO, "Setting up subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); - $oprofile->subscribeRemoteToLocal($this->user); + Subscription::start($oprofile->localProfile(), + $this->user->getProfile()); } else { common_log(LOG_INFO, "Can't set up subscription from remote; missing profile."); } From 5df61141d28426329d2f4e50e61c131d43d1e405 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 20 Feb 2010 18:25:40 -0800 Subject: [PATCH 069/190] OStatus: fix regressions from merge --- plugins/OStatus/classes/Ostatus_profile.php | 4 ++-- plugins/OStatus/lib/activity.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 5bd899bc46..d9cb7a6e1b 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -319,7 +319,7 @@ class Ostatus_profile extends Memcached_DataObject throw new ServerException("Invalid actor passed to " . __METHOD__ . ": " . $type); } if ($object == null) { - $object = $this->asActivityNoun('object'); + $object = $this; } if ($this->salmonuri) { $text = 'update'; // @fixme @@ -345,7 +345,7 @@ class Ostatus_profile extends Memcached_DataObject $entry->element('activity:verb', null, $verb); $entry->raw($actor->asAtomAuthor()); $entry->raw($actor->asActivityActor()); - $entry->raw($object); + $entry->raw($object->asActivityNoun('object')); $entry->elementEnd('entry'); $xml = $entry->getString(); diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 6d15f85b0d..7563488b70 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -284,7 +284,7 @@ class ActivityObject } } - static fromNotice($notice) + static function fromNotice($notice) { $object = new ActivityObject(); From 229f9bd069a25af9635a9eaaa822a614bf6e9348 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 09:15:57 -0500 Subject: [PATCH 070/190] more complete content retrieval in ActivityObject::__construct() --- plugins/OStatus/lib/activity.php | 67 ++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 6d15f85b0d..5f174d86f6 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -183,6 +183,8 @@ class ActivityObject const TITLE = 'title'; const SUMMARY = 'summary'; const CONTENT = 'content'; + const TYPE = 'type'; + const SRC = 'src'; const ID = 'id'; const SOURCE = 'source'; @@ -199,7 +201,7 @@ class ActivityObject public $link; public $source; - /** + /** * Constructor * * This probably needs to be refactored @@ -243,10 +245,11 @@ class ActivityObject $this->id = $this->_childContent($element, self::ID); $this->title = $this->_childContent($element, self::TITLE); $this->summary = $this->_childContent($element, self::SUMMARY); - $this->content = $this->_childContent($element, self::CONTENT); $this->source = $this->_getSource($element); + $this->content = $this->_getContent($element); + $this->link = ActivityUtils::getPermalink($element); // XXX: grab PoCo stuff @@ -284,7 +287,65 @@ class ActivityObject } } - static fromNotice($notice) + /** + * Get the content of an atom:entry-like object + * + * @param DOMElement $element The element to examine. + * + * @return string unencoded HTML content of the element, like "This -< is HTML." + * + * @todo handle remote content + * @todo handle embedded XML mime types + * @todo handle base64-encoded non-XML and non-text mime types + */ + + private function _getContent($element) + { + $contentEl = ActivityUtils::child($element, self::CONTENT); + + if (!empty($contentEl)) { + + $src = $contentEl->getAttribute(self::SRC); + + if (!empty($src)) { + throw new ClientException(_("Can't handle remote content yet.")); + } + + $type = $contentEl->getAttribute(self::TYPE); + + // slavishly following http://atompub.org/rfc4287.html#rfc.section.4.1.3.3 + + if ($type == 'text') { + return $contentEl->textContent; + } else if ($type == 'html') { + $text = $contentEl->textContent; + return htmlspecialchars_decode($text, ENT_QUOTES); + } else if ($type == 'xhtml') { + $divEl = ActivityUtils::child($contentEl, 'div'); + if (empty($divEl)) { + return null; + } + $doc = $divEl->ownerDocument; + $text = ''; + $children = $divEl->childNodes; + + for ($i = 0; $i < $children->length; $i++) { + $child = $children->item($i); + $text .= $doc->saveXML($child); + } + return trim($text); + } else if (in_array(array('text/xml', 'application/xml'), $type) || + preg_match('#(+|/)xml$#', $type)) { + throw new ClientException(_("Can't handle embedded XML content yet.")); + } else if (strncasecmp($type, 'text/', 5)) { + return $contentEl->textContent; + } else { + throw new ClientException(_("Can't handle embedded Base64 content yet.")); + } + } + } + + static function fromNotice($notice) { $object = new ActivityObject(); From 6169d8a877fb0e76ee17187f74a6747fe7f2c97d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 09:16:27 -0500 Subject: [PATCH 071/190] saving notices in salmon actions --- plugins/OStatus/lib/salmonaction.php | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index c838905077..41e8322e89 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -231,4 +231,49 @@ class SalmonAction extends Action return null; } } + + function saveNotice() + { + $oprofile = $this->ensureProfile(); + + // Get (safe!) HTML and text versions of the content + + require_once(INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php'); + + $html = $this->act->object->content; + + $rendered = HTMLPurifier::purify($html); + $content = html_entity_decode(strip_tags($rendered)); + + $options = array('is_local' => Notice::REMOTE_OMB, + 'uri' => $this->act->object->id, + 'url' => $this->act->object->link, + 'rendered' => $rendered); + + if (!empty($this->act->context->location)) { + $options['lat'] = $location->lat; + $options['lon'] = $location->lon; + if ($location->location_id) { + $options['location_ns'] = $location->location_ns; + $options['location_id'] = $location->location_id; + } + } + + if (!empty($this->act->context->replyToID)) { + $orig = Notice::staticGet('uri', + $this->act->context->replyToID); + if (!empty($orig)) { + $options['reply_to'] = $orig->id; + } + } + + if (!empty($this->act->time)) { + $options['created'] = common_sql_time($this->act->time); + } + + return Notice::saveNew($oprofile->profile_id, + $content, + 'ostatus+salmon', + $options); + } } From 9498a164805892a8af17311f7e7697b132524990 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 09:17:00 -0500 Subject: [PATCH 072/190] Notice::saveNew() accepts url and rendered options --- classes/Notice.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index 8b8f90474d..0051cf8851 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -194,6 +194,7 @@ class Notice extends Memcached_DataObject */ static function saveNew($profile_id, $content, $source, $options=null) { $defaults = array('uri' => null, + 'url' => null, 'reply_to' => null, 'repeat_of' => null); @@ -256,9 +257,16 @@ class Notice extends Memcached_DataObject } $notice->content = $final; - $notice->rendered = common_render_content($final, $notice); + + if (!empty($rendered)) { + $notice->rendered = $rendered; + } else { + $notice->rendered = common_render_content($final, $notice); + } + $notice->source = $source; $notice->uri = $uri; + $notice->url = $url; // Handle repeat case From 4a4c34de3221eb8000e911addad039cd170faaa1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 09:17:35 -0500 Subject: [PATCH 073/190] Save posted notices in usersalmon --- plugins/OStatus/actions/usersalmon.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 020ca597cd..12c74798f2 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -87,8 +87,7 @@ class UsersalmonAction extends SalmonAction throw new ClientException("Not to anyone in reply to anything!"); } - $profile = $this->ensureProfile(); - // @fixme do something with the post + $this->saveNotice(); } /** From 7f471bde231071e3512f203ceca4b830ac2204a1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 09:17:52 -0500 Subject: [PATCH 074/190] more tests for Activity parsing --- plugins/OStatus/tests/ActivityParseTests.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/OStatus/tests/ActivityParseTests.php b/plugins/OStatus/tests/ActivityParseTests.php index 35b4b0f9d7..d7305dedea 100644 --- a/plugins/OStatus/tests/ActivityParseTests.php +++ b/plugins/OStatus/tests/ActivityParseTests.php @@ -22,8 +22,15 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $act = new Activity($dom->documentElement); $this->assertFalse(empty($act)); + $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'); } public function testExample3() @@ -84,6 +91,10 @@ 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, + '@evan now is the time for all good men to come to the aid of their country. #'); + $this->assertFalse(empty($act->actor)); } } From e9d22138efb059fd701d332815d63e65b09c5282 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 09:23:51 -0500 Subject: [PATCH 075/190] permalink on a note represented by rel=alternate --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index 0051cf8851..7e524cacd4 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1137,7 +1137,7 @@ class Notice extends Memcached_DataObject $this->rendered); $xs->element('link', array('type' => 'text/html', - 'rel' => 'permalink', + 'rel' => 'alternate', 'href' => $this->bestUrl())); $xs->elementEnd('activity:' . $element); From ff2efd314f15bf5e4b42fe02d56217a996a7c692 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 10:50:51 -0500 Subject: [PATCH 076/190] let activities generate their own XML --- plugins/OStatus/lib/activity.php | 192 +++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 63 deletions(-) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 5f174d86f6..5da6c75856 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -55,6 +55,9 @@ class ActivityUtils const TYPE = 'type'; const HREF = 'href'; + const CONTENT = 'content'; + const SRC = 'src'; + /** * Get the permalink for an Activity object * @@ -139,6 +142,64 @@ class ActivityUtils return $el->textContent; } } + + /** + * Get the content of an atom:entry-like object + * + * @param DOMElement $element The element to examine. + * + * @return string unencoded HTML content of the element, like "This -< is HTML." + * + * @todo handle remote content + * @todo handle embedded XML mime types + * @todo handle base64-encoded non-XML and non-text mime types + */ + + static function getContent($element) + { + $contentEl = ActivityUtils::child($element, self::CONTENT); + + if (!empty($contentEl)) { + + $src = $contentEl->getAttribute(self::SRC); + + if (!empty($src)) { + throw new ClientException(_("Can't handle remote content yet.")); + } + + $type = $contentEl->getAttribute(self::TYPE); + + // slavishly following http://atompub.org/rfc4287.html#rfc.section.4.1.3.3 + + if ($type == 'text') { + return $contentEl->textContent; + } else if ($type == 'html') { + $text = $contentEl->textContent; + return htmlspecialchars_decode($text, ENT_QUOTES); + } else if ($type == 'xhtml') { + $divEl = ActivityUtils::child($contentEl, 'div'); + if (empty($divEl)) { + return null; + } + $doc = $divEl->ownerDocument; + $text = ''; + $children = $divEl->childNodes; + + for ($i = 0; $i < $children->length; $i++) { + $child = $children->item($i); + $text .= $doc->saveXML($child); + } + return trim($text); + } else if (in_array(array('text/xml', 'application/xml'), $type) || + preg_match('#(+|/)xml$#', $type)) { + throw new ClientException(_("Can't handle embedded XML content yet.")); + } else if (strncasecmp($type, 'text/', 5)) { + return $contentEl->textContent; + } else { + throw new ClientException(_("Can't handle embedded Base64 content yet.")); + } + } + } } /** @@ -182,9 +243,6 @@ class ActivityObject const TITLE = 'title'; const SUMMARY = 'summary'; - const CONTENT = 'content'; - const TYPE = 'type'; - const SRC = 'src'; const ID = 'id'; const SOURCE = 'source'; @@ -248,7 +306,7 @@ class ActivityObject $this->source = $this->_getSource($element); - $this->content = $this->_getContent($element); + $this->content = ActivityUtils::getContent($element); $this->link = ActivityUtils::getPermalink($element); @@ -287,64 +345,6 @@ class ActivityObject } } - /** - * Get the content of an atom:entry-like object - * - * @param DOMElement $element The element to examine. - * - * @return string unencoded HTML content of the element, like "This -< is HTML." - * - * @todo handle remote content - * @todo handle embedded XML mime types - * @todo handle base64-encoded non-XML and non-text mime types - */ - - private function _getContent($element) - { - $contentEl = ActivityUtils::child($element, self::CONTENT); - - if (!empty($contentEl)) { - - $src = $contentEl->getAttribute(self::SRC); - - if (!empty($src)) { - throw new ClientException(_("Can't handle remote content yet.")); - } - - $type = $contentEl->getAttribute(self::TYPE); - - // slavishly following http://atompub.org/rfc4287.html#rfc.section.4.1.3.3 - - if ($type == 'text') { - return $contentEl->textContent; - } else if ($type == 'html') { - $text = $contentEl->textContent; - return htmlspecialchars_decode($text, ENT_QUOTES); - } else if ($type == 'xhtml') { - $divEl = ActivityUtils::child($contentEl, 'div'); - if (empty($divEl)) { - return null; - } - $doc = $divEl->ownerDocument; - $text = ''; - $children = $divEl->childNodes; - - for ($i = 0; $i < $children->length; $i++) { - $child = $children->item($i); - $text .= $doc->saveXML($child); - } - return trim($text); - } else if (in_array(array('text/xml', 'application/xml'), $type) || - preg_match('#(+|/)xml$#', $type)) { - throw new ClientException(_("Can't handle embedded XML content yet.")); - } else if (strncasecmp($type, 'text/', 5)) { - return $contentEl->textContent; - } else { - throw new ClientException(_("Can't handle embedded Base64 content yet.")); - } - } - } - static function fromNotice($notice) { $object = new ActivityObject(); @@ -359,6 +359,18 @@ class ActivityObject return $object; } + static function fromProfile($profile) + { + $object = new ActivityObject(); + + $object->type = ActivityObject::PERSON; + $object->id = $profile->getUri(); + $object->title = $this->getBestName(); + $object->link = $profile->profileurl; + + return $object; + } + function asString($tag='activity:object') { $xs = new XMLStringer(true); @@ -550,6 +562,11 @@ class Activity public $entry; // the source entry public $feed; // the source feed + public $summary; // summary of activity + public $content; // HTML content of activity + public $id; // ID of the activity + public $title; // title of the activity + /** * Turns a regular old Atom into a magical activity * @@ -557,8 +574,12 @@ class Activity * @param DOMElement $feed Atom feed, for context */ - function __construct($entry, $feed = null) + function __construct($entry = null, $feed = null) { + if (is_null($entry)) { + return; + } + $this->entry = $entry; $this->feed = $feed; @@ -629,6 +650,10 @@ class Activity if (!empty($targetEl)) { $this->target = new ActivityObject($targetEl); } + + $this->summary = ActivityUtils::childContent($entry, 'summary'); + $this->id = ActivityUtils::childContent($entry, 'id'); + $this->content = ActivityUtils::getContent($entry); } /** @@ -642,6 +667,47 @@ class Activity return null; } + function asString($namespace=false) + { + $xs = new XMLStringer(true); + + if ($namespace) { + $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', + 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', + 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); + } else { + $attrs = array(); + } + + $xs->elementStart('entry', $attrs); + + $xs->element('id', null, $this->id); + $xs->element('title', null, $this->title); + $xs->element('published', null, common_date_iso8601($this->time)); + $xs->element('content', array('type' => 'html'), $this->content); + + if (!empty($this->summary)) { + $xs->element('summary', null, $this->summary); + } + + if (!empty($this->link)) { + $xs->element('link', array('rel' => 'alternate', + 'type' => 'text/html'), + $this->link); + } + + // XXX: add context + // XXX: add target + + $xs->raw($this->actor->asString()); + $xs->element('activity:verb', null, $this->verb); + $xs->raw($this->object->asString()); + + $xs->elementEnd('entry'); + + return $xs->getString(); + } + private function _child($element, $tag, $namespace=self::SPEC) { return ActivityUtils::child($element, $tag, $namespace); From 4e90bd34e9aff1abd97a92b62fc7c48bf1ee5a9c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 10:53:11 -0500 Subject: [PATCH 077/190] activity notification in Ostatus_profile --- plugins/OStatus/classes/Ostatus_profile.php | 31 +++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index d9cb7a6e1b..55f347a029 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -305,9 +305,9 @@ class Ostatus_profile extends Memcached_DataObject * Send an Activity Streams notification to the remote Salmon endpoint, * if so configured. * - * @param Profile $actor - * @param $verb eg Activity::SUBSCRIBE or Activity::JOIN - * @param string $object object of the action; if null, the remote entity itself is assumed + * @param Profile $actor Actor who did the activity + * @param string $verb Activity::SUBSCRIBE or Activity::JOIN + * @param Object $object object of the action; must define asActivityNoun($tag) */ public function notify($actor, $verb, $object=null) { @@ -322,11 +322,12 @@ class Ostatus_profile extends Memcached_DataObject $object = $this; } if ($this->salmonuri) { - $text = 'update'; // @fixme - $id = 'tag:' . common_config('site', 'server') . - ':' . $verb . - ':' . $actor->id . - ':' . time(); // @fixme + + $text = 'update'; + $id = TagURI::mint('%s:%s:%s', + $verb, + $actor->getURI(), + common_date_iso8601(date())); // @fixme consolidate all these NS settings somewhere $attributes = array('xmlns' => Activity::ATOM, @@ -356,6 +357,20 @@ class Ostatus_profile extends Memcached_DataObject } } + public function notifyActivity($activity) + { + if ($this->salmonuri) { + + $xml = $activity->asString(); + + $salmon = new Salmon(); // ? + + $salmon->post($this->salmonuri, $xml); + } + + return; + } + function getBestName() { if ($this->isGroup()) { From df7c6b37c8b8f548a56193181acd5b2d8ee9bd9e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 10:53:32 -0500 Subject: [PATCH 078/190] use notifyActivity() for notifications in OStatusPlugin --- plugins/OStatus/OStatusPlugin.php | 124 ++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 25 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 29799b0dc1..3aaa769db4 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -251,27 +251,47 @@ class OStatusPlugin extends Plugin * @param Profile $other * @return hook return value */ - function onEndUnsubscribe($user, $other) + function onEndUnsubscribe($profile, $other) { - if ($user instanceof Profile) { - $profile = $user; - } else if ($user instanceof User) { - $profile = $user->getProfile(); - } - $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); - if ($oprofile) { - // Notify the remote server of the unsub, if supported. - $oprofile->notify($profile, ActivityVerb::UNFOLLOW, $oprofile); + $user = User::staticGet('id', $profile->id); - // Drop the PuSH subscription if there are no other subscribers. - $sub = new Subscription(); - $sub->subscribed = $other->id; - $sub->limit(1); - if (!$sub->find(true)) { - common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri"); - $oprofile->unsubscribe(); - } + if (empty($user)) { + return true; } + + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + + if (empty($oprofile)) { + return true; + } + + // Drop the PuSH subscription if there are no other subscribers. + + if ($other->subscriberCount() == 0) { + common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri"); + $oprofile->unsubscribe(); + } + + $act = new Activity(); + + $act->verb = ActivityVerb::UNFOLLOW; + + $act->id = TagURI::mint('unfollow:%d:%d:%s', + $profile->id, + $other->id, + common_date_iso8601(time())); + + $act->time = time(); + $act->title = _("Unfollow"); + $act->content = sprintf(_("%s stopped following %s."), + $profile->getBestName(), + $other->getBestName()); + + $act->actor = ActivityObject::fromProfile($subscriber); + $act->object = ActivityObject::fromProfile($other); + + $oprofile->notifyActivity($act); + return true; } @@ -350,10 +370,25 @@ class OStatusPlugin extends Plugin return true; } - // We have a local user subscribing to a remote profile; make the - // magic happen! + $act = new Activity(); - $oprofile->notify($subscriber, ActivityVerb::FOLLOW, $oprofile); + $act->verb = ActivityVerb::FOLLOW; + + $act->id = TagURI::mint('follow:%d:%d:%s', + $subscriber->id, + $other->id, + common_date_iso8601(time())); + + $act->time = time(); + $act->title = _("Follow"); + $act->content = sprintf(_("%s is now following %s."), + $subscriber->getBestName(), + $other->getBestName()); + + $act->actor = ActivityObject::fromProfile($subscriber); + $act->object = ActivityObject::fromProfile($other); + + $oprofile->notifyActivity($act); return true; } @@ -365,6 +400,7 @@ class OStatusPlugin extends Plugin * @param Notice $notice being favored * @return hook return value */ + function onEndFavorNotice(Profile $profile, Notice $notice) { $user = User::staticGet('id', $profile->id); @@ -375,10 +411,29 @@ class OStatusPlugin extends Plugin $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); - if ($oprofile) { - $oprofile->notify($profile, ActivityVerb::FAVORITE, $notice); + if (empty($oprofile)) { + return true; } + $act = new Activity(); + + $act->verb = ActivityVerb::FAVORITE; + $act->id = TagURI::mint('favor:%d:%d:%s', + $profile->id, + $notice->id, + common_date_iso8601(time())); + + $act->time = time(); + $act->title = _("Favor"); + $act->content = sprintf(_("%s marked notice %s as a favorite."), + $profile->getBestName(), + $notice->uri); + + $act->actor = ActivityObject::fromProfile($profile); + $act->object = ActivityObject::fromNotice($notice); + + $oprofile->notifyActivity($act); + return true; } @@ -389,6 +444,7 @@ class OStatusPlugin extends Plugin * @param Notice $notice being favored * @return hook return value */ + function onEndDisfavorNotice(Profile $profile, Notice $notice) { $user = User::staticGet('id', $profile->id); @@ -399,10 +455,28 @@ class OStatusPlugin extends Plugin $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); - if ($oprofile) { - $oprofile->notify($profile, ActivityVerb::UNFAVORITE, $notice); + if (empty($oprofile)) { + return true; } + $act = new Activity(); + + $act->verb = ActivityVerb::UNFAVORITE; + $act->id = TagURI::mint('disfavor:%d:%d:%s', + $profile->id, + $notice->id, + common_date_iso8601(time())); + $act->time = time(); + $act->title = _("Disfavor"); + $act->content = sprintf(_("%s marked notice %s as no longer a favorite."), + $profile->getBestName(), + $notice->uri); + + $act->actor = ActivityObject::fromProfile($profile); + $act->object = ActivityObject::fromNotice($notice); + + $oprofile->notifyActivity($act); + return true; } } From 727773cdfa8f229babbfe8a620645f2f4db9bbd8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 11:24:04 -0500 Subject: [PATCH 079/190] redirect ostatussub if not logged in --- plugins/OStatus/actions/ostatussub.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 5244031437..bbbd1b7e69 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -58,7 +58,6 @@ class OStatusSubAction extends Action $this->showPage(); } - /** * Content area of the page * @@ -116,7 +115,18 @@ class OStatusSubAction extends Action function prepare($args) { parent::prepare($args); + + if (!common_logged_in()) { + // XXX: selfURL() didn't work. :< + common_set_returnto($_SERVER['REQUEST_URI']); + if (Event::handle('RedirectToLogin', array($this, null))) { + common_redirect(common_local_url('login'), 303); + } + return false; + } + $this->profile_uri = $this->arg('profile'); + return true; } @@ -173,13 +183,13 @@ class OStatusSubAction extends Action function validateFeed() { $profile_uri = trim($this->arg('profile')); - + if ($profile_uri == '') { $this->showForm(_m('Empty remote profile URL!')); return; } $this->profile_uri = $profile_uri; - + // @fixme validate, normalize bla bla try { $oprofile = Ostatus_profile::ensureProfile($this->profile_uri); From 09e2d181be3b72b1d8134273b9fdfa280895627c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 12:54:52 -0500 Subject: [PATCH 080/190] remove unused profile code from salmonaction --- plugins/OStatus/lib/salmonaction.php | 71 ---------------------------- 1 file changed, 71 deletions(-) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 41e8322e89..abd8d4c833 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -161,77 +161,6 @@ class SalmonAction extends Action return Ostatus_profile::ensureActorProfile($this->act); } - /** - * @fixme merge into Ostatus_profile::ensureActorProfile and friends - */ - function createProfile() - { - $actor = $this->act->actor; - - $profile = new Profile(); - - $profile->nickname = $this->nicknameFromURI($actor->id); - - if (empty($profile->nickname)) { - $profile->nickname = common_nicknamize($actor->title); - } - - $profile->fullname = $actor->title; - $profile->bio = $actor->summary; // XXX: is that right? - $profile->profileurl = $actor->link; // XXX: is that right? - $profile->created = common_sql_now(); - - $id = $profile->insert(); - - if (empty($id)) { - common_log_db_error($profile, 'INSERT', __FILE__); - throw new Exception("Couldn't save new profile for $actor->id\n"); - } - - // XXX: add avatars - - $op = new Ostatus_profile(); - - $op->profile_id = $id; - $op->homeuri = $actor->id; - $op->created = $profile->created; - - // XXX: determine feed URI from source or Webfinger or whatever - - $id = $op->insert(); - - if (empty($id)) { - common_log_db_error($op, 'INSERT', __FILE__); - throw new Exception("Couldn't save new ostatus profile for $actor->id\n"); - } - - return $profile; - } - - /** - * @fixme should be merged into Ostatus_profile - */ - function nicknameFromURI($uri) - { - preg_match('/(\w+):/', $uri, $matches); - - $protocol = $matches[1]; - - switch ($protocol) { - case 'acct': - case 'mailto': - if (preg_match("/^$protocol:(.*)?@.*\$/", $uri, $matches)) { - return common_canonical_nickname($matches[1]); - } - return null; - case 'http': - return common_url_to_nickname($uri); - break; - default: - return null; - } - } - function saveNotice() { $oprofile = $this->ensureProfile(); From d372a352ec16f7fabd9059e283c98bd45d7272f0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 12:55:40 -0500 Subject: [PATCH 081/190] make avatar attribute explicit for ActivityObject --- plugins/OStatus/lib/activity.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index 5da6c75856..ea1303f199 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -258,6 +258,7 @@ class ActivityObject public $content; public $link; public $source; + public $avatar; /** * Constructor From 1a86bf9c65d2579d9245c6edcc968fed3d674f39 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 12:56:46 -0500 Subject: [PATCH 082/190] try different ways to get a profile from a feed --- plugins/OStatus/classes/Ostatus_profile.php | 177 +++++++++++++++----- 1 file changed, 132 insertions(+), 45 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 55f347a029..793d451125 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -537,18 +537,58 @@ class Ostatus_profile extends Memcached_DataObject throw new FeedSubNoHubException(); } - // Ok this is going to be a terrible hack! - // Won't be suitable for groups, empty feeds, or getting - // info that's only available on the profile page. - $entries = $discover->feed->getElementsByTagNameNS(Activity::ATOM, 'entry'); - if (!$entries || $entries->length == 0) { - throw new FeedSubException('empty feed'); + // Try to get a profile from the feed activity:subject + + $feedEl = $discover->feed->documentElement; + + $subject = ActivityUtils::child($feedEl, Activity::SUBJECT, Activity::SPEC); + + if (!empty($subject)) { + $subjObject = new ActivityObject($subject); + return self::ensureActivityObjectProfile($subjObject, $feeduri, $salmonuri); } - $first = new Activity($entries->item(0), $discover->feed); - return self::ensureActorProfile($first, $feeduri, $salmonuri); + + // Otherwise, try the feed author + + $author = ActivityUtils::child($feedEl, Activity::AUTHOR, Activity::ATOM); + + if (!empty($author)) { + $authorObject = new ActivityObject($author); + return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri); + } + + // Sheesh. Not a very nice feed! Let's try fingerpoken in the + // entries. + + $entries = $discover->feed->getElementsByTagNameNS(Activity::ATOM, 'entry'); + + if (!empty($entries) && $entries->length > 0) { + + $entry = $entries->item(0); + + $actor = ActivityUtils::child($entry, Activity::ACTOR, Activity::SPEC); + + if (!empty($actor)) { + $actorObject = new ActivityObject($actor); + return self::ensureActivityObjectProfile($actorObject, $feeduri, $salmonuri); + + } + + $author = ActivityUtils::child($entry, Activity::AUTHOR, Activity::ATOM); + + if (!empty($author)) { + $authorObject = new ActivityObject($author); + return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri); + } + } + + // XXX: make some educated guesses here + + throw new FeedSubException("Can't find enough profile information to make a feed."); } /** + * * Download and update given avatar image * @param string $url * @throws Exception in various failure cases @@ -581,6 +621,12 @@ class Ostatus_profile extends Memcached_DataObject } } + protected static function getActivityObjectAvatar($object) + { + // XXX: go poke around in the feed + return $object->avatar; + } + /** * Get an appropriate avatar image source URL, if available. * @@ -588,6 +634,7 @@ class Ostatus_profile extends Memcached_DataObject * @param DOMElement $feed * @return string */ + protected static function getAvatar($actor, $feed) { $url = ''; @@ -635,11 +682,17 @@ class Ostatus_profile extends Memcached_DataObject * @param string $salmonuri if we already know the salmon return channel URI * @return Ostatus_profile */ + public static function ensureActorProfile($activity, $feeduri=null, $salmonuri=null) { - $profile = self::getActorProfile($activity); + return self::ensureActivityObjectProfile($activity->actor, $feeduri, $salmonuri); + } + + public static function ensureActivityObjectProfile($object, $feeduri=null, $salmonuri=null) + { + $profile = self::getActivityObjectProfile($object); if (!$profile) { - $profile = self::createActorProfile($activity, $feeduri, $salmonuri); + $profile = self::createActivityObjectProfile($object, $feeduri, $salmonuri); } return $profile; } @@ -650,8 +703,18 @@ class Ostatus_profile extends Memcached_DataObject */ protected static function getActorProfile($activity) { - $homeuri = self::getActorProfileURI($activity); - return self::staticGet('uri', $homeuri); + return self::getActivityObjectProfile($activity->actor); + } + + protected static function getActivityObjectProfile($object) + { + $uri = self::getActivityObjectProfileURI($object); + return Ostatus_profile::staticGet('homeuri', $uri); + } + + protected static function getActorProfileURI($activity) + { + return self::getActivityObjectProfileURI($activity->actor); } /** @@ -659,15 +722,14 @@ class Ostatus_profile extends Memcached_DataObject * @return string * @throws ServerException */ - protected static function getActorProfileURI($activity) + protected static function getActivityObjectProfileURI($object) { $opts = array('allowed_schemes' => array('http', 'https')); - $actor = $activity->actor; - if ($actor->id && Validate::uri($actor->id, $opts)) { - return $actor->id; + if ($object->id && Validate::uri($object->id, $opts)) { + return $object->id; } - if ($actor->link && Validate::uri($actor->link, $opts)) { - return $actor->link; + if ($object->link && Validate::uri($object->link, $opts)) { + return $object->link; } throw new ServerException("No author ID URI found"); } @@ -675,12 +737,19 @@ class Ostatus_profile extends Memcached_DataObject /** * @fixme validate stuff somewhere */ + protected static function createActorProfile($activity, $feeduri=null, $salmonuri=null) { $actor = $activity->actor; - $homeuri = self::getActorProfileURI($activity); - $nickname = self::getAuthorNick($activity); - $avatar = self::getAvatar($actor, $activity->feed); + + self::createActivityObjectProfile($actor, $feeduri, $salmonuri); + } + + protected static function createActivityObjectProfile($object, $feeduri=null, $salmonuri=null) + { + $homeuri = self::getActivityObjectProfileURI($object); + $nickname = self::getActivityObjectNickname($object); + $avatar = self::getActivityObjectAvatar($object); if (!$homeuri) { common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true)); @@ -703,9 +772,10 @@ class Ostatus_profile extends Memcached_DataObject $profile = new Profile(); $profile->nickname = $nickname; - $profile->fullname = $actor->displayName; - $profile->homepage = $actor->link; // @fixme - $profile->profileurl = $homeuri; + $profile->fullname = $object->title; + $profile->profileurl = $object->link; + $profile->created = common_sql_now(); + // @fixme bio // @fixme tags/categories // @fixme location? @@ -713,6 +783,7 @@ class Ostatus_profile extends Memcached_DataObject // @todo lat/lon/location? $ok = $profile->insert(); + if (!$ok) { throw new ServerException("Can't save local profile"); } @@ -720,16 +791,19 @@ class Ostatus_profile extends Memcached_DataObject // @fixme either need to do feed discovery here // or need to split out some of the feed stuff // so we can leave it empty until later. + $oprofile = new Ostatus_profile(); - $oprofile->uri = $homeuri; - $oprofile->feeduri = $feeduri; - $oprofile->salmonuri = $salmonuri; + + $oprofile->uri = $homeuri; + $oprofile->feeduri = $feeduri; + $oprofile->salmonuri = $salmonuri; $oprofile->profile_id = $profile->id; - $oprofile->created = common_sql_now(); - $oprofile->modified = common_sql_now(); + $oprofile->created = common_sql_now(); + $oprofile->modified = common_sql_now(); $ok = $oprofile->insert(); + if ($ok) { $oprofile->updateAvatar($avatar); return $oprofile; @@ -738,24 +812,37 @@ class Ostatus_profile extends Memcached_DataObject } } - /** - * @fixme move this into Activity? - * @param Activity $activity - * @return string - */ - protected static function getAuthorNick($activity) + protected static function getActivityObjectNickname($object) { - // @fixme not technically part of the actor? - foreach (array($activity->entry, $activity->feed) as $source) { - $author = ActivityUtils::child($source, 'author', Activity::ATOM); - if ($author) { - $name = ActivityUtils::child($author, 'name', Activity::ATOM); - if ($name) { - return trim($name->textContent); - } - } + // XXX: check whatever PoCo calls a nickname first + + $nickname = self::nicknameFromURI($object->id); + + if (empty($nickname)) { + $nickname = common_nicknamize($object->title); } - return false; + + return $nickname; } + protected static function nicknameFromURI($uri) + { + preg_match('/(\w+):/', $uri, $matches); + + $protocol = $matches[1]; + + switch ($protocol) { + case 'acct': + case 'mailto': + if (preg_match("/^$protocol:(.*)?@.*\$/", $uri, $matches)) { + return common_canonical_nickname($matches[1]); + } + return null; + case 'http': + return common_url_to_nickname($uri); + break; + default: + return null; + } + } } From d5ba9e1b10071484ec9bdce9821207a37b446fc8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 13:03:13 -0500 Subject: [PATCH 083/190] add feed-level author for user atom feeds --- lib/atomusernoticefeed.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php index 9f224325c6..f71c721fec 100644 --- a/lib/atomusernoticefeed.php +++ b/lib/atomusernoticefeed.php @@ -54,9 +54,15 @@ class AtomUserNoticeFeed extends AtomNoticeFeed * * @return void */ + function __construct($user = null, $indent = true) { parent::__construct($indent); $this->user = $user; + if (!empty($user)) { + $profile = $user->getProfile(); + $this->addAuthor($profile->getBestName(), + $user->uri); + } } function getUser() From 5aeed9e04110c34bca12e601836797afd5acadba Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 13:11:00 -0500 Subject: [PATCH 084/190] add activity:subject to atom feeds --- plugins/OStatus/OStatusPlugin.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 3aaa769db4..b5cfb5caec 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -102,16 +102,21 @@ class OStatusPlugin extends Plugin $id = null; if ($feed instanceof AtomUserNoticeFeed) { - $salmonAction = 'salmon'; - $id = $feed->getUser()->id; + $salmonAction = 'usersalmon'; + $user = $feed->getUser(); + $id = $user->id; + $profile = $user->getProfile(); + $feed->setActivitySubject($profile->asActivityNoun('subject')); } else if ($feed instanceof AtomGroupNoticeFeed) { - $salmonAction = 'salmongroup'; - $id = $feed->getGroup()->id; + $salmonAction = 'groupsalmon'; + $group = $feed->getGroup(); + $id = $group->id; + $feed->setActivitySubject($group->asActivitySubject()); } else { - return; + return true; } - if (!empty($id)) { + if (!empty($id)) { $hub = common_config('ostatus', 'hub'); if (empty($hub)) { // Updates will be handled through our internal PuSH hub. @@ -123,6 +128,8 @@ class OStatusPlugin extends Plugin $salmon = common_local_url($salmonAction, array('id' => $id)); $feed->addLink($salmon, array('rel' => 'salmon')); } + + return true; } /** From f83941a67baab8acf3bb381ec7fce5480f9c8626 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 13:31:31 -0500 Subject: [PATCH 085/190] correct name check in ActivityObject::fromProfile() --- plugins/OStatus/lib/activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index ea1303f199..f25a843c36 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -366,7 +366,7 @@ class ActivityObject $object->type = ActivityObject::PERSON; $object->id = $profile->getUri(); - $object->title = $this->getBestName(); + $object->title = $profile->getBestName(); $object->link = $profile->profileurl; return $object; From 068d8f92200e6fcef31db2fdca956a745422a1ac Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 13:31:58 -0500 Subject: [PATCH 086/190] correct call to time() in Ostatus_profile::notify() --- plugins/OStatus/classes/Ostatus_profile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 793d451125..aab316c347 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -327,7 +327,7 @@ class Ostatus_profile extends Memcached_DataObject $id = TagURI::mint('%s:%s:%s', $verb, $actor->getURI(), - common_date_iso8601(date())); + common_date_iso8601(time())); // @fixme consolidate all these NS settings somewhere $attributes = array('xmlns' => Activity::ATOM, From de093537f6c7f3b83817146247fbd9edbed16935 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 13:32:24 -0500 Subject: [PATCH 087/190] correct actor for OStatusPlugin::onEndUnsubscribe() --- plugins/OStatus/OStatusPlugin.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index b5cfb5caec..b966661db6 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -294,7 +294,7 @@ class OStatusPlugin extends Plugin $profile->getBestName(), $other->getBestName()); - $act->actor = ActivityObject::fromProfile($subscriber); + $act->actor = ActivityObject::fromProfile($profile); $act->object = ActivityObject::fromProfile($other); $oprofile->notifyActivity($act); @@ -447,8 +447,9 @@ class OStatusPlugin extends Plugin /** * Notify remote users when their notices get de-favorited. * - * @param Profile or User $profile of local user doing the de-faving - * @param Notice $notice being favored + * @param Profile $profile Profile person doing the de-faving + * @param Notice $notice Notice being favored + * * @return hook return value */ From 588fe5d603abe40c45a1147eba18c8b5143babc4 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 10:48:48 -0800 Subject: [PATCH 088/190] OStatus: debug aid - log the received Salmon post when it can't be parsed properly as an --- plugins/OStatus/lib/salmonaction.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index abd8d4c833..4e5ed7fe6a 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -51,6 +51,7 @@ class SalmonAction extends Action if ($dom->documentElement->namespaceURI != Activity::ATOM || $dom->documentElement->localName != 'entry') { + common_log(LOG_DEBUG, "Got invalid Salmon post: $xml"); $this->clientError(_m('Salmon post must be an Atom entry.')); } // XXX: check the signature From 3e7a2a4014dd93637f5a666e238dde13e397523c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 11:11:37 -0800 Subject: [PATCH 089/190] Fix for doc action on systems that return false for globbing in a non-existing dir --- actions/doc.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/actions/doc.php b/actions/doc.php index eaf4b7df2d..459f5f0968 100644 --- a/actions/doc.php +++ b/actions/doc.php @@ -173,6 +173,10 @@ class DocAction extends Action } $local = glob(INSTALLDIR.'/local/doc-src/'.$this->title.'.*'); + if ($local === false) { + // Some systems return false, others array(), if dir didn't exist. + $local = array(); + } if (count($local) || isset($localDef)) { return $this->negotiateLanguage($local, $localDef); @@ -183,6 +187,9 @@ class DocAction extends Action } $dist = glob(INSTALLDIR.'/doc-src/'.$this->title.'.*'); + if ($dist === false) { + $dist = array(); + } if (count($dist) || isset($distDef)) { return $this->negotiateLanguage($dist, $distDef); From 2d9d444b05e29105082d3a443b8b71de6498b7e9 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 11:13:57 -0800 Subject: [PATCH 090/190] Pulling PubSubHubbub plugin out of default list for 0.9.x; not compatible with recent changes to Atom feed generation for OStatus. --- lib/default.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/default.php b/lib/default.php index e9bca79a68..70e00ea750 100644 --- a/lib/default.php +++ b/lib/default.php @@ -280,7 +280,6 @@ $default = 'Mapstraction' => null, 'Linkback' => null, 'WikiHashtags' => null, - 'PubSubHubBub' => null, 'RSSCloud' => null, 'OpenID' => null), ), From 16a43b1154baf967183279c5e291a080cb2d5868 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 14:14:45 -0500 Subject: [PATCH 091/190] slightly more robust remote profile creation --- plugins/OStatus/classes/Ostatus_profile.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index aab316c347..3b79f32c62 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -709,7 +709,7 @@ class Ostatus_profile extends Memcached_DataObject protected static function getActivityObjectProfile($object) { $uri = self::getActivityObjectProfileURI($object); - return Ostatus_profile::staticGet('homeuri', $uri); + return Ostatus_profile::staticGet('uri', $uri); } protected static function getActorProfileURI($activity) @@ -747,9 +747,9 @@ class Ostatus_profile extends Memcached_DataObject protected static function createActivityObjectProfile($object, $feeduri=null, $salmonuri=null) { - $homeuri = self::getActivityObjectProfileURI($object); + $homeuri = $object->id; $nickname = self::getActivityObjectNickname($object); - $avatar = self::getActivityObjectAvatar($object); + $avatar = self::getActivityObjectAvatar($object); if (!$homeuri) { common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true)); @@ -782,9 +782,9 @@ class Ostatus_profile extends Memcached_DataObject // @todo tags from categories // @todo lat/lon/location? - $ok = $profile->insert(); + $profile_id = $profile->insert(); - if (!$ok) { + if (!$profile_id) { throw new ServerException("Can't save local profile"); } @@ -797,7 +797,7 @@ class Ostatus_profile extends Memcached_DataObject $oprofile->uri = $homeuri; $oprofile->feeduri = $feeduri; $oprofile->salmonuri = $salmonuri; - $oprofile->profile_id = $profile->id; + $oprofile->profile_id = $profile_id; $oprofile->created = common_sql_now(); $oprofile->modified = common_sql_now(); From ad3406a919d950315ed1381ffb4dd8d47baf2c24 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 14:17:37 -0500 Subject: [PATCH 092/190] use Ostatus_profile::ensureActivityObjectProfile() in SalmonAction::ensureProfile() --- plugins/OStatus/lib/salmonaction.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index abd8d4c833..87e98ad354 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -155,10 +155,11 @@ class SalmonAction extends Action $actor = $this->act->actor; if (empty($actor->id)) { common_log(LOG_ERR, "broken actor: " . var_export($actor, true)); + common_log(LOG_ERR, "activity with no actor: " . var_export($this->act, true)); throw new Exception("Received a salmon slap from unidentified actor."); } - return Ostatus_profile::ensureActorProfile($this->act); + return Ostatus_profile::ensureActivityObjectProfile($actor); } function saveNotice() From ab3db8c89971fc6148fbc8e0c031f9518c280bf1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 16:20:30 -0500 Subject: [PATCH 093/190] Combine code that finds mentions into one place and add hook points Combined the code that finds mentions of other profiles into one place. common_find_mentions() finds mentions and calls hooks to allow supplemental syntax for mentions (like OStatus). common_linkify_mentions() links mentions. common_linkify_mention() links a mention. Notice::saveReplies() now uses common_find_mentions() instead of trying to parse everything again. --- EVENTS.txt | 15 ++++ classes/Notice.php | 93 +++++++-------------- lib/util.php | 195 ++++++++++++++++++++++++++++++++------------- 3 files changed, 184 insertions(+), 119 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index c108606ce2..d3c2fb7bf6 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -748,3 +748,18 @@ EndDisfavorNotice: After saving a notice as a favorite - $profile: profile of the person faving (can be remote!) - $notice: notice being faved +StartFindMentions: start finding mentions in a block of text +- $sender: sender profile +- $text: plain text version of the notice +- &$mentions: mentions found so far. Array of arrays; each array + has 'mentioned' (array of mentioned profiles), 'url' (url to link as), + 'title' (title of the link), 'position' (position of the text to + replace), 'text' (text to replace) + +EndFindMentions: end finding mentions in a block of text +- $sender: sender profile +- $text: plain text version of the notice +- &$mentions: mentions found so far. Array of arrays; each array + has 'mentioned' (array of mentioned profiles), 'url' (url to link as), + 'title' (title of the link), 'position' (position of the text to + replace), 'text' (text to replace) diff --git a/classes/Notice.php b/classes/Notice.php index 7e524cacd4..6f1ef81fc5 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -820,6 +820,7 @@ class Notice extends Memcached_DataObject /** * @return array of integer profile IDs */ + function saveReplies() { // Don't save reply data for repeats @@ -828,76 +829,44 @@ class Notice extends Memcached_DataObject return array(); } - // Alternative reply format - $tname = false; - if (preg_match('/^T ([A-Z0-9]{1,64}) /', $this->content, $match)) { - $tname = $match[1]; - } - // extract all @messages - $cnt = preg_match_all('/(?:^|\s)@([a-z0-9]{1,64})/', $this->content, $match); - - $names = array(); - - if ($cnt || $tname) { - // XXX: is there another way to make an array copy? - $names = ($tname) ? array_unique(array_merge(array(strtolower($tname)), $match[1])) : array_unique($match[1]); - } - $sender = Profile::staticGet($this->profile_id); + $mentions = common_find_mentions($this->profile_id, $this->content); + $replied = array(); // store replied only for first @ (what user/notice what the reply directed, // we assume first @ is it) - for ($i=0; $icreated); - if (empty($recipient)) { - continue; - } - // Don't save replies from blocked profile to local user - $recipient_user = User::staticGet('id', $recipient->id); - if (!empty($recipient_user) && $recipient_user->hasBlocked($sender)) { - continue; - } - $reply = new Reply(); - $reply->notice_id = $this->id; - $reply->profile_id = $recipient->id; - $id = $reply->insert(); - if (!$id) { - $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); - common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message); - common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message)); - return array(); - } else { - $replied[$recipient->id] = 1; - } - } + foreach ($mentions as $mention) { - // Hash format replies, too - $cnt = preg_match_all('/(?:^|\s)@#([a-z0-9]{1,64})/', $this->content, $match); - if ($cnt) { - foreach ($match[1] as $tag) { - $tagged = Profile_tag::getTagged($sender->id, $tag); - foreach ($tagged as $t) { - if (!$replied[$t->id]) { - // Don't save replies from blocked profile to local user - $t_user = User::staticGet('id', $t->id); - if ($t_user && $t_user->hasBlocked($sender)) { - continue; - } - $reply = new Reply(); - $reply->notice_id = $this->id; - $reply->profile_id = $t->id; - $id = $reply->insert(); - if (!$id) { - common_log_db_error($reply, 'INSERT', __FILE__); - return array(); - } else { - $replied[$recipient->id] = 1; - } - } + foreach ($mention['mentioned'] as $mentioned) { + + // skip if they're already covered + + if (!empty($replied[$mentioned->id])) { + continue; + } + + // Don't save replies from blocked profile to local user + + $mentioned_user = User::staticGet('id', $mentioned->id); + if (!empty($mentioned_user) && $mentioned_user->hasBlocked($sender)) { + continue; + } + + $reply = new Reply(); + + $reply->notice_id = $this->id; + $reply->profile_id = $mentioned->id; + + $id = $reply->insert(); + + if (!$id) { + common_log_db_error($reply, 'INSERT', __FILE__); + throw new ServerException("Couldn't save reply for {$this->id}, {$mentioned->id}"); + } else { + $replied[$mentioned->id] = 1; } } } diff --git a/lib/util.php b/lib/util.php index ae812e8cf4..7fb2c6c4b0 100644 --- a/lib/util.php +++ b/lib/util.php @@ -426,13 +426,148 @@ function common_render_content($text, $notice) { $r = common_render_text($text); $id = $notice->profile_id; - $r = preg_replace('/(^|\s+)@(['.NICKNAME_FMT.']{1,64})/e', "'\\1@'.common_at_link($id, '\\2')", $r); - $r = preg_replace('/^T ([A-Z0-9]{1,64}) /e', "'T '.common_at_link($id, '\\1').' '", $r); - $r = preg_replace('/(^|[\s\.\,\:\;]+)@#([A-Za-z0-9]{1,64})/e', "'\\1@#'.common_at_hash_link($id, '\\2')", $r); + $r = common_linkify_mentions($id, $r); $r = preg_replace('/(^|[\s\.\,\:\;]+)!([A-Za-z0-9]{1,64})/e', "'\\1!'.common_group_link($id, '\\2')", $r); return $r; } +function common_linkify_mentions($profile_id, $text) +{ + $mentions = common_find_mentions($profile_id, $text); + + // We need to go through in reverse order by position, + // so our positions stay valid despite our fudging with the + // string! + + $points = array(); + + foreach ($mentions as $mention) + { + $points[$mention['position']] = $mention; + } + + krsort($points); + + foreach ($points as $position => $mention) { + + $linkText = common_linkify_mention($mention); + + $text = substr_replace($text, $linkText, $position, mb_strlen($mention['text'])); + } + + return $text; +} + +function common_linkify_mention($mention) +{ + $output = null; + + if (Event::handle('StartLinkifyMention', array($mention, &$output))) { + + $xs = new XMLStringer(false); + + $attrs = array('href' => $mention['url'], + 'class' => 'url'); + + if (!empty($mention['title'])) { + $attrs['title'] = $mention['title']; + } + + $xs->elementStart('span', 'vcard'); + $xs->elementStart('a', $attrs); + $xs->element('span', 'fn nickname', $mention['text']); + $xs->elementEnd('a'); + $xs->elementEnd('span'); + + $output = $xs->getString(); + + Event::handle('EndLinkifyMention', array($mention, &$output)); + } + + return $output; +} + +function common_find_mentions($profile_id, $text) +{ + $mentions = array(); + + $sender = Profile::staticGet('id', $profile_id); + + if (empty($sender)) { + return $mentions; + } + + if (Event::handle('StartFindMentions', array($sender, $text, &$mentions))) { + + preg_match_all('/^T ([A-Z0-9]{1,64}) /', + $text, + $tmatches, + PREG_OFFSET_CAPTURE); + + preg_match_all('/(?:^|\s+)@(['.NICKNAME_FMT.']{1,64})/', + $text, + $atmatches, + PREG_OFFSET_CAPTURE); + + $matches = array_merge($tmatches[1], $atmatches[1]); + + foreach ($matches as $match) { + + $nickname = common_canonical_nickname($match[0]); + $mentioned = common_relative_profile($sender, $nickname); + + if (!empty($mentioned)) { + + $user = User::staticGet('id', $mentioned->id); + + if ($user) { + $url = common_local_url('userbyid', array('id' => $user->id)); + } else { + $url = $mentioned->profileurl; + } + + $mention = array('mentioned' => array($mentioned), + 'text' => $match[0], + 'position' => $match[1], + 'url' => $url); + + if (!empty($mentioned->fullname)) { + $mention['title'] = $mentioned->fullname; + } + + $mentions[] = $mention; + } + } + + // @#tag => mention of all subscriptions tagged 'tag' + + preg_match_all('/(?:^|[\s\.\,\:\;]+)@#([\pL\pN_\-\.]{1,64})/', + $text, + $hmatches, + PREG_OFFSET_CAPTURE); + + foreach ($hmatches[1] as $hmatch) { + + $tag = common_canonical_tag($hmatch[0]); + + $tagged = Profile_tag::getTagged($sender->id, $tag); + + $url = common_local_url('subscriptions', + array('nickname' => $sender->nickname, + 'tag' => $tag)); + + $mentions[] = array('mentioned' => $tagged, + 'text' => $hmatch[0], + 'position' => $hmatch[1], + 'url' => $url); + } + + Event::handle('EndFindMentions', array($sender, $text, &$mentions)); + } + + return $mentions; +} + function common_render_text($text) { $r = htmlspecialchars($text); @@ -663,37 +798,6 @@ function common_valid_profile_tag($str) return preg_match('/^[A-Za-z0-9_\-\.]{1,64}$/', $str); } -function common_at_link($sender_id, $nickname) -{ - $sender = Profile::staticGet($sender_id); - if (!$sender) { - return $nickname; - } - $recipient = common_relative_profile($sender, common_canonical_nickname($nickname)); - if ($recipient) { - $user = User::staticGet('id', $recipient->id); - if ($user) { - $url = common_local_url('userbyid', array('id' => $user->id)); - } else { - $url = $recipient->profileurl; - } - $xs = new XMLStringer(false); - $attrs = array('href' => $url, - 'class' => 'url'); - if (!empty($recipient->fullname)) { - $attrs['title'] = $recipient->fullname . ' (' . $recipient->nickname . ')'; - } - $xs->elementStart('span', 'vcard'); - $xs->elementStart('a', $attrs); - $xs->element('span', 'fn nickname', $nickname); - $xs->elementEnd('a'); - $xs->elementEnd('span'); - return $xs->getString(); - } else { - return $nickname; - } -} - function common_group_link($sender_id, $nickname) { $sender = Profile::staticGet($sender_id); @@ -716,29 +820,6 @@ function common_group_link($sender_id, $nickname) } } -function common_at_hash_link($sender_id, $tag) -{ - $user = User::staticGet($sender_id); - if (!$user) { - return $tag; - } - $tagged = Profile_tag::getTagged($user->id, common_canonical_tag($tag)); - if ($tagged) { - $url = common_local_url('subscriptions', - array('nickname' => $user->nickname, - 'tag' => $tag)); - $xs = new XMLStringer(); - $xs->elementStart('span', 'tag'); - $xs->element('a', array('href' => $url, - 'rel' => $tag), - $tag); - $xs->elementEnd('span'); - return $xs->getString(); - } else { - return $tag; - } -} - function common_relative_profile($sender, $nickname, $dt=null) { // Try to find profiles this profile is subscribed to that have this nickname From 10f6c023f4573868326c4b6599bdfb66cffdd7d6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 16:23:55 -0500 Subject: [PATCH 094/190] include namespaces in posted activities in notifyActivity() --- plugins/OStatus/classes/Ostatus_profile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 3b79f32c62..b67e202026 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -361,7 +361,7 @@ class Ostatus_profile extends Memcached_DataObject { if ($this->salmonuri) { - $xml = $activity->asString(); + $xml = $activity->asString(true); $salmon = new Salmon(); // ? From 5349aa420ed45c2f5bf773d10c7709826ae6babd Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 13:40:59 -0800 Subject: [PATCH 095/190] OStatus feedsub fixlets: - actually udpate feedsub.last_update when we get a new PuSH update in - move incoming PuSH processing to a queue handler to minimize time spent before POST return, as recommended by PuSH spec. When queues are disabled this'll still be handled immediately. --- plugins/OStatus/OStatusPlugin.php | 4 ++ plugins/OStatus/actions/pushcallback.php | 9 +++- plugins/OStatus/classes/FeedSub.php | 10 ++++ plugins/OStatus/lib/pushinputqueuehandler.php | 49 +++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 plugins/OStatus/lib/pushinputqueuehandler.php diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index b966661db6..c5a2db3d84 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -78,9 +78,13 @@ class OStatusPlugin extends Plugin */ function onEndInitializeQueueManager(QueueManager $qm) { + // Outgoing from our internal PuSH hub $qm->connect('hubverify', 'HubVerifyQueueHandler'); $qm->connect('hubdistrib', 'HubDistribQueueHandler'); $qm->connect('hubout', 'HubOutQueueHandler'); + + // Incoming from a foreign PuSH hub + $qm->connect('pushinput', 'PushInputQueueHandler'); return true; } diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index 7e1227a66a..9e976a80de 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -60,9 +60,14 @@ class PushCallbackAction extends Action $post = file_get_contents('php://input'); - // @fixme Queue this to a background process; we should return + // Queue this to a background process; we should return // as quickly as possible from a distribution POST. - $feedsub->receive($post, $hmac); + // If queues are disabled this'll process immediately. + $data = array('feedsub_id' => $feedsub->id, + 'post' => $post, + 'hmac' => $hmac); + $qm = QueueManager::get(); + $qm->enqueue($data, 'pushinput'); } /** diff --git a/plugins/OStatus/classes/FeedSub.php b/plugins/OStatus/classes/FeedSub.php index bf9d063fa1..31241d3de7 100644 --- a/plugins/OStatus/classes/FeedSub.php +++ b/plugins/OStatus/classes/FeedSub.php @@ -372,6 +372,12 @@ class FeedSub extends Memcached_DataObject * feed (as a DOMDocument) will be passed to the StartFeedSubHandleFeed * and EndFeedSubHandleFeed events for processing. * + * Not guaranteed to be running in an immediate POST context; may be run + * from a queue handler. + * + * Side effects: the feedsub record's lastupdate field will be updated + * to the current time (not published time) if we got a legit update. + * * @param string $post source of Atom or RSS feed * @param string $hmac X-Hub-Signature header, if present */ @@ -402,6 +408,10 @@ class FeedSub extends Memcached_DataObject return; } + $orig = clone($this); + $this->last_update = common_sql_now(); + $this->update($orig); + Event::handle('StartFeedSubReceive', array($this, $feed)); Event::handle('EndFeedSubReceive', array($this, $feed)); } diff --git a/plugins/OStatus/lib/pushinputqueuehandler.php b/plugins/OStatus/lib/pushinputqueuehandler.php new file mode 100644 index 0000000000..cbd9139b50 --- /dev/null +++ b/plugins/OStatus/lib/pushinputqueuehandler.php @@ -0,0 +1,49 @@ +. + */ + +/** + * Process a feed distribution POST from a PuSH hub. + * @package FeedSub + * @author Brion Vibber + */ + +class PushInputQueueHandler extends QueueHandler +{ + function transport() + { + return 'pushinput'; + } + + function handle($data) + { + assert(is_array($data)); + + $feedsub_id = $data['feedsub_id']; + $post = $data['post']; + $hmac = $data['hmac']; + + $feedsub = FeedSub::staticGet('id', $feedsub_id); + if ($feedsub) { + $feedsub->receive($post, $hmac); + } else { + common_log(LOG_ERR, "Discarding POST to unknown feed subscription id $feedsub_id"); + } + return true; + } +} From 1c22bf20f1e99664b02d71318592b73e7fb4d4b5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 17:00:05 -0500 Subject: [PATCH 096/190] fixup activity serialization so salmon notifications work --- plugins/OStatus/lib/activity.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index f25a843c36..af83f8bc66 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -392,7 +392,7 @@ class ActivityObject if (!empty($this->content)) { // XXX: assuming HTML content here - $xs->element(self::CONTENT, array('type' => 'html'), $this->content); + $xs->element(ActivityUtils::CONTENT, array('type' => 'html'), $this->content); } if (!empty($this->link)) { @@ -700,7 +700,7 @@ class Activity // XXX: add context // XXX: add target - $xs->raw($this->actor->asString()); + $xs->raw($this->actor->asString('activity:actor')); $xs->element('activity:verb', null, $this->verb); $xs->raw($this->object->asString()); From aa0b2ce81ad4a99fb55a36feda54e70bcd0808be Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 14:28:06 -0800 Subject: [PATCH 097/190] OStatus PuSH fixlets: - set minimal error page output on PuSH callback - allow hub to retry ($config['ostatus']['hub_retries']), simplify internal iface a bit. Retries are pushed to end of queue but otherwise not delayed yet; makes delivery more robust to one-off transitory errors but not yet against downtime. --- plugins/OStatus/actions/pushcallback.php | 1 + plugins/OStatus/classes/HubSub.php | 47 ++++++++++++------- .../OStatus/lib/hubdistribqueuehandler.php | 5 +- plugins/OStatus/lib/huboutqueuehandler.php | 18 +++++-- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index 9e976a80de..35c92c7323 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -29,6 +29,7 @@ class PushCallbackAction extends Action { function handle() { + StatusNet::setApi(true); // Minimize error messages to aid in debugging parent::handle(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->handlePost(); diff --git a/plugins/OStatus/classes/HubSub.php b/plugins/OStatus/classes/HubSub.php index 0cd4281f8f..a81de68e69 100644 --- a/plugins/OStatus/classes/HubSub.php +++ b/plugins/OStatus/classes/HubSub.php @@ -226,6 +226,26 @@ class HubSub extends Memcached_DataObject return parent::insert(); } + /** + * Schedule delivery of a 'fat ping' to the subscriber's callback + * endpoint. If queues are disabled, this will run immediately. + * + * @param string $atom well-formed Atom feed + * @param int $retries optional count of retries if POST fails; defaults to hub_retries from config or 0 if unset + */ + function distribute($atom, $retries=null) + { + if ($retries === null) { + $retries = intval(common_config('ostatus', 'hub_retries')); + } + + $data = array('sub' => clone($this), + 'atom' => $atom, + 'retries' => $retries); + $qm = QueueManager::get(); + $qm->enqueue($data, 'hubout'); + } + /** * Send a 'fat ping' to the subscriber's callback endpoint * containing the given Atom feed chunk. @@ -234,6 +254,7 @@ class HubSub extends Memcached_DataObject * a higher level; don't just shove in a complete feed! * * @param string $atom well-formed Atom feed + * @throws Exception (HTTP or general) */ function push($atom) { @@ -245,24 +266,18 @@ class HubSub extends Memcached_DataObject $hmac = '(none)'; } common_log(LOG_INFO, "About to push feed to $this->callback for $this->topic, HMAC $hmac"); - try { - $request = new HTTPClient(); - $request->setBody($atom); - $response = $request->post($this->callback, $headers); - if ($response->isOk()) { - return true; - } - common_log(LOG_ERR, "Error sending PuSH content " . - "to $this->callback for $this->topic: " . - $response->getStatus()); - return false; + $request = new HTTPClient(); + $request->setBody($atom); + $response = $request->post($this->callback, $headers); - } catch (Exception $e) { - common_log(LOG_ERR, "Error sending PuSH content " . - "to $this->callback for $this->topic: " . - $e->getMessage()); - return false; + if ($response->isOk()) { + return true; + } else { + throw new Exception("Callback returned status: " . + $response->getStatus() . + "; body: " . + trim($response->getBody())); } } } diff --git a/plugins/OStatus/lib/hubdistribqueuehandler.php b/plugins/OStatus/lib/hubdistribqueuehandler.php index 245a57f720..30a427e3fc 100644 --- a/plugins/OStatus/lib/hubdistribqueuehandler.php +++ b/plugins/OStatus/lib/hubdistribqueuehandler.php @@ -124,10 +124,7 @@ class HubDistribQueueHandler extends QueueHandler common_log(LOG_INFO, "Preparing $sub->N PuSH distribution(s) for $sub->topic"); $qm = QueueManager::get(); while ($sub->fetch()) { - common_log(LOG_INFO, "Prepping PuSH distribution to $sub->callback for $sub->topic"); - $data = array('sub' => clone($sub), - 'atom' => $atom); - $qm->enqueue($data, 'hubout'); + $sub->distribute($atom); } } diff --git a/plugins/OStatus/lib/huboutqueuehandler.php b/plugins/OStatus/lib/huboutqueuehandler.php index 0791c7e5db..3ad94646e6 100644 --- a/plugins/OStatus/lib/huboutqueuehandler.php +++ b/plugins/OStatus/lib/huboutqueuehandler.php @@ -33,6 +33,7 @@ class HubOutQueueHandler extends QueueHandler { $sub = $data['sub']; $atom = $data['atom']; + $retries = $data['retries']; assert($sub instanceof HubSub); assert(is_string($atom)); @@ -40,13 +41,20 @@ class HubOutQueueHandler extends QueueHandler try { $sub->push($atom); } catch (Exception $e) { - common_log(LOG_ERR, "Failed PuSH to $sub->callback for $sub->topic: " . - $e->getMessage()); - // @fixme Reschedule a later delivery? - return true; + $retries--; + $msg = "Failed PuSH to $sub->callback for $sub->topic: " . + $e->getMessage(); + if ($retries > 0) { + common_log(LOG_ERR, "$msg; scheduling for $retries more tries"); + + // @fixme when we have infrastructure to schedule a retry + // after a delay, use it. + $sub->distribute($atom, $retries); + } else { + common_log(LOG_ERR, "$msg; discarding"); + } } return true; } } - From 10281d59f4bf8298ff65792d1a7826913d96fafa Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 21 Feb 2010 14:43:28 -0800 Subject: [PATCH 098/190] Add PoCo namespace to notice feeds --- lib/atomnoticefeed.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index 7653f91544..d2bf2a416f 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -64,6 +64,11 @@ class AtomNoticeFeed extends Atom10Feed 'http://activitystrea.ms/spec/1.0/' ); + $this->addNamespace( + 'poco', + 'http://portablecontacts.net/spec/1.0' + ); + // XXX: What should the uri be? $this->addNamespace( 'ostatus', From daccaeb748fff65186fff85e28cda92f268dbc60 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Mon, 22 Feb 2010 00:06:47 +0100 Subject: [PATCH 099/190] Localisation updates for !StatusNet from !translatewiki.net !sntrans Signed-off-by: Siebrand Mazeland --- locale/ar/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/arz/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/bg/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/ca/LC_MESSAGES/statusnet.po | 223 ++++++------- locale/cs/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/de/LC_MESSAGES/statusnet.po | 464 ++++++++++++-------------- locale/el/LC_MESSAGES/statusnet.po | 223 ++++++------- locale/en_GB/LC_MESSAGES/statusnet.po | 223 ++++++------- locale/es/LC_MESSAGES/statusnet.po | 223 ++++++------- locale/fa/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/fi/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/fr/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/ga/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/he/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/hsb/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/ia/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/is/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/it/LC_MESSAGES/statusnet.po | 221 ++++++------ locale/ja/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/ko/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/mk/LC_MESSAGES/statusnet.po | 221 ++++++------ locale/nb/LC_MESSAGES/statusnet.po | 223 ++++++------- locale/nl/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/nn/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/pl/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/pt/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/pt_BR/LC_MESSAGES/statusnet.po | 264 ++++++++------- locale/ru/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/statusnet.po | 214 ++++++------ locale/sv/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/te/LC_MESSAGES/statusnet.po | 223 ++++++------- locale/tr/LC_MESSAGES/statusnet.po | 225 ++++++------- locale/uk/LC_MESSAGES/statusnet.po | 219 ++++++------ locale/vi/LC_MESSAGES/statusnet.po | 227 ++++++------- locale/zh_CN/LC_MESSAGES/statusnet.po | 227 +++++++------ locale/zh_TW/LC_MESSAGES/statusnet.po | 223 ++++++------- 36 files changed, 4067 insertions(+), 4204 deletions(-) diff --git a/locale/ar/LC_MESSAGES/statusnet.po b/locale/ar/LC_MESSAGES/statusnet.po index 3d3fca98c3..ebaf7290c8 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:55:38+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:19+0000\n" "Language-Team: Arabic\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -100,7 +100,6 @@ msgstr "لا صفحة كهذه" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "لا مستخدم كهذا." @@ -543,7 +542,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "الحساب" @@ -918,7 +917,7 @@ msgstr "أنت لست مالك هذا التطبيق." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1638,7 +1637,7 @@ msgstr "%1$s أعضاء المجموعة, الصفحة %2$d" msgid "A list of the users in this group." msgstr "قائمة بمستخدمي هذه المجموعة." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "إداري" @@ -1968,7 +1967,7 @@ msgstr "اسم المستخدم أو كلمة السر غير صحيحان." msgid "Error setting user. You are probably not authorized." msgstr "خطأ أثناء ضبط المستخدم. لست مُصرحًا على الأرجح." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "لُج" @@ -2896,7 +2895,7 @@ msgstr "عذرا، رمز دعوة غير صالح." msgid "Registration successful" msgstr "نجح التسجيل" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "سجّل" @@ -3726,7 +3725,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "تعذّر حفظ الاشتراك." @@ -4148,7 +4148,7 @@ msgstr "" msgid "Plugins" msgstr "ملحقات" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "النسخة" @@ -4207,49 +4207,73 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "مشكلة في حفظ الإشعار. طويل جدًا." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "مشكلة في حفظ الإشعار. مستخدم غير معروف." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "مشكلة أثناء حفظ الإشعار." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "مشكلة أثناء حفظ الإشعار." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "آر تي @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "مُشترك أصلا!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "لقد منعك المستخدم." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "غير مشترك!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "لم يمكن حذف اشتراك ذاتي." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "تعذّر حذف الاشتراك." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "أهلا بكم في %1$s يا @%2$s!" @@ -4299,124 +4323,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "صفحة غير مُعنونة" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "الرئيسية" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "الملف الشخصي ومسار الأصدقاء الزمني" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "اتصل" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "غيّر ضبط الموقع" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "ادعُ" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "اخرج" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "اخرج من الموقع" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "أنشئ حسابًا" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "لُج إلى الموقع" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "مساعدة" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "ساعدني!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "ابحث" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "ابحث عن أشخاص أو نص" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "إشعار الموقع" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "المشاهدات المحلية" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "إشعار الصفحة" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "عن" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "الأسئلة المكررة" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "الشروط" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "خصوصية" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "المصدر" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "اتصل" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "رخصة برنامج StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4425,12 +4449,12 @@ msgstr "" "**%%site.name%%** خدمة تدوين مصغر يقدمها لك [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4441,41 +4465,41 @@ msgstr "" "المتوفر تحت [رخصة غنو أفيرو العمومية](http://www.fsf.org/licensing/licenses/" "agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "رخصة محتوى الموقع" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "الرخصة." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "بعد" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "قبل" @@ -4775,54 +4799,59 @@ msgstr "خطأ أثناء حفظ الإشعار." msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "لا مستخدم كهذا." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "مُشترك ب%s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "لست مُشتركًا بأي أحد." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "لست مشتركًا بأحد." @@ -4832,11 +4861,11 @@ msgstr[3] "أنت مشترك بهؤلاء الأشخاص:" msgstr[4] "" msgstr[5] "" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "لا أحد مشترك بك." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "لا أحد مشترك بك." @@ -4846,11 +4875,11 @@ msgstr[3] "هؤلاء الأشخاص مشتركون بك:" msgstr[4] "" msgstr[5] "" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "لست عضوًا في أي مجموعة." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "لست عضوًا في أي مجموعة." @@ -4860,7 +4889,7 @@ msgstr[3] "أنت عضو في هذه المجموعات:" msgstr[4] "" msgstr[5] "" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5522,10 +5551,6 @@ msgstr "خطأ أثناء إدراج الملف الشخصي البعيد" msgid "Duplicate notice" msgstr "ضاعف الإشعار" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "تعذّر إدراج اشتراك جديد." @@ -5702,34 +5727,6 @@ msgstr "الأشخاص المشتركون ب%s" msgid "Groups %s is a member of" msgstr "المجموعات التي %s عضو فيها" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "مُشترك أصلا!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "لقد منعك المستخدم." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "تعذّر الاشتراك." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "غير مشترك!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "لم يمكن حذف اشتراك ذاتي." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "تعذّر حذف الاشتراك." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/arz/LC_MESSAGES/statusnet.po b/locale/arz/LC_MESSAGES/statusnet.po index 2163be1b4f..9c0e7c4dd9 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:55:41+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:22+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.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -104,7 +104,6 @@ msgstr "لا صفحه كهذه" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "لا مستخدم كهذا." @@ -547,7 +546,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "الحساب" @@ -922,7 +921,7 @@ msgstr "انت مش بتملك الapplication دى." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1642,7 +1641,7 @@ msgstr "%1$s اعضاء الجروپ, صفحه %2$d" msgid "A list of the users in this group." msgstr "قائمه بمستخدمى هذه المجموعه." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "إداري" @@ -1972,7 +1971,7 @@ msgstr "اسم المستخدم أو كلمه السر غير صحيحان." msgid "Error setting user. You are probably not authorized." msgstr "خطأ أثناء ضبط المستخدم. لست مُصرحًا على الأرجح." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "لُج" @@ -2897,7 +2896,7 @@ msgstr "عذرا، رمز دعوه غير صالح." msgid "Registration successful" msgstr "نجح التسجيل" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "سجّل" @@ -3727,7 +3726,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "تعذّر حفظ الاشتراك." @@ -4149,7 +4149,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "النسخه" @@ -4208,49 +4208,73 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "مشكله فى حفظ الإشعار. طويل جدًا." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "مشكله فى حفظ الإشعار. مستخدم غير معروف." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "مشكله أثناء حفظ الإشعار." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "مشكله أثناء حفظ الإشعار." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "آر تى @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "مُشترك أصلا!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "لقد منعك المستخدم." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "غير مشترك!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "ما نفعش يمسح الاشتراك الشخصى." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "تعذّر حذف الاشتراك." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "أهلا بكم فى %1$s يا @%2$s!" @@ -4300,124 +4324,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "صفحه غير مُعنونة" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "الرئيسية" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "الملف الشخصى ومسار الأصدقاء الزمني" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "اتصل" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "غيّر ضبط الموقع" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "ادعُ" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "اخرج" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "اخرج من الموقع" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "أنشئ حسابًا" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "لُج إلى الموقع" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "مساعدة" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "ساعدني!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "ابحث" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "ابحث عن أشخاص أو نص" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "إشعار الموقع" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "المشاهدات المحلية" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "إشعار الصفحة" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "عن" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "الأسئله المكررة" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "الشروط" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "خصوصية" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "المصدر" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "اتصل" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4426,12 +4450,12 @@ msgstr "" "**%%site.name%%** خدمه تدوين مصغر يقدمها لك [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4442,41 +4466,41 @@ msgstr "" "المتوفر تحت [رخصه غنو أفيرو العمومية](http://www.fsf.org/licensing/licenses/" "agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "رخصه محتوى الموقع" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "الرخصه." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "بعد" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "قبل" @@ -4776,54 +4800,59 @@ msgstr "خطأ أثناء حفظ الإشعار." msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "لا مستخدم كهذا." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "مُشترك ب%s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "لست مُشتركًا بأى أحد." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "لست مشتركًا بأحد." @@ -4833,11 +4862,11 @@ msgstr[3] "أنت مشترك بهؤلاء الأشخاص:" msgstr[4] "" msgstr[5] "" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "لا أحد مشترك بك." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "لا أحد مشترك بك." @@ -4847,11 +4876,11 @@ msgstr[3] "هؤلاء الأشخاص مشتركون بك:" msgstr[4] "" msgstr[5] "" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "لست عضوًا فى أى مجموعه." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "لست عضوًا فى أى مجموعه." @@ -4861,7 +4890,7 @@ msgstr[3] "أنت عضو فى هذه المجموعات:" msgstr[4] "" msgstr[5] "" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5513,10 +5542,6 @@ msgstr "خطأ أثناء إدراج الملف الشخصى البعيد" msgid "Duplicate notice" msgstr "ضاعف الإشعار" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "تعذّر إدراج اشتراك جديد." @@ -5693,34 +5718,6 @@ msgstr "الأشخاص المشتركون ب%s" msgid "Groups %s is a member of" msgstr "المجموعات التى %s عضو فيها" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "مُشترك أصلا!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "لقد منعك المستخدم." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "تعذّر الاشتراك." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "غير مشترك!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "ما نفعش يمسح الاشتراك الشخصى." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "تعذّر حذف الاشتراك." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/bg/LC_MESSAGES/statusnet.po b/locale/bg/LC_MESSAGES/statusnet.po index 973f57496a..873dcfb61d 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:55:44+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:26+0000\n" "Language-Team: Bulgarian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -99,7 +99,6 @@ msgstr "Няма такака страница." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Няма такъв потребител" @@ -553,7 +552,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Сметка" @@ -934,7 +933,7 @@ msgstr "Не членувате в тази група." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Имаше проблем със сесията ви в сайта." @@ -1691,7 +1690,7 @@ msgstr "Членове на групата %s, страница %d" msgid "A list of the users in this group." msgstr "Списък с потребителите в тази група." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Настройки" @@ -2068,7 +2067,7 @@ msgstr "Грешно име или парола." msgid "Error setting user. You are probably not authorized." msgstr "Забранено." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Вход" @@ -3017,7 +3016,7 @@ msgstr "Грешка в кода за потвърждение." msgid "Registration successful" msgstr "Записването е успешно." -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Регистриране" @@ -3884,7 +3883,8 @@ msgstr "Не е въведен код." msgid "You are not subscribed to that profile." msgstr "Не сте абонирани за този профил" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "Грешка при създаване на нов абонамент." @@ -4328,7 +4328,7 @@ msgstr "" msgid "Plugins" msgstr "Приставки" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Версия" @@ -4391,23 +4391,23 @@ msgstr "Грешка при обновяване на бележката с но msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Проблем при записване на бележката." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Грешка при записване на бележката. Непознат потребител." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Твърде много бележки за кратко време. Спрете, поемете дъх и публикувайте " "отново след няколко минути." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4416,30 +4416,57 @@ msgstr "" "Твърде много бележки за кратко време. Спрете, поемете дъх и публикувайте " "отново след няколко минути." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Забранено ви е да публикувате бележки в този сайт." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Проблем при записване на бележката." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Проблем при записване на бележката." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Грешка в базата от данни — отговор при вмъкването: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +#, fuzzy +msgid "You have been banned from subscribing." +msgstr "Потребителят е забранил да се абонирате за него." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Потребителят ви е блокирал." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Не сте абонирани!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Грешка при изтриване на абонамента." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Грешка при изтриване на абонамента." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Добре дошли в %1$s, @%2$s!" @@ -4491,128 +4518,128 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Неозаглавена страница" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Начало" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Промяна на поща, аватар, парола, профил" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Свързване" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Свързване към услуги" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Промяна настройките на сайта" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Покани" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Поканете приятели и колеги да се присъединят към вас в %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Изход" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Излизане от сайта" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Създаване на нова сметка" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Влизане в сайта" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Помощ" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "Помощ" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Търсене" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Търсене за хора или бележки" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "Нова бележка" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "Нова бележка" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "Абонаменти" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Относно" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Въпроси" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "Условия" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Поверителност" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Изходен код" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Контакт" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Табелка" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Лиценз на програмата StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4621,12 +4648,12 @@ msgstr "" "**%%site.name%%** е услуга за микроблогване, предоставена ви от [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** е услуга за микроблогване. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4637,41 +4664,41 @@ msgstr "" "достъпна под [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Лиценз на съдържанието" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Всички " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "лиценз." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Страниране" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "След" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Преди" @@ -4985,80 +5012,85 @@ msgstr "Грешка при записване на бележката." msgid "Specify the name of the user to subscribe to" msgstr "Уточнете името на потребителя, за когото се абонирате." -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Няма такъв потребител" + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Абонирани сте за %s." -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Уточнете името на потребителя, от когото се отписвате." -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Отписани сте от %s." -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Командата все още не се поддържа." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Уведомлението е изключено." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Грешка при изключване на уведомлението." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Уведомлението е включено." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Грешка при включване на уведомлението." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Не сте абонирани за никого." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Вече сте абонирани за следните потребители:" msgstr[1] "Вече сте абонирани за следните потребители:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Никой не е абониран за вас." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Грешка при абониране на друг потребител за вас." msgstr[1] "Грешка при абониране на друг потребител за вас." -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Не членувате в нито една група." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Не членувате в тази група." msgstr[1] "Не членувате в тази група." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5731,11 +5763,6 @@ msgstr "Грешка при вмъкване на отдалечен профи msgid "Duplicate notice" msgstr "Изтриване на бележката" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "Потребителят е забранил да се абонирате за него." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Грешка при добавяне на нов абонамент." @@ -5919,36 +5946,6 @@ msgstr "Абонирани за %s" msgid "Groups %s is a member of" msgstr "Групи, в които участва %s" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Потребителят ви е блокирал." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Грешка при абониране." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Грешка при абониране на друг потребител за вас." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Не сте абонирани!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Грешка при изтриване на абонамента." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Грешка при изтриване на абонамента." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/ca/LC_MESSAGES/statusnet.po b/locale/ca/LC_MESSAGES/statusnet.po index e141f0a0dd..48cd84bccc 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:55:48+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:28+0000\n" "Language-Team: Catalan\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -105,7 +105,6 @@ msgstr "No existeix la pàgina." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "No existeix aquest usuari." @@ -569,7 +568,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Compte" @@ -954,7 +953,7 @@ msgstr "No sou un membre del grup." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Ha ocorregut algun problema amb la teva sessió." @@ -1711,7 +1710,7 @@ msgstr "%s membre/s en el grup, pàgina %d" msgid "A list of the users in this group." msgstr "La llista dels usuaris d'aquest grup." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2091,7 +2090,7 @@ msgstr "Nom d'usuari o contrasenya incorrectes." msgid "Error setting user. You are probably not authorized." msgstr "No autoritzat." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Inici de sessió" @@ -3061,7 +3060,7 @@ msgstr "El codi d'invitació no és vàlid." msgid "Registration successful" msgstr "Registre satisfactori" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registre" @@ -3949,7 +3948,8 @@ msgstr "No hi ha cap codi entrat" msgid "You are not subscribed to that profile." msgstr "No estàs subscrit a aquest perfil." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "No s'ha pogut guardar la subscripció." @@ -4396,7 +4396,7 @@ msgstr "" msgid "Plugins" msgstr "Connectors" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Sessions" @@ -4460,23 +4460,23 @@ msgstr "No s'ha pogut inserir el missatge amb la nova URI." msgid "DB error inserting hashtag: %s" msgstr "Hashtag de l'error de la base de dades:%s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Problema en guardar l'avís." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problema al guardar la notificació. Usuari desconegut." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Masses notificacions massa ràpid; pren un respir i publica de nou en uns " "minuts." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4485,30 +4485,56 @@ msgstr "" "Masses notificacions massa ràpid; pren un respir i publica de nou en uns " "minuts." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Ha estat bandejat de publicar notificacions en aquest lloc." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problema en guardar l'avís." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Problema en guardar l'avís." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Error de BD en inserir resposta: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Se us ha banejat la subscripció." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Ja hi esteu subscrit!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Un usuari t'ha bloquejat." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "No estàs subscrit!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "No s'ha pogut eliminar la subscripció." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "No s'ha pogut eliminar la subscripció." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Us donem la benvinguda a %1$s, @%2$s!" @@ -4559,125 +4585,125 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Pàgina sense titol" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Navegació primària del lloc" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Inici" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Perfil personal i línia temporal dels amics" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Canviar correu electrònic, avatar, contrasenya, perfil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Connexió" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "No s'ha pogut redirigir al servidor: %s" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Canvia la configuració del lloc" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Convida" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Convidar amics i companys perquè participin a %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Finalitza la sessió" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Finalitza la sessió del lloc" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Crea un compte" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Inicia una sessió al lloc" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Ajuda" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Ajuda'm" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Cerca" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Cerca gent o text" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Avís del lloc" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Vistes locals" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Notificació pàgina" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Navegació del lloc secundària" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Quant a" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Preguntes més freqüents" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privadesa" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Font" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contacte" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Insígnia" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Llicència del programari StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4686,12 +4712,12 @@ msgstr "" "**%%site.name%%** és un servei de microblogging de [%%site.broughtby%%**](%%" "site.broughtbyurl%%)." -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** és un servei de microblogging." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4702,41 +4728,41 @@ msgstr "" "%s, disponible sota la [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Llicència de contingut del lloc" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Tot " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "llicència." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginació" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Posteriors" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Anteriors" @@ -5048,82 +5074,87 @@ msgstr "Problema en guardar l'avís." msgid "Specify the name of the user to subscribe to" msgstr "Especifica el nom de l'usuari a que vols subscriure't" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "No existeix aquest usuari." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Subscrit a %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Especifica el nom de l'usuari del que vols deixar d'estar subscrit" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Has deixat d'estar subscrit a %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Comanda encara no implementada." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notificacions off." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "No es poden posar en off les notificacions." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notificacions on." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "No es poden posar en on les notificacions." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "No estàs subscrit a aquest perfil." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Ja estàs subscrit a aquests usuaris:" msgstr[1] "Ja estàs subscrit a aquests usuaris:" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "No pots subscriure a un altre a tu mateix." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "No pots subscriure a un altre a tu mateix." msgstr[1] "No pots subscriure a un altre a tu mateix." -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "No sou membre de cap grup." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Sou un membre d'aquest grup:" msgstr[1] "Sou un membre d'aquests grups:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5799,10 +5830,6 @@ msgstr "Error en inserir perfil remot" msgid "Duplicate notice" msgstr "Eliminar nota." -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Se us ha banejat la subscripció." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "No s'ha pogut inserir una nova subscripció." @@ -5984,36 +6011,6 @@ msgstr "Persones subscrites a %s" msgid "Groups %s is a member of" msgstr "%s grups són membres de" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Ja hi esteu subscrit!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Un usuari t'ha bloquejat." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "No pots subscriure." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "No pots subscriure a un altre a tu mateix." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "No estàs subscrit!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "No s'ha pogut eliminar la subscripció." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "No s'ha pogut eliminar la subscripció." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/cs/LC_MESSAGES/statusnet.po b/locale/cs/LC_MESSAGES/statusnet.po index 192a6572eb..2d6cdda177 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:55:51+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:31+0000\n" "Language-Team: Czech\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -106,7 +106,6 @@ msgstr "Žádné takové oznámení." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Žádný takový uživatel." @@ -564,7 +563,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 #, fuzzy msgid "Account" msgstr "O nás" @@ -957,7 +956,7 @@ msgstr "Neodeslal jste nám profil" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1719,7 +1718,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2069,7 +2068,7 @@ msgstr "Neplatné jméno nebo heslo" msgid "Error setting user. You are probably not authorized." msgstr "Neautorizován." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Přihlásit" @@ -3030,7 +3029,7 @@ msgstr "Chyba v ověřovacím kódu" msgid "Registration successful" msgstr "Registrace úspěšná" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrovat" @@ -3890,7 +3889,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "Neodeslal jste nám profil" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "Nelze vytvořit odebírat" @@ -4342,7 +4342,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Osobní" @@ -4405,51 +4405,78 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Problém při ukládání sdělení" -#: classes/Notice.php:218 +#: classes/Notice.php:219 #, fuzzy msgid "Problem saving notice. Unknown user." msgstr "Problém při ukládání sdělení" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problém při ukládání sdělení" -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Problém při ukládání sdělení" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Chyba v DB při vkládání odpovědi: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +#, fuzzy +msgid "User has blocked you." +msgstr "Uživatel nemá profil." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Nepřihlášen!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Nelze smazat odebírání" + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Nelze smazat odebírání" + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4503,130 +4530,130 @@ msgstr "%1 statusů na %2" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Domů" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Připojit" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Nelze přesměrovat na server: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Odběry" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Odhlásit" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "Vytvořit nový účet" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Nápověda" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Pomoci mi!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Hledat" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "Nové sdělení" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "Nové sdělení" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "Odběry" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "O nás" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Soukromí" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Zdroj" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4635,12 +4662,12 @@ msgstr "" "**%%site.name%%** je služba microblogů, kterou pro vás poskytuje [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** je služba mikroblogů." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4651,43 +4678,43 @@ msgstr "" "dostupná pod [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "Nové sdělení" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 #, fuzzy msgid "After" msgstr "« Novější" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "Starší »" @@ -5002,86 +5029,91 @@ msgstr "Problém při ukládání sdělení" msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Žádný takový uživatel." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Neodeslal jste nám profil" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Neodeslal jste nám profil" msgstr[1] "Neodeslal jste nám profil" msgstr[2] "" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Vzdálený odběr" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Vzdálený odběr" msgstr[1] "Vzdálený odběr" msgstr[2] "" -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Neodeslal jste nám profil" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Neodeslal jste nám profil" msgstr[1] "Neodeslal jste nám profil" msgstr[2] "" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5763,10 +5795,6 @@ msgstr "Chyba při vkládaní vzdáleného profilu" msgid "Duplicate notice" msgstr "Nové sdělení" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Nelze vložit odebírání" @@ -5952,37 +5980,6 @@ msgstr "Vzdálený odběr" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -#, fuzzy -msgid "User has blocked you." -msgstr "Uživatel nemá profil." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Nepřihlášen!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Nelze smazat odebírání" - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Nelze smazat odebírání" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/de/LC_MESSAGES/statusnet.po b/locale/de/LC_MESSAGES/statusnet.po index 6578c2f5c5..820fffcab1 100644 --- a/locale/de/LC_MESSAGES/statusnet.po +++ b/locale/de/LC_MESSAGES/statusnet.po @@ -13,12 +13,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:55:55+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:34+0000\n" "Language-Team: German\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -109,7 +109,6 @@ msgstr "Seite nicht vorhanden" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Unbekannter Benutzer." @@ -568,7 +567,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Konto" @@ -951,7 +950,7 @@ msgstr "Du bist kein Mitglied dieser Gruppe." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Es gab ein Problem mit deinem Sessiontoken." @@ -1702,7 +1701,7 @@ msgstr "%s Gruppen-Mitglieder, Seite %d" msgid "A list of the users in this group." msgstr "Liste der Benutzer in dieser Gruppe." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2090,7 +2089,7 @@ msgid "Error setting user. You are probably not authorized." msgstr "" "Fehler beim setzen des Benutzers. Du bist vermutlich nicht autorisiert." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Anmelden" @@ -2386,7 +2385,7 @@ msgstr "Profil-Einstellungen ansehen" #: actions/othersettings.php:123 msgid "Show or hide profile designs." -msgstr "" +msgstr "Prifil-Designs anzeigen oder verstecken." #: actions/othersettings.php:153 msgid "URL shortening service is too long (max 50 chars)." @@ -2535,7 +2534,7 @@ msgstr "Server" #: actions/pathsadminpanel.php:238 msgid "Site's server hostname." -msgstr "" +msgstr "Server Name der Seite" #: actions/pathsadminpanel.php:242 msgid "Path" @@ -2595,15 +2594,15 @@ msgstr "Avatarverzeichnis" #: actions/pathsadminpanel.php:301 msgid "Backgrounds" -msgstr "" +msgstr "Hintergrundbilder" #: actions/pathsadminpanel.php:305 msgid "Background server" -msgstr "" +msgstr "Server für Hintergrundbilder" #: actions/pathsadminpanel.php:309 msgid "Background path" -msgstr "" +msgstr "Pfad zu den Hintergrundbildern" #: actions/pathsadminpanel.php:313 msgid "Background directory" @@ -2665,20 +2664,20 @@ msgid "Not a valid people tag: %s" msgstr "Ungültiger Personen-Tag: %s" #: actions/peopletag.php:144 -#, fuzzy, php-format +#, php-format msgid "Users self-tagged with %1$s - page %2$d" -msgstr "Benutzer die sich selbst mit %s getagged haben - Seite %d" +msgstr "Benutzer die sich selbst mit %1$s getagged haben - Seite %2$d" #: actions/postnotice.php:84 msgid "Invalid notice content" msgstr "Ungültiger Nachrichteninhalt" #: actions/postnotice.php:90 -#, fuzzy, php-format +#, php-format msgid "Notice license ‘%1$s’ is not compatible with site license ‘%2$s’." msgstr "" -"Die Nachrichtenlizenz '%s' ist nicht kompatibel mit der Lizenz der Seite '%" -"s'." +"Die Nachrichtenlizenz '%1$s' ist nicht kompatibel mit der Lizenz der Seite '%" +"2$s'." #: actions/profilesettings.php:60 msgid "Profile settings" @@ -2741,7 +2740,7 @@ msgstr "Wo du bist, beispielsweise „Stadt, Gebiet, Land“" #: actions/profilesettings.php:138 msgid "Share my current location when posting notices" -msgstr "" +msgstr "Teile meine aktuelle Position wenn ich Nachrichten sende" #: actions/profilesettings.php:145 actions/tagother.php:149 #: actions/tagother.php:209 lib/subscriptionlist.php:106 @@ -2802,9 +2801,8 @@ msgid "Couldn't update user for autosubscribe." msgstr "Autosubscribe konnte nicht aktiviert werden." #: actions/profilesettings.php:359 -#, fuzzy msgid "Couldn't save location prefs." -msgstr "Konnte Tags nicht speichern." +msgstr "Konnte Positions-Einstellungen nicht speichern." #: actions/profilesettings.php:371 msgid "Couldn't save profile." @@ -2821,7 +2819,7 @@ msgstr "Einstellungen gespeichert." #: actions/public.php:83 #, php-format msgid "Beyond the page limit (%s)" -msgstr "" +msgstr "Jenseits des Seitenlimits (%s)" #: actions/public.php:92 msgid "Could not retrieve public stream." @@ -2854,10 +2852,12 @@ msgid "" "This is the public timeline for %%site.name%% but no one has posted anything " "yet." msgstr "" +"Dies ist die öffentliche Zeitlinie von %%site.name%% es wurde allerdings " +"noch nichts gepostet." #: actions/public.php:190 msgid "Be the first to post!" -msgstr "" +msgstr "Sei der erste der etwas schreibt!" #: actions/public.php:194 #, php-format @@ -2898,6 +2898,8 @@ msgstr "Das sind die beliebtesten Tags auf %s " #, php-format msgid "No one has posted a notice with a [hashtag](%%doc.tags%%) yet." msgstr "" +"Bis jetzt hat noch niemand eine Nachricht mit dem Tag [hashtag](%%doc.tags%" +"%) gepostet." #: actions/publictagcloud.php:72 msgid "Be the first to post one!" @@ -3048,7 +3050,7 @@ msgstr "Entschuldigung, ungültiger Bestätigungscode." msgid "Registration successful" msgstr "Registrierung erfolgreich" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrieren" @@ -3366,9 +3368,8 @@ msgstr "" #: actions/showapplication.php:169 actions/version.php:195 #: lib/applicationeditform.php:195 -#, fuzzy msgid "Name" -msgstr "Nutzername" +msgstr "Name" #: actions/showapplication.php:178 lib/applicationeditform.php:222 #, fuzzy @@ -3481,7 +3482,7 @@ msgstr "" #: actions/showfavorites.php:242 msgid "This is a way to share what you like." -msgstr "" +msgstr "Dies ist ein Weg Dinge zu teilen die dir gefallen." #: actions/showgroup.php:82 lib/groupnav.php:86 #, php-format @@ -3681,35 +3682,32 @@ msgstr "" "Software [StatusNet](http://status.net/). " #: actions/showstream.php:305 -#, fuzzy, php-format +#, php-format msgid "Repeat of %s" -msgstr "Antworten an %s" +msgstr "Wiederholung von %s" #: actions/silence.php:65 actions/unsilence.php:65 -#, fuzzy msgid "You cannot silence users on this site." -msgstr "Du kannst diesem Benutzer keine Nachricht schicken." +msgstr "Du kannst Nutzer dieser Seite nicht ruhig stellen." #: actions/silence.php:72 -#, fuzzy msgid "User is already silenced." -msgstr "Dieser Benutzer hat dich blockiert." +msgstr "Nutzer ist bereits ruhig gestellt." #: actions/siteadminpanel.php:69 msgid "Basic settings for this StatusNet site." -msgstr "" +msgstr "Grundeinstellungen für diese StatusNet Seite." #: actions/siteadminpanel.php:132 msgid "Site name must have non-zero length." -msgstr "" +msgstr "Der Seiten Name darf nicht leer sein." #: actions/siteadminpanel.php:140 -#, fuzzy msgid "You must have a valid contact email address." -msgstr "Du musst eine gültige E-Mail-Adresse haben" +msgstr "Du musst eine gültige E-Mail-Adresse haben." #: actions/siteadminpanel.php:158 -#, fuzzy, php-format +#, php-format msgid "Unknown language \"%s\"." msgstr "Unbekannte Sprache „%s“" @@ -3727,7 +3725,7 @@ msgstr "" #: actions/siteadminpanel.php:183 msgid "Minimum text limit is 140 characters." -msgstr "" +msgstr "Minimale Textlänge ist 140 Zeichen." #: actions/siteadminpanel.php:189 msgid "Dupe limit must 1 or more seconds." @@ -3738,13 +3736,12 @@ msgid "General" msgstr "" #: actions/siteadminpanel.php:242 -#, fuzzy msgid "Site name" -msgstr "Seitennachricht" +msgstr "Seitenname" #: actions/siteadminpanel.php:243 msgid "The name of your site, like \"Yourcompany Microblog\"" -msgstr "" +msgstr "Der Name deiner Seite, sowas wie \"DeinUnternehmen Mircoblog\"" #: actions/siteadminpanel.php:247 msgid "Brought by" @@ -3947,7 +3944,8 @@ msgstr "Kein Code eingegeben" msgid "You are not subscribed to that profile." msgstr "Du hast dieses Profil nicht abonniert." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Konnte Abonnement nicht erstellen." @@ -3965,9 +3963,9 @@ msgid "%s subscribers" msgstr "%s Abonnenten" #: actions/subscribers.php:52 -#, fuzzy, php-format +#, php-format msgid "%1$s subscribers, page %2$d" -msgstr "%s Abonnenten, Seite %d" +msgstr "%1$s Abonnenten, Seite %2$d" #: actions/subscribers.php:63 msgid "These are the people who listen to your notices." @@ -4006,9 +4004,9 @@ msgid "%s subscriptions" msgstr "%s Abonnements" #: actions/subscriptions.php:54 -#, fuzzy, php-format +#, php-format msgid "%1$s subscriptions, page %2$d" -msgstr "%s Abonnements, Seite %d" +msgstr "%1$s Abonnements, Seite %2$d" #: actions/subscriptions.php:65 msgid "These are the people whose notices you listen to." @@ -4030,9 +4028,9 @@ msgid "" msgstr "" #: actions/subscriptions.php:123 actions/subscriptions.php:127 -#, fuzzy, php-format +#, php-format msgid "%s is not listening to anyone." -msgstr "%1$s liest ab sofort " +msgstr "%s hat niemanden abonniert." #: actions/subscriptions.php:194 msgid "Jabber" @@ -4043,24 +4041,24 @@ msgid "SMS" msgstr "SMS" #: actions/tag.php:68 -#, fuzzy, php-format +#, php-format msgid "Notices tagged with %1$s, page %2$d" -msgstr "Benutzer die sich selbst mit %s getagged haben - Seite %d" +msgstr "Mit %1$s gekennzeichnete Nachrichten, Seite %2$d" #: actions/tag.php:86 -#, fuzzy, php-format +#, php-format msgid "Notice feed for tag %s (RSS 1.0)" -msgstr "Feed der Nachrichten von %s" +msgstr "Nachrichten Feed für Tag %s (RSS 1.0)" #: actions/tag.php:92 -#, fuzzy, php-format +#, php-format msgid "Notice feed for tag %s (RSS 2.0)" -msgstr "Feed der Nachrichten von %s" +msgstr "Nachrichten Feed für Tag %s (RSS 2.0)" #: actions/tag.php:98 -#, fuzzy, php-format +#, php-format msgid "Notice feed for tag %s (Atom)" -msgstr "Feed der Nachrichten von %s" +msgstr "Nachrichten Feed für Tag %s (Atom)" #: actions/tagother.php:39 #, fuzzy @@ -4128,9 +4126,8 @@ msgid "User is not sandboxed." msgstr "Dieser Benutzer hat dich blockiert." #: actions/unsilence.php:72 -#, fuzzy msgid "User is not silenced." -msgstr "Benutzer hat kein Profil." +msgstr "Der Benutzer ist nicht ruhig gestellt." #: actions/unsubscribe.php:77 msgid "No profile id in request." @@ -4155,15 +4152,15 @@ msgstr "Benutzer" #: actions/useradminpanel.php:69 msgid "User settings for this StatusNet site." -msgstr "" +msgstr "Nutzer Einstellungen dieser StatusNet Seite." #: actions/useradminpanel.php:148 msgid "Invalid bio limit. Must be numeric." -msgstr "" +msgstr "Das Zeichenlimit der Biografie muss numerisch sein!" #: actions/useradminpanel.php:154 msgid "Invalid welcome text. Max length is 255 characters." -msgstr "" +msgstr "Willkommens-Nachricht ungültig. Maximale Länge sind 255 Zeichen." #: actions/useradminpanel.php:164 #, php-format @@ -4193,33 +4190,27 @@ msgstr "" #: actions/useradminpanel.php:235 msgid "Welcome text for new users (Max 255 chars)." -msgstr "" +msgstr "Willkommens-Nachricht für neue Nutzer (maximal 255 Zeichen)." #: actions/useradminpanel.php:240 -#, fuzzy msgid "Default subscription" -msgstr "Alle Abonnements" +msgstr "Standard Abonnement" #: actions/useradminpanel.php:241 -#, fuzzy msgid "Automatically subscribe new users to this user." -msgstr "" -"Abonniere automatisch alle Kontakte, die mich abonnieren (sinnvoll für Nicht-" -"Menschen)" +msgstr "Neue Nutzer abonnieren automatisch diesen Nutzer" #: actions/useradminpanel.php:250 -#, fuzzy msgid "Invitations" -msgstr "Einladung(en) verschickt" +msgstr "Einladungen" #: actions/useradminpanel.php:255 -#, fuzzy msgid "Invitations enabled" -msgstr "Einladung(en) verschickt" +msgstr "Einladungen aktivieren" #: actions/useradminpanel.php:257 msgid "Whether to allow users to invite new users." -msgstr "" +msgstr "Ist es Nutzern erlaubt neue Nutzer einzuladen." #: actions/userauthorization.php:105 msgid "Authorize subscription" @@ -4245,7 +4236,6 @@ msgstr "Akzeptieren" #: actions/userauthorization.php:218 lib/subscribeform.php:115 #: lib/subscribeform.php:139 -#, fuzzy msgid "Subscribe to this user" msgstr "Abonniere diesen Benutzer" @@ -4403,7 +4393,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Eigene" @@ -4468,22 +4458,22 @@ msgstr "Konnte Nachricht nicht mit neuer URI versehen." msgid "DB error inserting hashtag: %s" msgstr "Datenbankfehler beim Einfügen des Hashtags: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problem bei Speichern der Nachricht. Sie ist zu lang." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problem bei Speichern der Nachricht. Unbekannter Benutzer." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Zu schnell zu viele Nachrichten; atme kurz durch und schicke sie erneut in " "ein paar Minuten ab." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4492,31 +4482,57 @@ msgstr "" "Zu schnell zu viele Nachrichten; atme kurz durch und schicke sie erneut in " "ein paar Minuten ab." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" "Du wurdest für das Schreiben von Nachrichten auf dieser Seite gesperrt." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problem bei Speichern der Nachricht." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Problem bei Speichern der Nachricht." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Datenbankfehler beim Einfügen der Antwort: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Dieser Benutzer erlaubt dir nicht ihn zu abonnieren." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Bereits abonniert!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Dieser Benutzer hat dich blockiert." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Nicht abonniert!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Konnte Abonnement nicht löschen." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Konnte Abonnement nicht löschen." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Herzlich willkommen bei %1$s, @%2$s!" @@ -4567,127 +4583,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Seite ohne Titel" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Hauptnavigation" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Startseite" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Persönliches Profil und Freundes-Zeitleiste" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Ändere deine E-Mail, dein Avatar, Passwort, Profil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Verbinden" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Konnte nicht zum Server umleiten: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Hauptnavigation" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Einladen" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Lade Freunde und Kollegen ein dir auf %s zu folgen" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Abmelden" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Von der Seite abmelden" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Neues Konto erstellen" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Auf der Seite anmelden" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Hilfe" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Hilf mir!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Suchen" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Suche nach Leuten oder Text" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Seitennachricht" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Lokale Ansichten" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Neue Nachricht" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Unternavigation" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Über" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "AGB" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privatsphäre" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Quellcode" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:752 +#: lib/action.php:751 #, fuzzy msgid "Badge" msgstr "Stups" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNet-Software-Lizenz" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4696,12 +4712,12 @@ msgstr "" "**%%site.name%%** ist ein Microbloggingdienst von [%%site.broughtby%%](%%" "site.broughtbyurl%%)." -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** ist ein Microbloggingdienst." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4712,42 +4728,42 @@ msgstr "" "(Version %s) betrieben, die unter der [GNU Affero General Public License]" "(http://www.fsf.org/licensing/licenses/agpl-3.0.html) erhältlich ist." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "StatusNet-Software-Lizenz" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 #, fuzzy msgid "All " msgstr "Alle " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "Lizenz." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Seitenerstellung" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Später" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Vorher" @@ -5057,81 +5073,86 @@ msgstr "Problem beim Speichern der Nachricht." msgid "Specify the name of the user to subscribe to" msgstr "Gib den Namen des Benutzers an, den du abonnieren möchtest" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Unbekannter Benutzer." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "%s abonniert" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Gib den Namen des Benutzers ein, den du nicht mehr abonnieren möchtest" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "%s nicht mehr abonniert" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Befehl noch nicht implementiert." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Benachrichtigung deaktiviert." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Konnte Benachrichtigung nicht deaktivieren." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Benachrichtigung aktiviert." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Konnte Benachrichtigung nicht aktivieren." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Du hast dieses Profil nicht abonniert." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Du hast diese Benutzer bereits abonniert:" msgstr[1] "Du hast diese Benutzer bereits abonniert:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Niemand hat Dich abonniert." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Die Gegenseite konnte Dich nicht abonnieren." msgstr[1] "Die Gegenseite konnte Dich nicht abonnieren." -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Du bist in keiner Gruppe Mitglied." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Du bist Mitglied dieser Gruppe:" msgstr[1] "Du bist Mitglied dieser Gruppen:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5245,19 +5266,19 @@ msgstr "Zu Favoriten hinzufügen" #: lib/feed.php:85 msgid "RSS 1.0" -msgstr "" +msgstr "RSS 1.0" #: lib/feed.php:87 msgid "RSS 2.0" -msgstr "" +msgstr "RSS 2.0" #: lib/feed.php:89 msgid "Atom" -msgstr "" +msgstr "Atom" #: lib/feed.php:91 msgid "FOAF" -msgstr "" +msgstr "FOAF" #: lib/feedlist.php:64 msgid "Export data" @@ -5324,12 +5345,12 @@ msgid "Blocked" msgstr "Blockiert" #: lib/groupnav.php:102 -#, fuzzy, php-format +#, php-format msgid "%s blocked users" -msgstr "Benutzer blockieren" +msgstr "in %s blockierte Nutzer" #: lib/groupnav.php:108 -#, fuzzy, php-format +#, php-format msgid "Edit %s group properties" msgstr "%s Gruppeneinstellungen bearbeiten" @@ -5338,14 +5359,14 @@ msgid "Logo" msgstr "Logo" #: lib/groupnav.php:114 -#, fuzzy, php-format +#, php-format msgid "Add or edit %s logo" msgstr "%s Logo hinzufügen oder bearbeiten" #: lib/groupnav.php:120 -#, fuzzy, php-format +#, php-format msgid "Add or edit %s design" -msgstr "%s Logo hinzufügen oder bearbeiten" +msgstr "%s Design hinzufügen oder bearbeiten" #: lib/groupsbymemberssection.php:71 msgid "Groups with most members" @@ -5356,7 +5377,7 @@ msgid "Groups with most posts" msgstr "Gruppen mit den meisten Beiträgen" #: lib/grouptagcloudsection.php:56 -#, fuzzy, php-format +#, php-format msgid "Tags in %s group's notices" msgstr "Tags in den Nachrichten der Gruppe %s" @@ -5395,16 +5416,16 @@ msgstr "Unbekannter Dateityp" #: lib/imagefile.php:217 msgid "MB" -msgstr "" +msgstr "MB" #: lib/imagefile.php:219 msgid "kB" -msgstr "" +msgstr "kB" #: lib/jabber.php:220 #, php-format msgid "[%s]" -msgstr "" +msgstr "[%s]" #: lib/jabber.php:400 #, fuzzy, php-format @@ -5420,14 +5441,12 @@ msgid "Leave" msgstr "Verlassen" #: lib/logingroupnav.php:80 -#, fuzzy msgid "Login with a username and password" -msgstr "Anmelden mit einem Benutzernamen und Passwort" +msgstr "Mit Nutzernamen und Passwort anmelden" #: lib/logingroupnav.php:86 -#, fuzzy msgid "Sign up for a new account" -msgstr "Für ein neues Konto registrieren" +msgstr "Registriere ein neues Nutzerkonto" #: lib/mail.php:172 msgid "Email address confirmation" @@ -5495,11 +5514,9 @@ msgstr "" "$s ändern.\n" #: lib/mail.php:258 -#, fuzzy, php-format +#, php-format msgid "Bio: %s" -msgstr "" -"Biografie: %s\n" -"\n" +msgstr "Biografie: %s" #: lib/mail.php:286 #, php-format @@ -5666,7 +5683,6 @@ msgstr "" "Nachrichten schicken, die nur Du sehen kannst." #: lib/mailbox.php:227 lib/noticelist.php:481 -#, fuzzy msgid "from" msgstr "von" @@ -5687,39 +5703,45 @@ msgid "Sorry, no incoming email allowed." msgstr "Sorry, keinen eingehenden E-Mails gestattet." #: lib/mailhandler.php:228 -#, fuzzy, php-format +#, php-format msgid "Unsupported message type: %s" -msgstr "Bildformat wird nicht unterstützt." +msgstr "Nachrichten-Typ %s wird nicht unterstützt." #: lib/mediafile.php:98 lib/mediafile.php:123 msgid "There was a database error while saving your file. Please try again." msgstr "" +"Beim Speichern der Datei trat ein Datenbank Fehler auf. Bitte versuche es " +"noch einmal." #: lib/mediafile.php:142 msgid "The uploaded file exceeds the upload_max_filesize directive in php.ini." msgstr "" +"Die Größe der hoch geladenen Datei überschreitet die upload_max_filesize " +"Angabe in der php.ini." #: lib/mediafile.php:147 msgid "" "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in " "the HTML form." msgstr "" +"Die Größe der hoch geladenen Datei überschreitet die MAX_FILE_SIZE Angabe, " +"die im HTML Formular angegeben wurde." #: lib/mediafile.php:152 msgid "The uploaded file was only partially uploaded." -msgstr "" +msgstr "Die Datei wurde nur teilweise auf den Server geladen." #: lib/mediafile.php:159 msgid "Missing a temporary folder." -msgstr "" +msgstr "Kein temporäres Verzeichnis gefunden." #: lib/mediafile.php:162 msgid "Failed to write file to disk." -msgstr "" +msgstr "Konnte die Datei nicht auf die Festplatte schreiben." #: lib/mediafile.php:165 msgid "File upload stopped by extension." -msgstr "" +msgstr "Upload der Datei wurde wegen der Dateiendung gestoppt." #: lib/mediafile.php:179 lib/mediafile.php:216 msgid "File exceeds user's quota." @@ -5745,7 +5767,6 @@ msgid "%s is not a supported file type on this server." msgstr "" #: lib/messageform.php:120 -#, fuzzy msgid "Send a direct notice" msgstr "Versende eine direkte Nachricht" @@ -5754,14 +5775,12 @@ msgid "To" msgstr "An" #: lib/messageform.php:159 lib/noticeform.php:185 -#, fuzzy msgid "Available characters" msgstr "Verfügbare Zeichen" #: lib/noticeform.php:160 -#, fuzzy msgid "Send a notice" -msgstr "Nachricht versenden" +msgstr "Nachricht senden" #: lib/noticeform.php:173 #, php-format @@ -5777,14 +5796,12 @@ msgid "Attach a file" msgstr "" #: lib/noticeform.php:212 -#, fuzzy msgid "Share my location" -msgstr "Konnte Tags nicht speichern." +msgstr "Teile meinen Aufenthaltsort" #: lib/noticeform.php:215 -#, fuzzy msgid "Do not share my location" -msgstr "Konnte Tags nicht speichern." +msgstr "Teile meinen Aufenthaltsort nicht" #: lib/noticeform.php:216 msgid "" @@ -5798,21 +5815,20 @@ msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s" msgstr "" #: lib/noticelist.php:430 -#, fuzzy msgid "N" -msgstr "Nein" +msgstr "N" #: lib/noticelist.php:430 msgid "S" -msgstr "" +msgstr "S" #: lib/noticelist.php:431 msgid "E" -msgstr "" +msgstr "O" #: lib/noticelist.php:431 msgid "W" -msgstr "" +msgstr "W" #: lib/noticelist.php:438 msgid "at" @@ -5823,9 +5839,8 @@ msgid "in context" msgstr "im Zusammenhang" #: lib/noticelist.php:582 -#, fuzzy msgid "Repeated by" -msgstr "Erstellt" +msgstr "Wiederholt von" #: lib/noticelist.php:609 msgid "Reply to this notice" @@ -5836,9 +5851,8 @@ msgid "Reply" msgstr "Antworten" #: lib/noticelist.php:654 -#, fuzzy msgid "Notice repeated" -msgstr "Nachricht gelöscht." +msgstr "Nachricht wiederholt" #: lib/nudgeform.php:116 msgid "Nudge this user" @@ -5869,11 +5883,6 @@ msgstr "Fehler beim Einfügen des entfernten Profils" msgid "Duplicate notice" msgstr "Notiz löschen" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "Dieser Benutzer erlaubt dir nicht ihn zu abonnieren." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Konnte neues Abonnement nicht eintragen." @@ -5907,7 +5916,7 @@ msgid "Your sent messages" msgstr "Deine gesendeten Nachrichten" #: lib/personaltagcloudsection.php:56 -#, fuzzy, php-format +#, php-format msgid "Tags in %s's notices" msgstr "Tags in %ss Nachrichten" @@ -5974,28 +5983,24 @@ msgid "Popular" msgstr "Beliebt" #: lib/repeatform.php:107 -#, fuzzy msgid "Repeat this notice?" -msgstr "Auf diese Nachricht antworten" +msgstr "Diese Nachricht wiederholen?" #: lib/repeatform.php:132 -#, fuzzy msgid "Repeat this notice" -msgstr "Auf diese Nachricht antworten" +msgstr "Diese Nachricht wiederholen" #: lib/router.php:665 msgid "No single user defined for single-user mode." msgstr "" #: lib/sandboxform.php:67 -#, fuzzy msgid "Sandbox" -msgstr "Posteingang" +msgstr "Spielwiese" #: lib/sandboxform.php:78 -#, fuzzy msgid "Sandbox this user" -msgstr "Benutzer freigeben" +msgstr "Diesen Nutzer auf die Spielwiese setzen" #: lib/searchaction.php:120 msgid "Search site" @@ -6035,14 +6040,12 @@ msgid "More..." msgstr "" #: lib/silenceform.php:67 -#, fuzzy msgid "Silence" -msgstr "Seitennachricht" +msgstr "Stummschalten" #: lib/silenceform.php:78 -#, fuzzy msgid "Silence this user" -msgstr "Benutzer blockieren" +msgstr "Nutzer verstummen lassen" #: lib/subgroupnav.php:83 #, php-format @@ -6059,36 +6062,6 @@ msgstr "Leute, die %s abonniert haben" msgid "Groups %s is a member of" msgstr "Gruppen in denen %s Mitglied ist" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Bereits abonniert!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Dieser Benutzer hat dich blockiert." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Konnte nicht abbonieren." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Die Gegenseite konnte Dich nicht abonnieren." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Nicht abonniert!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Konnte Abonnement nicht löschen." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Konnte Abonnement nicht löschen." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" @@ -6109,19 +6082,17 @@ msgstr "Top-Schreiber" #: lib/unsandboxform.php:69 msgid "Unsandbox" -msgstr "" +msgstr "Von Spielwiese freigeben" #: lib/unsandboxform.php:80 -#, fuzzy msgid "Unsandbox this user" msgstr "Benutzer freigeben" #: lib/unsilenceform.php:67 msgid "Unsilence" -msgstr "" +msgstr "Stummschalten aufheben" #: lib/unsilenceform.php:78 -#, fuzzy msgid "Unsilence this user" msgstr "Benutzer freigeben" @@ -6147,7 +6118,7 @@ msgstr "Profil Einstellungen ändern" #: lib/userprofile.php:252 msgid "Edit" -msgstr "" +msgstr "Bearbeiten" #: lib/userprofile.php:275 msgid "Send a direct message to this user" @@ -6159,7 +6130,7 @@ msgstr "Nachricht" #: lib/userprofile.php:314 msgid "Moderate" -msgstr "" +msgstr "Moderieren" #: lib/util.php:871 msgid "a few seconds ago" @@ -6216,6 +6187,7 @@ msgid "%s is not a valid color! Use 3 or 6 hex chars." msgstr "%s ist keine gültige Farbe! Verwenden Sie 3 oder 6 Hex-Zeichen." #: lib/xmppmanager.php:402 -#, fuzzy, php-format +#, php-format msgid "Message too long - maximum is %1$d characters, you sent %2$d." -msgstr "Nachricht zu lang - maximal %d Zeichen erlaubt, du hast %d gesendet" +msgstr "" +"Nachricht zu lang - maximal %1$d Zeichen erlaubt, du hast %2$d gesendet." diff --git a/locale/el/LC_MESSAGES/statusnet.po b/locale/el/LC_MESSAGES/statusnet.po index f28a6623d4..90078d0c02 100644 --- a/locale/el/LC_MESSAGES/statusnet.po +++ b/locale/el/LC_MESSAGES/statusnet.po @@ -9,12 +9,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:55:58+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:37+0000\n" "Language-Team: Greek\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -102,7 +102,6 @@ msgstr "Δεν υπάρχει τέτοια σελίδα" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Κανένας τέτοιος χρήστης." @@ -554,7 +553,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Λογαριασμός" @@ -937,7 +936,7 @@ msgstr "Ομάδες με τα περισσότερα μέλη" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1688,7 +1687,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Διαχειριστής" @@ -2028,7 +2027,7 @@ msgstr "Λάθος όνομα χρήστη ή κωδικός" msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Σύνδεση" @@ -2978,7 +2977,7 @@ msgstr "" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -3843,7 +3842,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "Αδύνατη η αποθήκευση των νέων πληροφοριών του προφίλ" @@ -4273,7 +4273,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Προσωπικά" @@ -4336,48 +4336,74 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "Σφάλμα στη βάση δεδομένων κατά την εισαγωγή hashtag: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "" -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Σφάλμα βάσης δεδομένων κατά την εισαγωγή απάντησης: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "" + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Απέτυχε η συνδρομή." + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Απέτυχε η διαγραφή συνδρομής." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Απέτυχε η διαγραφή συνδρομής." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4428,125 +4454,125 @@ msgstr "" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Αρχή" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Σύνδεση" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Αδυναμία ανακατεύθηνσης στο διακομιστή: %s" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Προσκάλεσε φίλους και συναδέλφους σου να γίνουν μέλη στο %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Αποσύνδεση" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Δημιουργία ενός λογαριασμού" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Βοήθεια" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Βοηθήστε με!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Περί" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Συχνές ερωτήσεις" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Επικοινωνία" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, fuzzy, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4555,13 +4581,13 @@ msgstr "" "To **%%site.name%%** είναι μία υπηρεσία microblogging (μικρο-ιστολογίου) που " "έφερε κοντά σας το [%%site.broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, fuzzy, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" "Το **%%site.name%%** είναι μία υπηρεσία microblogging (μικρο-ιστολογίου). " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4569,41 +4595,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "" @@ -4909,82 +4935,87 @@ msgstr "" msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Κανένας τέτοιος χρήστης." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Δεν επιτρέπεται να κάνεις συνδρομητές του λογαριασμού σου άλλους." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Δεν επιτρέπεται να κάνεις συνδρομητές του λογαριασμού σου άλλους." msgstr[1] "Δεν επιτρέπεται να κάνεις συνδρομητές του λογαριασμού σου άλλους." -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Δεν επιτρέπεται να κάνεις συνδρομητές του λογαριασμού σου άλλους." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Δεν επιτρέπεται να κάνεις συνδρομητές του λογαριασμού σου άλλους." msgstr[1] "Δεν επιτρέπεται να κάνεις συνδρομητές του λογαριασμού σου άλλους." -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Δεν είστε μέλος καμίας ομάδας." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Ομάδες με τα περισσότερα μέλη" msgstr[1] "Ομάδες με τα περισσότερα μέλη" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5647,10 +5678,6 @@ msgstr "" msgid "Duplicate notice" msgstr "Διαγραφή μηνύματος" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Απέτυχε η εισαγωγή νέας συνδρομής." @@ -5831,36 +5858,6 @@ msgstr "" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "" - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Απέτυχε η συνδρομή." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Δεν επιτρέπεται να κάνεις συνδρομητές του λογαριασμού σου άλλους." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Απέτυχε η συνδρομή." - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Απέτυχε η διαγραφή συνδρομής." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Απέτυχε η διαγραφή συνδρομής." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/en_GB/LC_MESSAGES/statusnet.po b/locale/en_GB/LC_MESSAGES/statusnet.po index 50431ddfa5..ea92b0b774 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:01+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:40+0000\n" "Language-Team: British English\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -100,7 +100,6 @@ msgstr "No such page" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "No such user." @@ -558,7 +557,7 @@ msgstr "" "the ability to %3$s your %4$s account data. You should only " "give access to your %4$s account to third parties you trust." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Account" @@ -934,7 +933,7 @@ msgstr "You are not the owner of this application." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "There was a problem with your session token." @@ -1685,7 +1684,7 @@ msgstr "%s group members, page %d" msgid "A list of the users in this group." msgstr "A list of the users in this group." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2065,7 +2064,7 @@ msgstr "Incorrect username or password." msgid "Error setting user. You are probably not authorized." msgstr "Error setting user. You are probably not authorised." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Login" @@ -3035,7 +3034,7 @@ msgstr "Error with confirmation code." msgid "Registration successful" msgstr "Registration successful" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Register" @@ -3939,7 +3938,8 @@ msgstr "No code entered" msgid "You are not subscribed to that profile." msgstr "You are not subscribed to that profile." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Could not save subscription." @@ -4396,7 +4396,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Personal" @@ -4460,22 +4460,22 @@ msgstr "Could not update message with new URI." msgid "DB error inserting hashtag: %s" msgstr "DB error inserting hashtag: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Problem saving notice." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problem saving notice. Unknown user." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Too many notices too fast; take a breather and post again in a few minutes." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4483,30 +4483,56 @@ msgid "" msgstr "" "Too many notices too fast; take a breather and post again in a few minutes." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "You are banned from posting notices on this site." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problem saving notice." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Problem saving notice." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "DB error inserting reply: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "You have been banned from subscribing." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "User has blocked you." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Not subscribed!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Couldn't delete subscription." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Couldn't delete subscription." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Welcome to %1$s, @%2$s!" @@ -4556,126 +4582,126 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Untitled page" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Primary site navigation" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Home" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Personal profile and friends timeline" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Change your e-mail, avatar, password, profile" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Connect" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Could not redirect to server: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Primary site navigation" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invite" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invite friends and colleagues to join you on %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Logout" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Logout from the site" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Create an account" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Login to the site" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Help" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Help me!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Search" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Search for people or text" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Site notice" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Local views" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Page notice" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Secondary site navigation" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "About" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "F.A.Q." -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privacy" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Source" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contact" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Badge" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNet software licence" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4684,12 +4710,12 @@ msgstr "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%)." -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** is a microblogging service." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4700,41 +4726,41 @@ msgstr "" "s, available under the [GNU Affero General Public Licence](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Site content license" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "All " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licence." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Pagination" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "After" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Before" @@ -5047,83 +5073,88 @@ msgstr "Error saving notice." msgid "Specify the name of the user to subscribe to" msgstr "Specify the name of the user to subscribe to" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "No such user." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Subscribed to %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Specify the name of the user to unsubscribe from" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Unsubscribed from %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Command not yet implemented." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notification off." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Can't turn off notification." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notification on." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Can't turn on notification." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "You are not subscribed to that profile." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "You are already subscribed to these users:" msgstr[1] "You are already subscribed to these users:" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Could not subscribe other to you." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Could not subscribe other to you." msgstr[1] "Could not subscribe other to you." -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "You are not a member of that group." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "You are not a member of that group." msgstr[1] "You are not a member of that group." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5806,10 +5837,6 @@ msgstr "Error inserting remote profile." msgid "Duplicate notice" msgstr "Duplicate notice" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "You have been banned from subscribing." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Couldn't insert new subscription." @@ -5991,36 +6018,6 @@ msgstr "People subscribed to %s" msgid "Groups %s is a member of" msgstr "Groups %s is a member of" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "User has blocked you." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Could not subscribe." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Could not subscribe other to you." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Not subscribed!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Couldn't delete subscription." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Couldn't delete subscription." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/es/LC_MESSAGES/statusnet.po b/locale/es/LC_MESSAGES/statusnet.po index 06c3ee045a..3ce394aa6f 100644 --- a/locale/es/LC_MESSAGES/statusnet.po +++ b/locale/es/LC_MESSAGES/statusnet.po @@ -12,12 +12,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:07+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:43+0000\n" "Language-Team: Spanish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -102,7 +102,6 @@ msgstr "No existe tal página" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "No existe ese usuario." @@ -564,7 +563,7 @@ msgstr "" "permiso para %3$s la información de tu cuenta %4$s. Sólo " "debes dar acceso a tu cuenta %4$s a terceras partes en las que confíes." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Cuenta" @@ -943,7 +942,7 @@ msgstr "No eres el propietario de esta aplicación." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Hubo problemas con tu clave de sesión." @@ -1691,7 +1690,7 @@ msgstr "%1$s miembros de grupo, página %2$d" msgid "A list of the users in this group." msgstr "Lista de los usuarios en este grupo." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2075,7 +2074,7 @@ msgstr "Nombre de usuario o contraseña incorrectos." msgid "Error setting user. You are probably not authorized." msgstr "Error al configurar el usuario. Posiblemente no tengas autorización." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Inicio de sesión" @@ -3040,7 +3039,7 @@ msgstr "El código de invitación no es válido." msgid "Registration successful" msgstr "Registro exitoso." -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrarse" @@ -3916,7 +3915,8 @@ msgstr "No ingresó código" msgid "You are not subscribed to that profile." msgstr "No te has suscrito a ese perfil." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "No se ha podido guardar la suscripción." @@ -4359,7 +4359,7 @@ msgstr "" msgid "Plugins" msgstr "Complementos" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Sesiones" @@ -4421,22 +4421,22 @@ msgstr "No se pudo actualizar mensaje con nuevo URI." msgid "DB error inserting hashtag: %s" msgstr "Error de la BD al insertar la etiqueta clave: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Ha habido un problema al guardar el mensaje. Es muy largo." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Ha habido un problema al guardar el mensaje. Usuario desconocido." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Demasiados avisos demasiado rápido; para y publicar nuevamente en unos " "minutos." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4445,30 +4445,56 @@ msgstr "" "Demasiados avisos demasiado rápido; para y publicar nuevamente en unos " "minutos." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Tienes prohibido publicar avisos en este sitio." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Hubo un problema al guardar el aviso." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Hubo un problema al guardar el aviso." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Error de BD al insertar respuesta: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Se te ha prohibido la suscripción." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "El usuario te ha bloqueado." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "¡No estás suscrito!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "No se pudo eliminar la suscripción." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "No se pudo eliminar la suscripción." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Bienvenido a %1$s, @%2$s!" @@ -4519,124 +4545,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Página sin título" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Navegación de sitio primario" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Inicio" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Perfil personal y línea de tiempo de amigos" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Cambia tu correo electrónico, avatar, contraseña, perfil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Conectarse" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Conectar a los servicios" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Cambiar la configuración del sitio" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitar" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invita a amigos y colegas a unirse a %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Salir" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Salir de sitio" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Crear una cuenta" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Ingresar a sitio" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Ayuda" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Ayúdame!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Buscar" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Buscar personas o texto" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Aviso de sitio" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Vistas locales" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Aviso de página" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Navegación de sitio secundario" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Acerca de" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Preguntas Frecuentes" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privacidad" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Fuente" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Ponerse en contacto" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Insignia" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licencia de software de StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4645,12 +4671,12 @@ msgstr "" "**%%site.name%%** es un servicio de microblogueo de [%%site.broughtby%%**](%%" "site.broughtbyurl%%)." -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** es un servicio de microblogueo." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4661,43 +4687,43 @@ msgstr "" "disponible bajo la [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licencia de contenido del sitio" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Derechos de autor de contenido y datos por los colaboradores. Todos los " "derechos reservados." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Todo" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "Licencia." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginación" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Después" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Antes" @@ -5005,80 +5031,85 @@ msgstr "Hubo un problema al guardar el aviso." msgid "Specify the name of the user to subscribe to" msgstr "Especificar el nombre del usuario a suscribir" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "No existe ese usuario." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Suscrito a %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Especificar el nombre del usuario para desuscribirse de" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Desuscrito de %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Todavía no se implementa comando." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notificación no activa." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "No se puede desactivar notificación." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notificación activada." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "No se puede activar notificación." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "No estás suscrito a nadie." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Ya estás suscrito a estos usuarios:" msgstr[1] "Ya estás suscrito a estos usuarios:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Nadie está suscrito a ti." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "No se pudo suscribir otro a ti." msgstr[1] "No se pudo suscribir otro a ti." -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "No eres miembro de ningún grupo" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Eres miembro de este grupo:" msgstr[1] "Eres miembro de estos grupos:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5759,10 +5790,6 @@ msgstr "Error al insertar perfil remoto" msgid "Duplicate notice" msgstr "Duplicar aviso" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Se te ha prohibido la suscripción." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "No se pudo insertar una nueva suscripción." @@ -5949,36 +5976,6 @@ msgstr "Personas suscritas a %s" msgid "Groups %s is a member of" msgstr "%s es miembro de los grupos" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "El usuario te ha bloqueado." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "No se pudo suscribir." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "No se pudo suscribir otro a ti." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "¡No estás suscrito!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "No se pudo eliminar la suscripción." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "No se pudo eliminar la suscripción." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/fa/LC_MESSAGES/statusnet.po b/locale/fa/LC_MESSAGES/statusnet.po index 1d328d4f1f..877debaec3 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:13+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:49+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.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); Translate extension (2010-01-16)\n" "X-Translation-Project: translatewiki.net at http://translatewiki.net\n" #: actions/accessadminpanel.php:54 lib/adminpanelaction.php:326 @@ -105,7 +105,6 @@ msgstr "چنین صفحه‌ای وجود ندارد" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "چنین کاربری وجود ندارد." @@ -557,7 +556,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "حساب کاربری" @@ -941,7 +940,7 @@ msgstr "شما یک عضو این گروه نیستید." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1689,7 +1688,7 @@ msgstr "اعضای گروه %s، صفحهٔ %d" msgid "A list of the users in this group." msgstr "یک فهرست از کاربران در این گروه" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "مدیر" @@ -2042,7 +2041,7 @@ msgstr "نام کاربری یا رمز عبور نادرست." msgid "Error setting user. You are probably not authorized." msgstr "خطا در تنظیم کاربر. شما احتمالا اجازه ی این کار را ندارید." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "ورود" @@ -2995,7 +2994,7 @@ msgstr "با عرض تاسف، کد دعوت نا معتبر است." msgid "Registration successful" msgstr "ثبت نام با موفقیت انجام شد." -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "ثبت نام" @@ -3844,7 +3843,8 @@ msgstr "کدی وارد نشد" msgid "You are not subscribed to that profile." msgstr "شما به این پروفيل متعهد نشدید" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "" @@ -4266,7 +4266,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "شخصی" @@ -4328,22 +4328,22 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "مشکل در ذخیره کردن پیام. بسیار طولانی." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "مشکل در ذخیره کردن پیام. کاربر نا شناخته." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "تعداد خیلی زیاد آگهی و بسیار سریع؛ استراحت کنید و مجددا دقایقی دیگر ارسال " "کنید." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4351,30 +4351,54 @@ msgstr "" "تعداد زیاد پیام های دو نسخه ای و بسرعت؛ استراحت کنید و دقایقی دیگر مجددا " "ارسال کنید." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "شما از فرستادن پست در این سایت مردود شدید ." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "مشکل در ذخیره کردن آگهی." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "مشکل در ذخیره کردن آگهی." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "قبلا تایید شده !" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "" + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "تایید نشده!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "" + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "" + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "خوش امدید به %1$s , @%2$s!" @@ -4424,136 +4448,136 @@ msgstr "%s گروه %s را ترک کرد." msgid "Untitled page" msgstr "صفحه ی بدون عنوان" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "خانه" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "آدرس ایمیل، آواتار، کلمه ی عبور، پروفایل خود را تغییر دهید" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "وصل‌شدن" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "متصل شدن به خدمات" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "تغییر پیکربندی سایت" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "دعوت‌کردن" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr " به شما ملحق شوند %s دوستان و همکاران را دعوت کنید تا در" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "خروج" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "خارج شدن از سایت ." -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "یک حساب کاربری بسازید" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "ورود به وب‌گاه" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "کمک" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "به من کمک کنید!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "جست‌وجو" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "جستجو برای شخص با متن" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "خبر سایت" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "دید محلی" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "خبر صفحه" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "دربارهٔ" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "سوال‌های رایج" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "خصوصی" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "منبع" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "تماس" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNet مجوز نرم افزار" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%). " msgstr "" -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4561,41 +4585,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "مجوز محتویات سایت" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "همه " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "مجوز." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "صفحه بندى" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "بعد از" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "قبل از" @@ -4904,77 +4928,82 @@ msgstr "خطا هنگام ذخیره ی آگهی" msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "چنین کاربری وجود ندارد." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "دستور هنوز اجرا نشده" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "ناتوان در خاموش کردن آگاه سازی." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "آگاه سازی فعال است." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "ناتوان در روشن کردن آگاه سازی." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "فرمان ورود از کار افتاده است" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "شما توسط هیچ کس تصویب نشده اید ." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "هم اکنون شما این کاربران را دنبال می‌کنید: " -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "هیچکس شما را تایید نکرده ." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "هیچکس شما را تایید نکرده ." -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "شما در هیچ گروهی عضو نیستید ." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "شما یک عضو این گروه نیستید." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5638,10 +5667,6 @@ msgstr "" msgid "Duplicate notice" msgstr "" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "" @@ -5819,34 +5844,6 @@ msgstr "" msgid "Groups %s is a member of" msgstr "هست عضو %s گروه" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "قبلا تایید شده !" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "" - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "تایید نشده!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "" - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/fi/LC_MESSAGES/statusnet.po b/locale/fi/LC_MESSAGES/statusnet.po index f37da7b0f6..e1222193bb 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:10+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:46+0000\n" "Language-Team: Finnish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -107,7 +107,6 @@ msgstr "Sivua ei ole." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Käyttäjää ei ole." @@ -573,7 +572,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Käyttäjätili" @@ -958,7 +957,7 @@ msgstr "Sinä et kuulu tähän ryhmään." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Istuntoavaimesi kanssa oli ongelma." @@ -1722,7 +1721,7 @@ msgstr "Ryhmän %s jäsenet, sivu %d" msgid "A list of the users in this group." msgstr "Lista ryhmän käyttäjistä." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Ylläpito" @@ -2103,7 +2102,7 @@ msgstr "Väärä käyttäjätunnus tai salasana" msgid "Error setting user. You are probably not authorized." msgstr "Sinulla ei ole valtuutusta tähän." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Kirjaudu sisään" @@ -3083,7 +3082,7 @@ msgstr "Virheellinen kutsukoodin." msgid "Registration successful" msgstr "Rekisteröityminen onnistui" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Rekisteröidy" @@ -3984,7 +3983,8 @@ msgstr "Koodia ei ole syötetty." 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 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Tilausta ei onnistuttu tallentamaan." @@ -4436,7 +4436,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Omat" @@ -4500,23 +4500,23 @@ msgstr "Viestin päivittäminen uudella URI-osoitteella ei onnistunut." msgid "DB error inserting hashtag: %s" msgstr "Tietokantavirhe tallennettaessa risutagiä: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Ongelma päivityksen tallentamisessa." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Virhe tapahtui päivityksen tallennuksessa. Tuntematon käyttäjä." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Liian monta päivitystä liian nopeasti; pidä pieni hengähdystauko ja jatka " "päivityksien lähettämista muutaman minuutin päästä." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4524,30 +4524,57 @@ msgstr "" "Liian monta päivitystä liian nopeasti; pidä pieni hengähdystauko ja jatka " "päivityksien lähettämista muutaman minuutin päästä." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Päivityksesi tähän palveluun on estetty." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Ongelma päivityksen tallentamisessa." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Ongelma päivityksen tallentamisessa." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Tietokantavirhe tallennettaessa vastausta: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 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 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Käyttäjä on asettanut eston sinulle." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Ei ole tilattu!." + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Ei voitu poistaa tilausta." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Ei voitu poistaa tilausta." + +#: classes/User.php:372 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Viesti käyttäjälle %1$s, %2$s" @@ -4598,127 +4625,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Nimetön sivu" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Ensisijainen sivunavigointi" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Koti" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Henkilökohtainen profiili ja kavereiden aikajana" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Muuta sähköpostiosoitettasi, kuvaasi, salasanaasi, profiiliasi" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Yhdistä" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Ei voitu uudelleenohjata palvelimelle: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Ensisijainen sivunavigointi" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Kutsu" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Kutsu kavereita ja työkavereita liittymään palveluun %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Kirjaudu ulos" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Kirjaudu ulos palvelusta" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Luo uusi käyttäjätili" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Kirjaudu sisään palveluun" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Ohjeet" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Auta minua!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Haku" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Hae ihmisiä tai tekstiä" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Palvelun ilmoitus" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Paikalliset näkymät" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Sivuilmoitus" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Toissijainen sivunavigointi" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Tietoa" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "UKK" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Yksityisyys" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Lähdekoodi" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Ota yhteyttä" -#: lib/action.php:752 +#: lib/action.php:751 #, fuzzy msgid "Badge" msgstr "Tönäise" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNet-ohjelmiston lisenssi" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4727,12 +4754,12 @@ msgstr "" "**%%site.name%%** on mikroblogipalvelu, jonka tarjoaa [%%site.broughtby%%](%%" "site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** on mikroblogipalvelu. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4743,42 +4770,42 @@ msgstr "" "versio %s, saatavilla lisenssillä [GNU Affero General Public License](http://" "www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "StatusNet-ohjelmiston lisenssi" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Kaikki " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "lisenssi." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Sivutus" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Myöhemmin" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Aiemmin" @@ -5096,83 +5123,88 @@ msgstr "Ongelma päivityksen tallentamisessa." msgid "Specify the name of the user to subscribe to" msgstr "Anna käyttäjätunnus, jonka päivitykset haluat tilata" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Käyttäjää ei ole." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Käyttäjän %s päivitykset tilattu" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Anna käyttäjätunnus, jonka päivityksien tilauksen haluat lopettaa" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Käyttäjän %s päivitysten tilaus lopetettu" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Komentoa ei ole vielä toteutettu." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Ilmoitukset pois päältä." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Ilmoituksia ei voi pistää pois päältä." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Ilmoitukset päällä." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Ilmoituksia ei voi pistää päälle." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Et ole tilannut tämän käyttäjän päivityksiä." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Olet jos tilannut seuraavien käyttäjien päivitykset:" msgstr[1] "Olet jos tilannut seuraavien käyttäjien päivitykset:" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Toista ei voitu asettaa tilaamaan sinua." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Toista ei voitu asettaa tilaamaan sinua." msgstr[1] "Toista ei voitu asettaa tilaamaan sinua." -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Sinä et kuulu tähän ryhmään." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Sinä et kuulu tähän ryhmään." msgstr[1] "Sinä et kuulu tähän ryhmään." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5863,11 +5895,6 @@ msgstr "Virhe tapahtui uuden etäprofiilin lisäämisessä" msgid "Duplicate notice" msgstr "Poista päivitys" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "Käyttäjä on estänyt sinua tilaamasta päivityksiä." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Ei voitu lisätä uutta tilausta." @@ -6055,36 +6082,6 @@ msgstr "Ihmiset jotka ovat käyttäjän %s tilaajia" msgid "Groups %s is a member of" msgstr "Ryhmät, joiden jäsen %s on" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Käyttäjä on asettanut eston sinulle." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Ei voitu tilata." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Toista ei voitu asettaa tilaamaan sinua." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Ei ole tilattu!." - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Ei voitu poistaa tilausta." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Ei voitu poistaa tilausta." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/fr/LC_MESSAGES/statusnet.po b/locale/fr/LC_MESSAGES/statusnet.po index ad0ae7fc5a..663f4fc1d1 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:16+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:52+0000\n" "Language-Team: French\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -104,7 +104,6 @@ msgstr "Page non trouvée" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Utilisateur non trouvé." @@ -573,7 +572,7 @@ msgstr "" "devriez donner l’accès à votre compte %4$s qu’aux tiers à qui vous faites " "confiance." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Compte" @@ -953,7 +952,7 @@ msgstr "Vous n’êtes pas le propriétaire de cette application." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Un problème est survenu avec votre jeton de session." @@ -1698,7 +1697,7 @@ msgstr "Membres du groupe %1$s - page %2$d" msgid "A list of the users in this group." msgstr "Liste des utilisateurs inscrits à ce groupe." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Administrer" @@ -2093,7 +2092,7 @@ msgstr "" "Erreur lors de la mise en place de l’utilisateur. Vous n’y êtes probablement " "pas autorisé." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Ouvrir une session" @@ -3068,7 +3067,7 @@ msgstr "Désolé, code d’invitation invalide." msgid "Registration successful" msgstr "Compte créé avec succès" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Créer un compte" @@ -3978,7 +3977,8 @@ msgstr "Aucun code entré" msgid "You are not subscribed to that profile." msgstr "Vous n’êtes pas abonné(e) à ce profil." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Impossible d’enregistrer l’abonnement." @@ -4445,7 +4445,7 @@ msgstr "" msgid "Plugins" msgstr "Extensions" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Version" @@ -4506,22 +4506,22 @@ msgstr "Impossible de mettre à jour le message avec un nouvel URI." msgid "DB error inserting hashtag: %s" msgstr "Erreur de base de donnée en insérant la marque (hashtag) : %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problème lors de l’enregistrement de l’avis ; trop long." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Erreur lors de l’enregistrement de l’avis. Utilisateur inconnu." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Trop d’avis, trop vite ! Faites une pause et publiez à nouveau dans quelques " "minutes." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4529,29 +4529,53 @@ msgstr "" "Trop de messages en double trop vite ! Prenez une pause et publiez à nouveau " "dans quelques minutes." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Il vous est interdit de poster des avis sur ce site." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problème lors de l’enregistrement de l’avis." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Problème lors de l’enregistrement de la boîte de réception du groupe." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Erreur de base de donnée en insérant la réponse :%s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Il vous avez été interdit de vous abonner." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Déjà abonné !" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Cet utilisateur vous a bloqué." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Pas abonné !" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Impossible de supprimer l’abonnement à soi-même." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Impossible de cesser l’abonnement" + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Bienvenue à %1$s, @%2$s !" @@ -4601,124 +4625,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Page sans nom" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Navigation primaire du site" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Accueil" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Profil personnel et flux des amis" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Modifier votre courriel, avatar, mot de passe, profil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Connecter" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Se connecter aux services" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Modifier la configuration du site" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Inviter" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Inviter des amis et collègues à vous rejoindre dans %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Fermeture de session" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Fermer la session" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Créer un compte" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Ouvrir une session" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Aide" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "À l’aide !" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Rechercher" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Rechercher des personnes ou du texte" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Notice du site" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Vues locales" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Avis de la page" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Navigation secondaire du site" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "À propos" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "CGU" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Confidentialité" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Source" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contact" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Insigne" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licence du logiciel StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4727,12 +4751,12 @@ msgstr "" "**%%site.name%%** est un service de microblogging qui vous est proposé par " "[%%site.broughtby%%](%%site.broughtbyurl%%)." -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** est un service de micro-blogging." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4743,45 +4767,45 @@ msgstr "" "version %s, disponible sous la licence [GNU Affero General Public License] " "(http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licence du contenu du site" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Le contenu et les données de %1$s sont privés et confidentiels." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Le contenu et les données sont sous le droit d’auteur de %1$s. Tous droits " "réservés." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Le contenu et les données sont sous le droit d’auteur du contributeur. Tous " "droits réservés." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Tous " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licence." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Pagination" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Après" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Avant" @@ -5088,82 +5112,87 @@ msgstr "Problème lors de l’enregistrement de l’avis." msgid "Specify the name of the user to subscribe to" msgstr "Indiquez le nom de l’utilisateur auquel vous souhaitez vous abonner" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Utilisateur non trouvé." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Abonné à %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Indiquez le nom de l’utilisateur duquel vous souhaitez vous désabonner" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Désabonné de %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Cette commande n’a pas encore été implémentée." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Avertissements désactivés." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Impossible de désactiver les avertissements." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Avertissements activés." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Impossible d’activer les avertissements." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "La commande d’ouverture de session est désactivée" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Ce lien n’est utilisable qu’une seule fois, et est valable uniquement " "pendant 2 minutes : %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Vous n’êtes abonné(e) à personne." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Vous êtes abonné à cette personne :" msgstr[1] "Vous êtes abonné à ces personnes :" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Personne ne s’est abonné à vous." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Cette personne est abonnée à vous :" msgstr[1] "Ces personnes sont abonnées à vous :" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Vous n’êtes membre d’aucun groupe." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Vous êtes membre de ce groupe :" msgstr[1] "Vous êtes membre de ces groupes :" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5953,10 +5982,6 @@ msgstr "Erreur lors de l’insertion du profil distant" msgid "Duplicate notice" msgstr "Dupliquer l’avis" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Il vous avez été interdit de vous abonner." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Impossible d’insérer un nouvel abonnement." @@ -6133,34 +6158,6 @@ msgstr "Abonnés de %s" msgid "Groups %s is a member of" msgstr "Groupes de %s" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Déjà abonné !" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Cet utilisateur vous a bloqué." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Impossible de s’abonner." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Impossible d’abonner une autre personne à votre profil." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Pas abonné !" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Impossible de supprimer l’abonnement à soi-même." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Impossible de cesser l’abonnement" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/ga/LC_MESSAGES/statusnet.po b/locale/ga/LC_MESSAGES/statusnet.po index 25adc99870..abbf011aaa 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:19+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:55+0000\n" "Language-Team: Irish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -107,7 +107,6 @@ msgstr "Non existe a etiqueta." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Ningún usuario." @@ -569,7 +568,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 #, fuzzy msgid "Account" msgstr "Sobre" @@ -968,7 +967,7 @@ msgstr "Non estás suscrito a ese perfil" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 #, fuzzy msgid "There was a problem with your session token." msgstr "Houbo un problema co teu token de sesión. Tentao de novo, anda..." @@ -1756,7 +1755,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2137,7 +2136,7 @@ msgstr "Usuario ou contrasinal incorrectos." msgid "Error setting user. You are probably not authorized." msgstr "Non está autorizado." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Inicio de sesión" @@ -3122,7 +3121,7 @@ msgstr "Acounteceu un erro co código de confirmación." msgid "Registration successful" msgstr "Xa estas rexistrado!!" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Rexistrar" @@ -4036,7 +4035,8 @@ msgstr "Non se inseriu ningún código" msgid "You are not subscribed to that profile." msgstr "Non estás suscrito a ese perfil" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Non se pode gardar a subscrición." @@ -4492,7 +4492,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Persoal" @@ -4556,23 +4556,23 @@ msgstr "Non se puido actualizar a mensaxe coa nova URI." msgid "DB error inserting hashtag: %s" msgstr "Erro ó inserir o hashtag na BD: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Aconteceu un erro ó gardar o chío." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Aconteceu un erro ó gardar o chío. Usuario descoñecido." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Demasiados chíos en pouco tempo; tomate un respiro e envíao de novo dentro " "duns minutos." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4581,30 +4581,57 @@ msgstr "" "Demasiados chíos en pouco tempo; tomate un respiro e envíao de novo dentro " "duns minutos." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Tes restrinxido o envio de chíos neste sitio." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Aconteceu un erro ó gardar o chío." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Aconteceu un erro ó gardar o chío." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Erro ó inserir a contestación na BD: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 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 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "O usuario bloqueoute." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Non está suscrito!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Non se pode eliminar a subscrición." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Non se pode eliminar a subscrición." + +#: classes/User.php:372 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Mensaxe de %1$s en %2$s" @@ -4658,134 +4685,134 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Persoal" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 #, fuzzy msgid "Change your email, avatar, password, profile" msgstr "Cambiar contrasinal" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Conectar" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Non se pode redireccionar ao servidor: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Navegación de subscricións" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitar" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, fuzzy, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" "Emprega este formulario para invitar ós teus amigos e colegas a empregar " "este servizo." -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Sair" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "Crear nova conta" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Axuda" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "Axuda" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Buscar" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "Novo chío" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "Novo chío" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "Navegación de subscricións" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Sobre" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Preguntas frecuentes" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privacidade" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Fonte" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contacto" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4794,12 +4821,12 @@ msgstr "" "**%%site.name%%** é un servizo de microbloguexo que che proporciona [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** é un servizo de microbloguexo." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4810,44 +4837,44 @@ msgstr "" "%s, dispoñible baixo licenza [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "Atopar no contido dos chíos" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 #, fuzzy msgid "All " msgstr "Todos" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 #, fuzzy msgid "After" msgstr "« Despois" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "Antes »" @@ -5170,55 +5197,60 @@ msgstr "Aconteceu un erro ó gardar o chío." msgid "Specify the name of the user to subscribe to" msgstr "Especifica o nome do usuario ó que queres suscribirte" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Ningún usuario." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Suscrito a %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Especifica o nome de usuario ó que queres deixar de seguir" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Desuscribir de %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Comando non implementado." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notificación desactivada." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "No se pode desactivar a notificación." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notificación habilitada." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Non se pode activar a notificación." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Non estás suscrito a ese perfil" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Xa estas suscrito a estes usuarios:" @@ -5227,12 +5259,12 @@ msgstr[2] "" msgstr[3] "" msgstr[4] "" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Outro usuario non se puido suscribir a ti." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Outro usuario non se puido suscribir a ti." @@ -5241,12 +5273,12 @@ msgstr[2] "" msgstr[3] "" msgstr[4] "" -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Non estás suscrito a ese perfil" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Non estás suscrito a ese perfil" @@ -5255,7 +5287,7 @@ msgstr[2] "" msgstr[3] "" msgstr[4] "" -#: lib/command.php:728 +#: lib/command.php:741 #, fuzzy msgid "" "Commands:\n" @@ -6031,11 +6063,6 @@ msgstr "Aconteceu un erro ó inserir o perfil remoto" msgid "Duplicate notice" msgstr "Eliminar chío" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "Este usuario non che permite suscribirte a el." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Non se puido inserir a nova subscrición." @@ -6227,36 +6254,6 @@ msgstr "Suscrito a %s" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "O usuario bloqueoute." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "No se pode suscribir." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Outro usuario non se puido suscribir a ti." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Non está suscrito!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Non se pode eliminar a subscrición." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Non se pode eliminar a subscrición." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/he/LC_MESSAGES/statusnet.po b/locale/he/LC_MESSAGES/statusnet.po index c67c14fc22..d90c74f5e4 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:22+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:02:58+0000\n" "Language-Team: Hebrew\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -104,7 +104,6 @@ msgstr "אין הודעה כזו." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "אין משתמש כזה." @@ -562,7 +561,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 #, fuzzy msgid "Account" msgstr "אודות" @@ -957,7 +956,7 @@ msgstr "לא שלחנו אלינו את הפרופיל הזה" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1727,7 +1726,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2077,7 +2076,7 @@ msgstr "שם משתמש או סיסמה לא נכונים." msgid "Error setting user. You are probably not authorized." msgstr "לא מורשה." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "היכנס" @@ -3036,7 +3035,7 @@ msgstr "שגיאה באישור הקוד." msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "הירשם" @@ -3891,7 +3890,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "לא שלחנו אלינו את הפרופיל הזה" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "יצירת המנוי נכשלה." @@ -4342,7 +4342,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "אישי" @@ -4405,51 +4405,78 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "בעיה בשמירת ההודעה." -#: classes/Notice.php:218 +#: classes/Notice.php:219 #, fuzzy msgid "Problem saving notice. Unknown user." msgstr "בעיה בשמירת ההודעה." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "בעיה בשמירת ההודעה." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "בעיה בשמירת ההודעה." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "שגיאת מסד נתונים בהכנסת התגובה: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +#, fuzzy +msgid "User has blocked you." +msgstr "למשתמש אין פרופיל." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "לא מנוי!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "מחיקת המנוי לא הצליחה." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "מחיקת המנוי לא הצליחה." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4503,131 +4530,131 @@ msgstr "הסטטוס של %1$s ב-%2$s " msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "בית" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "התחבר" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "נכשלה ההפניה לשרת: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "הרשמות" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "צא" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "צור חשבון חדש" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "עזרה" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "עזרה" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "חיפוש" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "הודעה חדשה" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "הודעה חדשה" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "הרשמות" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "אודות" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "רשימת שאלות נפוצות" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "פרטיות" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "מקור" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "צור קשר" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4636,12 +4663,12 @@ msgstr "" "**%%site.name%%** הוא שרות ביקרובלוג הניתן על ידי [%%site.broughtby%%](%%" "site.broughtbyurl%%)." -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** הוא שרות ביקרובלוג." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4652,43 +4679,43 @@ msgstr "" "s, המופצת תחת רשיון [GNU Affero General Public License](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)" -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "הודעה חדשה" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 #, fuzzy msgid "After" msgstr "<< אחרי" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "לפני >>" @@ -5003,83 +5030,88 @@ msgstr "בעיה בשמירת ההודעה." msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "אין משתמש כזה." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "לא שלחנו אלינו את הפרופיל הזה" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "לא שלחנו אלינו את הפרופיל הזה" msgstr[1] "לא שלחנו אלינו את הפרופיל הזה" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "הרשמה מרוחקת" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "הרשמה מרוחקת" msgstr[1] "הרשמה מרוחקת" -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "לא שלחנו אלינו את הפרופיל הזה" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "לא שלחנו אלינו את הפרופיל הזה" msgstr[1] "לא שלחנו אלינו את הפרופיל הזה" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5762,10 +5794,6 @@ msgstr "שגיאה בהכנסת פרופיל מרוחק" msgid "Duplicate notice" msgstr "הודעה חדשה" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "הכנסת מנוי חדש נכשלה." @@ -5953,37 +5981,6 @@ msgstr "הרשמה מרוחקת" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -#, fuzzy -msgid "User has blocked you." -msgstr "למשתמש אין פרופיל." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "לא מנוי!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "מחיקת המנוי לא הצליחה." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "מחיקת המנוי לא הצליחה." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/hsb/LC_MESSAGES/statusnet.po b/locale/hsb/LC_MESSAGES/statusnet.po index c9ed505a2a..d8f5480ac8 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:25+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:01+0000\n" "Language-Team: Dutch\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -103,7 +103,6 @@ msgstr "Strona njeeksistuje" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Wužiwar njeeksistuje" @@ -546,7 +545,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Konto" @@ -922,7 +921,7 @@ msgstr "Njejsy wobsedźer tuteje aplikacije." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1646,7 +1645,7 @@ msgstr "%1$s skupinskich čłonow, strona %2$d" msgid "A list of the users in this group." msgstr "Lisćina wužiwarjow w tutej skupinje." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -1978,7 +1977,7 @@ msgstr "Wopačne wužiwarske mjeno abo hesło." msgid "Error setting user. You are probably not authorized." msgstr "Zmylk při nastajenju wužiwarja. Snano njejsy awtorizowany." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Přizjewić" @@ -2898,7 +2897,7 @@ msgstr "Wodaj, njepłaćiwy přeprošenski kod." msgid "Registration successful" msgstr "Registrowanje wuspěšne" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrować" @@ -3724,7 +3723,8 @@ msgstr "Žadyn kod zapodaty" msgid "You are not subscribed to that profile." msgstr "Njejsy tón profil abonował." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "" @@ -4146,7 +4146,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Wersija" @@ -4205,48 +4205,72 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "" -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Hižo abonowany!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Wužiwar je će zablokował." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Njeje abonowany!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Sebjeabonement njeje so dał zničić." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Abonoment njeje so dał zničić." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4296,136 +4320,136 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Strona bjez titula" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Zwjazać" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Přeprosyć" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Konto załožić" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Pomoc" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Pomhaj!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Pytać" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Za ludźimi abo tekstom pytać" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Wo" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Huste prašenja" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Priwatnosć" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Žórło" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%). " msgstr "" -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4433,41 +4457,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "" @@ -4764,54 +4788,59 @@ msgstr "" msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Wužiwar njeeksistuje" + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Sy tutu wosobu abonował:" @@ -4819,11 +4848,11 @@ msgstr[1] "Sy tutej wosobje abonował:" msgstr[2] "Sy tute wosoby abonował:" msgstr[3] "Sy tute wosoby abonował:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Tuta wosoba je će abonowała:" @@ -4831,11 +4860,11 @@ msgstr[1] "Tutej wosobje stej će abonowałoj:" msgstr[2] "Tute wosoby su će abonowali:" msgstr[3] "Tute wosoby su će abonowali:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Sy čłon tuteje skupiny:" @@ -4843,7 +4872,7 @@ msgstr[1] "Sy čłon tuteju skupinow:" msgstr[2] "Sy čłon tutych skupinow:" msgstr[3] "Sy čłon tutych skupinow:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5495,10 +5524,6 @@ msgstr "Zmylk při zasunjenju zdaleneho profila" msgid "Duplicate notice" msgstr "Dwójna zdźělenka" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "" @@ -5675,34 +5700,6 @@ msgstr "" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Hižo abonowany!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Wužiwar je će zablokował." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Abonowanje njebě móžno" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Njeje abonowany!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Sebjeabonement njeje so dał zničić." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Abonoment njeje so dał zničić." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/ia/LC_MESSAGES/statusnet.po b/locale/ia/LC_MESSAGES/statusnet.po index a8d95a851e..b3fd3770a9 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:28+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:04+0000\n" "Language-Team: Interlingua\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -98,7 +98,6 @@ msgstr "Pagina non existe" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Usator non existe." @@ -558,7 +557,7 @@ msgstr "" "%3$s le datos de tu conto de %4$s. Tu debe solmente dar " "accesso a tu conto de %4$s a tertie personas in le quales tu ha confidentia." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Conto" @@ -939,7 +938,7 @@ msgstr "Tu non es le proprietario de iste application." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Il habeva un problema con tu indicio de session." @@ -1682,7 +1681,7 @@ msgstr "Membros del gruppo %1$s, pagina %2$d" msgid "A list of the users in this group." msgstr "Un lista de usatores in iste gruppo." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2068,7 +2067,7 @@ msgid "Error setting user. You are probably not authorized." msgstr "" "Error de acceder al conto de usator. Tu probabilemente non es autorisate." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Aperir session" @@ -3032,7 +3031,7 @@ msgstr "Pardono, le codice de invitation es invalide." msgid "Registration successful" msgstr "Registration succedite" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Crear conto" @@ -3930,7 +3929,8 @@ msgstr "Nulle codice entrate" msgid "You are not subscribed to that profile." msgstr "Tu non es subscribite a iste profilo." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Non poteva salveguardar le subscription." @@ -4392,7 +4392,7 @@ msgstr "" msgid "Plugins" msgstr "Plug-ins" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Version" @@ -4453,22 +4453,22 @@ msgstr "Non poteva actualisar message con nove URI." msgid "DB error inserting hashtag: %s" msgstr "Error in base de datos durante insertion del marca (hashtag): %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problema salveguardar nota. Troppo longe." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problema salveguardar nota. Usator incognite." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Troppo de notas troppo rapidemente; face un pausa e publica de novo post " "alcun minutas." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4476,29 +4476,53 @@ msgstr "" "Troppo de messages duplicate troppo rapidemente; face un pausa e publica de " "novo post alcun minutas." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Il te es prohibite publicar notas in iste sito." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problema salveguardar nota." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Problema salveguardar le cassa de entrata del gruppo." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Error del base de datos durante le insertion del responsa: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Tu ha essite blocate del subscription." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Ja subscribite!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Le usator te ha blocate." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Non subscribite!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Non poteva deler auto-subscription." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Non poteva deler subscription." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Benvenite a %1$s, @%2$s!" @@ -4548,124 +4572,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Pagina sin titulo" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Navigation primari del sito" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Initio" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Profilo personal e chronologia de amicos" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Cambiar tu e-mail, avatar, contrasigno, profilo" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Connecter" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Connecter con servicios" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Modificar le configuration del sito" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitar" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invitar amicos e collegas a accompaniar te in %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Clauder session" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Terminar le session del sito" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Crear un conto" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Identificar te a iste sito" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Adjuta" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Adjuta me!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Cercar" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Cercar personas o texto" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Aviso del sito" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Vistas local" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Aviso de pagina" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Navigation secundari del sito" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "A proposito" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "CdS" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Confidentialitate" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Fonte" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contacto" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Insignia" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licentia del software StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4674,12 +4698,12 @@ msgstr "" "**%%site.name%%** es un servicio de microblog offerite per [%%site.broughtby%" "%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** es un servicio de microblog. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4690,42 +4714,42 @@ msgstr "" "net/), version %s, disponibile sub le [GNU Affero General Public License]" "(http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licentia del contento del sito" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Le contento e datos de %1$s es private e confidential." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Contento e datos sub copyright de %1$s. Tote le derectos reservate." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Contento e datos sub copyright del contributores. Tote le derectos reservate." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Totes " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licentia." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Pagination" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Post" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Ante" @@ -5028,82 +5052,87 @@ msgstr "Errur durante le salveguarda del nota." msgid "Specify the name of the user to subscribe to" msgstr "Specifica le nomine del usator al qual subscriber te" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Usator non existe." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Subscribite a %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Specifica le nomine del usator al qual cancellar le subscription" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Subscription a %s cancellate" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Commando non ancora implementate." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notification disactivate." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Non pote disactivar notification." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notification activate." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Non pote activar notification." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Le commando de apertura de session es disactivate" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Iste ligamine pote esser usate solmente un vice, e es valide durante " "solmente 2 minutas: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Tu non es subscribite a alcuno." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Tu es subscribite a iste persona:" msgstr[1] "Tu es subscribite a iste personas:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Necuno es subscribite a te." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Iste persona es subscribite a te:" msgstr[1] "Iste personas es subscribite a te:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Tu non es membro de alcun gruppo." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Tu es membro de iste gruppo:" msgstr[1] "Tu es membro de iste gruppos:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5888,10 +5917,6 @@ msgstr "Error durante le insertion del profilo remote" msgid "Duplicate notice" msgstr "Duplicar nota" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Tu ha essite blocate del subscription." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Non poteva inserer nove subscription." @@ -6068,34 +6093,6 @@ msgstr "Personas qui seque %s" msgid "Groups %s is a member of" msgstr "Gruppos del quales %s es membro" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Ja subscribite!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Le usator te ha blocate." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Non poteva subscriber te." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Non poteva subcriber altere persona a te." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Non subscribite!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Non poteva deler auto-subscription." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Non poteva deler subscription." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/is/LC_MESSAGES/statusnet.po b/locale/is/LC_MESSAGES/statusnet.po index 3c17728611..4ff8809785 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:30+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:19+0000\n" "Language-Team: Icelandic\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -107,7 +107,6 @@ msgstr "Ekkert þannig merki." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Enginn svoleiðis notandi." @@ -564,7 +563,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Aðgangur" @@ -950,7 +949,7 @@ msgstr "Þú ert ekki meðlimur í þessum hópi." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Það komu upp vandamál varðandi setutókann þinn." @@ -1709,7 +1708,7 @@ msgstr "Hópmeðlimir %s, síða %d" msgid "A list of the users in this group." msgstr "Listi yfir notendur í þessum hóp." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Stjórnandi" @@ -2087,7 +2086,7 @@ msgstr "Rangt notendanafn eða lykilorð." msgid "Error setting user. You are probably not authorized." msgstr "Engin heimild." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Innskráning" @@ -3060,7 +3059,7 @@ msgstr "" msgid "Registration successful" msgstr "Nýskráning tókst" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Nýskrá" @@ -3939,7 +3938,8 @@ msgstr "Enginn lykill sleginn inn" msgid "You are not subscribed to that profile." msgstr "Þú ert ekki áskrifandi." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Gat ekki vistað áskrift." @@ -4389,7 +4389,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Persónulegt" @@ -4453,51 +4453,78 @@ msgstr "Gat ekki uppfært skilaboð með nýju veffangi." msgid "DB error inserting hashtag: %s" msgstr "Gagnagrunnsvilla við innsetningu myllumerkis: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "" -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Gat ekki vistað babl. Óþekktur notandi." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Of mikið babl í einu; slakaðu aðeins á og haltu svo áfram eftir nokkrar " "mínútur." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Það hefur verið lagt bann við babli frá þér á þessari síðu." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Vandamál komu upp við að vista babl." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Vandamál komu upp við að vista babl." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Gagnagrunnsvilla við innsetningu svars: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 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 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Notandinn hefur lokað á þig." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Ekki í áskrift!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Gat ekki eytt áskrift." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Gat ekki eytt áskrift." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4547,128 +4574,128 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Ónafngreind síða" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Stikl aðalsíðu" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Heim" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Persónuleg síða og vinarás" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" "Breyttu tölvupóstinum þínum, einkennismyndinni þinni, lykilorðinu þínu, " "persónulegu síðunni þinni" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Tengjast" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Gat ekki framsent til vefþjóns: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Stikl aðalsíðu" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Bjóða" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Bjóða vinum og vandamönnum að slást í hópinn á %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Útskráning" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Skrá þig út af síðunni" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Búa til aðgang" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Skrá þig inn á síðuna" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Hjálp" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Hjálp!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Leita" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Leita að fólki eða texta" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Babl vefsíðunnar" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Staðbundin sýn" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Babl síðunnar" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Stikl undirsíðu" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Um" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Spurt og svarað" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Friðhelgi" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Frumþula" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Tengiliður" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Hugbúnaðarleyfi StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4677,12 +4704,12 @@ msgstr "" "**%%site.name%%** er örbloggsþjónusta í boði [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** er örbloggsþjónusta." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4693,42 +4720,42 @@ msgstr "" "sem er gefinn út undir [GNU Affero almenningsleyfinu](http://www.fsf.org/" "licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "Hugbúnaðarleyfi StatusNet" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Allt " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "leyfi." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Uppröðun" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Eftir" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Áður" @@ -5044,83 +5071,88 @@ msgstr "Vandamál komu upp við að vista babl." msgid "Specify the name of the user to subscribe to" msgstr "Tilgreindu nafn notandans sem þú vilt gerast áskrifandi að" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Enginn svoleiðis notandi." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Nú ert þú áskrifandi að %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Tilgreindu nafn notandans sem þú vilt hætta sem áskrifandi að" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Nú ert þú ekki lengur áskrifandi að %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Skipun hefur ekki verið fullbúin" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Tilkynningar af." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Get ekki slökkt á tilkynningum." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Tilkynningar á." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Get ekki kveikt á tilkynningum." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Þú ert ekki áskrifandi." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Þú ert nú þegar í áskrift að þessum notendum:" msgstr[1] "Þú ert nú þegar í áskrift að þessum notendum:" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Gat ekki leyft öðrum að gerast áskrifandi að þér." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Gat ekki leyft öðrum að gerast áskrifandi að þér." msgstr[1] "Gat ekki leyft öðrum að gerast áskrifandi að þér." -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Þú ert ekki meðlimur í þessum hópi." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Þú ert ekki meðlimur í þessum hópi." msgstr[1] "Þú ert ekki meðlimur í þessum hópi." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5797,11 +5829,6 @@ msgstr "Villa kom upp við að setja inn persónulega fjarsíðu" msgid "Duplicate notice" msgstr "Eyða babli" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "Þessi notandi hefur bannað þér að gerast áskrifandi" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Gat ekki sett inn nýja áskrift." @@ -5986,36 +6013,6 @@ msgstr "Fólk sem eru áskrifendur að %s" msgid "Groups %s is a member of" msgstr "Hópar sem %s er meðlimur í" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Notandinn hefur lokað á þig." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Gat ekki farið í áskrift." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Gat ekki leyft öðrum að gerast áskrifandi að þér." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Ekki í áskrift!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Gat ekki eytt áskrift." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Gat ekki eytt áskrift." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/it/LC_MESSAGES/statusnet.po b/locale/it/LC_MESSAGES/statusnet.po index ec02b5363b..3c2b8cc8ad 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:42+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:22+0000\n" "Language-Team: Italian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -101,7 +101,6 @@ msgstr "Pagina inesistente." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Utente inesistente." @@ -562,7 +561,7 @@ msgstr "" "%3$s ai dati del tuo account %4$s. È consigliato fornire " "accesso al proprio account %4$s solo ad applicazioni di cui ci si può fidare." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Account" @@ -618,7 +617,7 @@ msgstr "Messaggio eliminato." #: actions/apistatusesshow.php:144 msgid "No status with that ID found." -msgstr "Nessun stato trovato con quel ID." +msgstr "Nessuno stato trovato con quel ID." #: actions/apistatusesupdate.php:161 actions/newnotice.php:155 #: lib/mailhandler.php:60 @@ -940,7 +939,7 @@ msgstr "Questa applicazione non è di tua proprietà." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Si è verificato un problema con il tuo token di sessione." @@ -1686,7 +1685,7 @@ msgstr "Membri del gruppo %1$s, pagina %2$d" msgid "A list of the users in this group." msgstr "Un elenco degli utenti in questo gruppo." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Amministra" @@ -2070,7 +2069,7 @@ msgstr "Nome utente o password non corretto." msgid "Error setting user. You are probably not authorized." msgstr "Errore nell'impostare l'utente. Forse non hai l'autorizzazione." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Accedi" @@ -3030,7 +3029,7 @@ msgstr "Codice di invito non valido." msgid "Registration successful" msgstr "Registrazione riuscita" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registra" @@ -3928,7 +3927,8 @@ msgstr "Nessun codice inserito" msgid "You are not subscribed to that profile." msgstr "Non hai una abbonamento a quel profilo." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Impossibile salvare l'abbonamento." @@ -4390,7 +4390,7 @@ msgstr "" msgid "Plugins" msgstr "Plugin" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Versione" @@ -4453,22 +4453,22 @@ msgstr "Impossibile aggiornare il messaggio con il nuovo URI." msgid "DB error inserting hashtag: %s" msgstr "Errore del DB nell'inserire un hashtag: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problema nel salvare il messaggio. Troppo lungo." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problema nel salvare il messaggio. Utente sconosciuto." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Troppi messaggi troppo velocemente; fai una pausa e scrivi di nuovo tra " "qualche minuto." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4476,29 +4476,53 @@ msgstr "" "Troppi messaggi duplicati troppo velocemente; fai una pausa e scrivi di " "nuovo tra qualche minuto." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Ti è proibito inviare messaggi su questo sito." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problema nel salvare il messaggio." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Problema nel salvare la casella della posta del gruppo." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Errore del DB nell'inserire la risposta: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Non ti è possibile abbonarti." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Hai già l'abbonamento!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "L'utente non ti consente di seguirlo." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Non hai l'abbonamento!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Impossibile eliminare l'auto-abbonamento." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Impossibile eliminare l'abbonamento." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Benvenuti su %1$s, @%2$s!" @@ -4548,124 +4572,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Pagina senza nome" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Esplorazione sito primaria" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Home" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Profilo personale e attività degli amici" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Modifica la tua email, immagine, password o il tuo profilo" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Connetti" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Connettiti con altri servizi" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Modifica la configurazione del sito" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invita" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Invita amici e colleghi a seguirti su %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Esci" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Termina la tua sessione sul sito" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Crea un account" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Accedi al sito" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Aiuto" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Aiutami!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Cerca" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Cerca persone o del testo" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Messaggio del sito" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Viste locali" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Pagina messaggio" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Esplorazione secondaria del sito" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Informazioni" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "TOS" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privacy" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Sorgenti" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contatti" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Badge" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licenza del software StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4674,12 +4698,12 @@ msgstr "" "**%%site.name%%** è un servizio di microblog offerto da [%%site.broughtby%%]" "(%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** è un servizio di microblog. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4690,44 +4714,44 @@ msgstr "" "s, disponibile nei termini della licenza [GNU Affero General Public License]" "(http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licenza del contenuto del sito" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "I contenuti e i dati di %1$s sono privati e confidenziali." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "I contenuti e i dati sono copyright di %1$s. Tutti i diritti riservati." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "I contenuti e i dati sono forniti dai collaboratori. Tutti i diritti " "riservati." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Tutti " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licenza." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginazione" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Successivi" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Precedenti" @@ -5029,82 +5053,87 @@ msgstr "Errore nel salvare il messaggio." msgid "Specify the name of the user to subscribe to" msgstr "Specifica il nome dell'utente a cui abbonarti." -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Utente inesistente." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Abbonati a %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Specifica il nome dell'utente da cui annullare l'abbonamento." -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Abbonamento a %s annullato" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Comando non ancora implementato." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notifiche disattivate." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Impossibile disattivare le notifiche." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notifiche attivate." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Impossibile attivare le notifiche." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Il comando di accesso è disabilitato" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Questo collegamento è utilizzabile una sola volta ed è valido solo per 2 " "minuti: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Il tuo abbonamento è stato annullato." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Persona di cui hai già un abbonamento:" msgstr[1] "Persone di cui hai già un abbonamento:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Nessuno è abbonato ai tuoi messaggi." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Questa persona è abbonata ai tuoi messaggi:" msgstr[1] "Queste persone sono abbonate ai tuoi messaggi:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Non fai parte di alcun gruppo." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Non fai parte di questo gruppo:" msgstr[1] "Non fai parte di questi gruppi:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5891,10 +5920,6 @@ msgstr "Errore nell'inserire il profilo remoto" msgid "Duplicate notice" msgstr "Messaggio duplicato" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Non ti è possibile abbonarti." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Impossibile inserire un nuovo abbonamento." @@ -6071,34 +6096,6 @@ msgstr "Persone abbonate a %s" msgid "Groups %s is a member of" msgstr "Gruppi di cui %s fa parte" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Hai già l'abbonamento!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "L'utente non ti consente di seguirlo." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Impossibile abbonarsi." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Impossibile abbonare altri a te." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Non hai l'abbonamento!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Impossibile eliminare l'auto-abbonamento." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Impossibile eliminare l'abbonamento." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/ja/LC_MESSAGES/statusnet.po b/locale/ja/LC_MESSAGES/statusnet.po index ba52e7bfb0..9b8fd009d7 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:45+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:25+0000\n" "Language-Team: Japanese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -101,7 +101,6 @@ msgstr "そのようなページはありません。" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "そのようなユーザはいません。" @@ -556,7 +555,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "アカウント" @@ -933,7 +932,7 @@ msgstr "このアプリケーションのオーナーではありません。" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "あなたのセッショントークンに関する問題がありました。" @@ -1679,7 +1678,7 @@ msgstr "%1$s グループメンバー、ページ %2$d" msgid "A list of the users in this group." msgstr "このグループのユーザのリスト。" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "管理者" @@ -2062,7 +2061,7 @@ msgstr "ユーザ名またはパスワードが間違っています。" msgid "Error setting user. You are probably not authorized." msgstr "ユーザ設定エラー。 あなたはたぶん承認されていません。" -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "ログイン" @@ -3020,7 +3019,7 @@ msgstr "すみません、不正な招待コード。" msgid "Registration successful" msgstr "登録成功" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "登録" @@ -3921,7 +3920,8 @@ msgstr "コードが入力されていません" msgid "You are not subscribed to that profile." msgstr "あなたはそのプロファイルにフォローされていません。" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "フォローを保存できません。" @@ -4371,7 +4371,7 @@ msgstr "" msgid "Plugins" msgstr "プラグイン" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "バージョン" @@ -4435,21 +4435,21 @@ msgstr "新しいURIでメッセージをアップデートできませんでし msgid "DB error inserting hashtag: %s" msgstr "ハッシュタグ追加 DB エラー: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "つぶやきを保存する際に問題が発生しました。長すぎです。" -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "つぶやきを保存する際に問題が発生しました。不明なユーザです。" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "多すぎるつぶやきが速すぎます; 数分間の休みを取ってから再投稿してください。" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4457,29 +4457,53 @@ msgstr "" "多すぎる重複メッセージが速すぎます; 数分間休みを取ってから再度投稿してくださ" "い。" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "あなたはこのサイトでつぶやきを投稿するのが禁止されています。" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "つぶやきを保存する際に問題が発生しました。" -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "グループ受信箱を保存する際に問題が発生しました。" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "返信を追加する際にデータベースエラー : %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "あなたはフォローが禁止されました。" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "すでにフォローしています!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "ユーザはあなたをブロックしました。" + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "フォローしていません!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "自己フォローを削除できません。" + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "フォローを削除できません" + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "ようこそ %1$s、@%2$s!" @@ -4529,124 +4553,124 @@ msgstr "" msgid "Untitled page" msgstr "名称未設定ページ" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "プライマリサイトナビゲーション" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "ホーム" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "パーソナルプロファイルと友人のタイムライン" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "メールアドレス、アバター、パスワード、プロパティの変更" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "接続" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "サービスへ接続" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "サイト設定の変更" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "招待" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "友人や同僚が %s で加わるよう誘ってください。" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "ログアウト" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "サイトからログアウト" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "アカウントを作成" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "サイトへログイン" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "ヘルプ" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "助けて!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "検索" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "人々かテキストを検索" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "サイトつぶやき" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "ローカルビュー" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "ページつぶやき" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "セカンダリサイトナビゲーション" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "About" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "よくある質問" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "プライバシー" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "ソース" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "連絡先" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "バッジ" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNet ソフトウェアライセンス" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4655,12 +4679,12 @@ msgstr "" "**%%site.name%%** は [%%site.broughtby%%](%%site.broughtbyurl%%) が提供するマ" "イクロブログサービスです。 " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** はマイクロブログサービスです。 " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4671,41 +4695,41 @@ msgstr "" "いています。 ライセンス [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)。" -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "サイト内容ライセンス" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "全て " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "ライセンス。" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "ページ化" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "<<後" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "前>>" @@ -5006,77 +5030,82 @@ msgstr "つぶやき保存エラー。" msgid "Specify the name of the user to subscribe to" msgstr "フォローするユーザの名前を指定してください" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "そのようなユーザはいません。" + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "%s をフォローしました" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "フォローをやめるユーザの名前を指定してください" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "%s のフォローをやめる" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "コマンドはまだ実装されていません。" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "通知オフ。" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "通知をオフできません。" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "通知オン。" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "通知をオンできません。" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "ログインコマンドが無効になっています。" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "このリンクは、かつてだけ使用可能であり、2分間だけ良いです: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "あなたはだれにもフォローされていません。" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "あなたはこの人にフォローされています:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "誰もフォローしていません。" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "この人はあなたにフォローされている:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "あなたはどのグループのメンバーでもありません。" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "あなたはこのグループのメンバーではありません:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5829,10 +5858,6 @@ msgstr "リモートプロファイル追加エラー" msgid "Duplicate notice" msgstr "重複したつぶやき" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "あなたはフォローが禁止されました。" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "サブスクリプションを追加できません" @@ -6009,34 +6034,6 @@ msgstr "人々は %s をフォローしました。" msgid "Groups %s is a member of" msgstr "グループ %s はメンバー" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "すでにフォローしています!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "ユーザはあなたをブロックしました。" - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "フォローできません。" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "他の人があなたをフォローできません。" - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "フォローしていません!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "自己フォローを削除できません。" - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "フォローを削除できません" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/ko/LC_MESSAGES/statusnet.po b/locale/ko/LC_MESSAGES/statusnet.po index dd89d10477..047593b475 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:48+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:28+0000\n" "Language-Team: Korean\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -105,7 +105,6 @@ msgstr "그러한 태그가 없습니다." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "그러한 사용자는 없습니다." @@ -567,7 +566,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "계정" @@ -957,7 +956,7 @@ msgstr "당신은 해당 그룹의 멤버가 아닙니다." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "당신의 세션토큰관련 문제가 있습니다." @@ -1736,7 +1735,7 @@ msgstr "%s 그룹 회원, %d페이지" msgid "A list of the users in this group." msgstr "이 그룹의 회원리스트" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "관리자" @@ -2108,7 +2107,7 @@ msgstr "틀린 계정 또는 비밀 번호" msgid "Error setting user. You are probably not authorized." msgstr "인증이 되지 않았습니다." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "로그인" @@ -3075,7 +3074,7 @@ msgstr "확인 코드 오류" msgid "Registration successful" msgstr "회원 가입이 성공적입니다." -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "회원가입" @@ -3963,7 +3962,8 @@ msgstr "코드가 입력 되지 않았습니다." msgid "You are not subscribed to that profile." msgstr "당신은 이 프로필에 구독되지 않고있습니다." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "구독을 저장할 수 없습니다." @@ -4410,7 +4410,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "개인적인" @@ -4474,23 +4474,23 @@ msgstr "새 URI와 함께 메시지를 업데이트할 수 없습니다." msgid "DB error inserting hashtag: %s" msgstr "해쉬테그를 추가 할 때에 데이타베이스 에러 : %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "통지를 저장하는데 문제가 발생했습니다." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "게시글 저장문제. 알려지지않은 회원" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "너무 많은 게시글이 너무 빠르게 올라옵니다. 한숨고르고 몇분후에 다시 포스트를 " "해보세요." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4499,30 +4499,57 @@ msgstr "" "너무 많은 게시글이 너무 빠르게 올라옵니다. 한숨고르고 몇분후에 다시 포스트를 " "해보세요." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "이 사이트에 게시글 포스팅으로부터 당신은 금지되었습니다." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "통지를 저장하는데 문제가 발생했습니다." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "통지를 저장하는데 문제가 발생했습니다." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "답신을 추가 할 때에 데이타베이스 에러 : %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +#, fuzzy +msgid "You have been banned from subscribing." +msgstr "이 회원은 구독으로부터 당신을 차단해왔다." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "회원이 당신을 차단해왔습니다." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "구독하고 있지 않습니다!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "예약 구독을 삭제 할 수 없습니다." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "예약 구독을 삭제 할 수 없습니다." + +#: classes/User.php:372 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "%2$s에서 %1$s까지 메시지" @@ -4573,127 +4600,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "제목없는 페이지" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "주 사이트 네비게이션" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "홈" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "개인 프로필과 친구 타임라인" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "당신의 이메일, 아바타, 비밀 번호, 프로필을 변경하세요." -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "연결" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "서버에 재접속 할 수 없습니다 : %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "주 사이트 네비게이션" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "초대" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "%s에 친구를 가입시키기 위해 친구와 동료를 초대합니다." -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "로그아웃" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "이 사이트로부터 로그아웃" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "계정 만들기" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "이 사이트 로그인" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "도움말" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "도움이 필요해!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "검색" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "프로필이나 텍스트 검색" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "사이트 공지" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "로컬 뷰" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "페이지 공지" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "보조 사이트 네비게이션" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "정보" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "자주 묻는 질문" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "개인정보 취급방침" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "소스 코드" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "연락하기" -#: lib/action.php:752 +#: lib/action.php:751 #, fuzzy msgid "Badge" msgstr "찔러 보기" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "라코니카 소프트웨어 라이선스" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4702,12 +4729,12 @@ msgstr "" "**%%site.name%%** 는 [%%site.broughtby%%](%%site.broughtbyurl%%)가 제공하는 " "마이크로블로깅서비스입니다." -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** 는 마이크로블로깅서비스입니다." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4718,42 +4745,42 @@ msgstr "" "을 사용합니다. StatusNet는 [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html) 라이선스에 따라 사용할 수 있습니다." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "라코니카 소프트웨어 라이선스" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "모든 것" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "라이선스" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "페이지수" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "뒷 페이지" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "앞 페이지" @@ -5071,80 +5098,85 @@ msgstr "통지를 저장하는데 문제가 발생했습니다." msgid "Specify the name of the user to subscribe to" msgstr "구독하려는 사용자의 이름을 지정하십시오." -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "그러한 사용자는 없습니다." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "%s에게 구독되었습니다." -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "구독을 해제하려는 사용자의 이름을 지정하십시오." -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "%s에서 구독을 해제했습니다." -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "명령이 아직 실행되지 않았습니다." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "알림끄기." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "알림을 끌 수 없습니다." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "알림이 켜졌습니다." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "알림을 켤 수 없습니다." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "당신은 이 프로필에 구독되지 않고있습니다." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "당신은 다음 사용자를 이미 구독하고 있습니다." -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "다른 사람을 구독 하실 수 없습니다." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "다른 사람을 구독 하실 수 없습니다." -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "당신은 해당 그룹의 멤버가 아닙니다." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "당신은 해당 그룹의 멤버가 아닙니다." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5821,11 +5853,6 @@ msgstr "리모트 프로필 추가 오류" msgid "Duplicate notice" msgstr "통지 삭제" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "이 회원은 구독으로부터 당신을 차단해왔다." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "예약 구독을 추가 할 수 없습니다." @@ -6013,36 +6040,6 @@ msgstr "%s에 의해 구독되는 사람들" msgid "Groups %s is a member of" msgstr "%s 그룹들은 의 멤버입니다." -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "회원이 당신을 차단해왔습니다." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "구독 하실 수 없습니다." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "다른 사람을 구독 하실 수 없습니다." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "구독하고 있지 않습니다!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "예약 구독을 삭제 할 수 없습니다." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "예약 구독을 삭제 할 수 없습니다." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/mk/LC_MESSAGES/statusnet.po b/locale/mk/LC_MESSAGES/statusnet.po index 5e7aba59fc..16697578b8 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:51+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:31+0000\n" "Language-Team: Macedonian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -101,7 +101,6 @@ msgstr "Нема таква страница" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Нема таков корисник." @@ -562,7 +561,7 @@ msgstr "" "%3$s податоците за Вашата %4$s сметка. Треба да дозволувате " "пристап до Вашата %4$s сметка само на трети страни на кои им верувате." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Сметка" @@ -943,7 +942,7 @@ msgstr "Не сте сопственик на овој програм." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Се појави проблем со Вашиот сесиски жетон." @@ -1691,7 +1690,7 @@ msgstr "Членови на групата %1$s, стр. %2$d" msgid "A list of the users in this group." msgstr "Листа на корисниците на овааг група." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Администратор" @@ -2077,7 +2076,7 @@ msgstr "Неточно корисничко име или лозинка" msgid "Error setting user. You are probably not authorized." msgstr "Грешка при поставувањето на корисникот. Веројатно не се заверени." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Најава" @@ -3045,7 +3044,7 @@ msgstr "Жалиме, неважечки код за поканата." msgid "Registration successful" msgstr "Регистрацијата е успешна" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Регистрирај се" @@ -3951,7 +3950,8 @@ msgstr "Нема внесено код" msgid "You are not subscribed to that profile." msgstr "Не сте претплатени на тој профил." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Не можев да ја зачувам претплатата." @@ -4413,7 +4413,7 @@ msgstr "" msgid "Plugins" msgstr "Приклучоци" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Верзија" @@ -4475,22 +4475,22 @@ msgstr "Не можев да ја подновам пораката со нов msgid "DB error inserting hashtag: %s" msgstr "Грешка во базата на податоци при вметнувањето на хеш-ознака: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Проблем со зачувувањето на белешката. Премногу долго." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Проблем со зачувувањето на белешката. Непознат корисник." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Премногу забелњшки за прекратко време; здивнете малку и продолжете за " "неколку минути." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4498,29 +4498,54 @@ msgstr "" "Премногу дуплирани пораки во прекратко време; здивнете малку и продолжете за " "неколку минути." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Забрането Ви е да објавувате забелешки на оваа веб-страница." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Проблем во зачувувањето на белешката." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Проблем при зачувувањето на групното приемно сандаче." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Одговор од внесот во базата: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Блокирани сте од претплаќање." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Веќе претплатено!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Корисникот Ве има блокирано." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Не сте претплатени!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Не можам да ја избришам самопретплатата." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Претплата не може да се избрише." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Добредојдовте на %1$s, @%2$s!" @@ -4570,124 +4595,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Страница без наслов" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Главна навигација" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Дома" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Личен профил и историја на пријатели" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Промена на е-пошта, аватар, лозинка, профил" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Поврзи се" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Поврзи се со услуги" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Промена на конфигурацијата на веб-страницата" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Покани" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Поканете пријатели и колеги да Ви се придружат на %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Одјави се" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Одјава" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Создај сметка" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Најава" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Помош" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Напомош!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Барај" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Пребарајте луѓе или текст" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Напомена за веб-страницата" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Локални прегледи" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Напомена за страницата" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Споредна навигација" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "За" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "ЧПП" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "Услови" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Приватност" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Изворен код" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Контакт" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Значка" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Лиценца на програмот StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4696,12 +4721,12 @@ msgstr "" "**%%site.name%%** е сервис за микроблогирање што ви го овозможува [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** е сервис за микроблогирање." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4712,45 +4737,45 @@ msgstr "" "верзија %s, достапен пд [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Лиценца на содржините на веб-страницата" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Содржината и податоците на %1$s се лични и доверливи." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Авторските права на содржината и податоците се во сопственост на %1$s. Сите " "права задржани." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Авторските права на содржината и податоците им припаѓаат на учесниците. Сите " "права задржани." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Сите " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "лиценца." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Прелом на страници" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "По" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Пред" @@ -5053,80 +5078,85 @@ msgstr "Грешка при зачувувањето на белешката." msgid "Specify the name of the user to subscribe to" msgstr "Назначете го името на корисникот на којшто сакате да се претплатите" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Нема таков корисник." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Претплатено на %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Назначете го името на корисникот од кого откажувате претплата." -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Претплатата на %s е откажана" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Наредбата сè уште не е имплементирана." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Известувањето е исклучено." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Не можам да исклучам известување." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Известувањето е вклучено." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Не можам да вклучам известување." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Наредбата за најава е оневозможена" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "Оваа врска може да се употреби само еднаш, и трае само 2 минути: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Не сте претплатени никому." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Не ни го испративте тој профил." msgstr[1] "Не ни го испративте тој профил." -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Никој не е претплатен на Вас." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Оддалечена претплата" msgstr[1] "Оддалечена претплата" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Не членувате во ниедна група." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Не ни го испративте тој профил." msgstr[1] "Не ни го испративте тој профил." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5915,10 +5945,6 @@ msgstr "Грешка во внесувањето на оддалечениот msgid "Duplicate notice" msgstr "Дуплирај забелешка" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Блокирани сте од претплаќање." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Не може да се внесе нова претплата." @@ -6095,35 +6121,6 @@ msgstr "Луѓе претплатени на %s" msgid "Groups %s is a member of" msgstr "Групи кадешто членува %s" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Веќе претплатено!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Корисникот Ве има блокирано." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Претплатата е неуспешна." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Не можев да прептлатам друг корисник на Вас." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Не сте претплатени!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Не можам да ја избришам самопретплатата." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Претплата не може да се избрише." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/nb/LC_MESSAGES/statusnet.po b/locale/nb/LC_MESSAGES/statusnet.po index 5e48b86359..c107f49065 100644 --- a/locale/nb/LC_MESSAGES/statusnet.po +++ b/locale/nb/LC_MESSAGES/statusnet.po @@ -8,12 +8,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:54+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:34+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.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -98,7 +98,6 @@ msgstr "Ingen slik side" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Ingen slik bruker" @@ -552,7 +551,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Konto" @@ -925,7 +924,7 @@ msgstr "Du er ikke eieren av dette programmet." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1663,7 +1662,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "En liste over brukerne i denne gruppen." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2021,7 +2020,7 @@ msgstr "Feil brukernavn eller passord" msgid "Error setting user. You are probably not authorized." msgstr "Ikke autorisert." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Logg inn" @@ -2959,7 +2958,7 @@ msgstr "" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -3824,7 +3823,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "Klarte ikke å lagre avatar-informasjonen" @@ -4260,7 +4260,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Personlig" @@ -4323,48 +4323,74 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "" -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "" + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Alle abonnementer" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Klarte ikke å lagre avatar-informasjonen" + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "" + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4417,126 +4443,126 @@ msgstr "%1$s sin status på %2$s" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Hjem" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Koble til" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Logg ut" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "Opprett en ny konto" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Hjelp" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "Hjelp" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Søk" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Om" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "OSS/FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Kilde" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4545,12 +4571,12 @@ msgstr "" "**%%site.name%%** er en mikrobloggingtjeneste av [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** er en mikrobloggingtjeneste. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4558,41 +4584,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "Tidligere »" @@ -4898,83 +4924,88 @@ msgstr "" msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Ingen slik bruker" + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Ikke autorisert." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Ikke autorisert." msgstr[1] "Ikke autorisert." -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Svar til %s" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Svar til %s" msgstr[1] "Svar til %s" -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Du er allerede logget inn!" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Du er allerede logget inn!" msgstr[1] "Du er allerede logget inn!" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5653,10 +5684,6 @@ msgstr "" msgid "Duplicate notice" msgstr "" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "" @@ -5842,36 +5869,6 @@ msgstr "Svar til %s" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "" - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Alle abonnementer" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Klarte ikke å lagre avatar-informasjonen" - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/nl/LC_MESSAGES/statusnet.po b/locale/nl/LC_MESSAGES/statusnet.po index 54c042b2ff..34f28afbde 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:00+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:41+0000\n" "Language-Team: Dutch\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -100,7 +100,6 @@ msgstr "Deze pagina bestaat niet" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Onbekende gebruiker." @@ -572,7 +571,7 @@ msgstr "" "van het type \"%3$s tot uw gebruikersgegevens. Geef alleen " "toegang tot uw gebruiker bij %4$s aan derde partijen die u vertrouwt." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Gebruiker" @@ -952,7 +951,7 @@ msgstr "U bent niet de eigenaar van deze applicatie." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Er is een probleem met uw sessietoken." @@ -1705,7 +1704,7 @@ msgstr "%1$s groeps leden, pagina %2$d" msgid "A list of the users in this group." msgstr "Ledenlijst van deze groep" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Beheerder" @@ -2095,7 +2094,7 @@ msgstr "" "Er is een fout opgetreden bij het maken van de instellingen. U hebt " "waarschijnlijk niet de juiste rechten." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Aanmelden" @@ -3068,7 +3067,7 @@ msgstr "Sorry. De uitnodigingscode is ongeldig." msgid "Registration successful" msgstr "De registratie is voltooid" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registreren" @@ -3975,7 +3974,8 @@ msgstr "Er is geen code ingevoerd" msgid "You are not subscribed to that profile." msgstr "U bent niet geabonneerd op dat profiel." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Het was niet mogelijk het abonnement op te slaan." @@ -4440,7 +4440,7 @@ msgstr "" msgid "Plugins" msgstr "Plug-ins" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Versie" @@ -4503,26 +4503,26 @@ msgstr "Het was niet mogelijk het bericht bij te werken met de nieuwe URI." msgid "DB error inserting hashtag: %s" msgstr "Er is een databasefout opgetreden bij de invoer van de hashtag: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "" "Er is een probleem opgetreden bij het opslaan van de mededeling. Deze is te " "lang." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "" "Er was een probleem bij het opslaan van de mededeling. De gebruiker is " "onbekend." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "U hebt te snel te veel mededelingen verstuurd. Kom even op adem en probeer " "het over enige tijd weer." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4530,33 +4530,57 @@ msgstr "" "Te veel duplicaatberichten te snel achter elkaar. Neem een adempauze en " "plaats over een aantal minuten pas weer een bericht." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" "U bent geblokkeerd en mag geen mededelingen meer achterlaten op deze site." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Er is een probleem opgetreden bij het opslaan van de mededeling." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "" "Er is een probleem opgetreden bij het opslaan van het Postvak IN van de " "groep." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" "Er is een databasefout opgetreden bij het invoegen van het antwoord: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "U mag zich niet abonneren." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "U bent al gebonneerd!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Deze gebruiker negeert u." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Niet geabonneerd!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Het was niet mogelijk het abonnement op uzelf te verwijderen." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Kon abonnement niet verwijderen." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Welkom bij %1$s, @%2$s!" @@ -4606,124 +4630,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Naamloze pagina" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Primaire sitenavigatie" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Start" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Persoonlijk profiel en tijdlijn van vrienden" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Uw e-mailadres, avatar, wachtwoord of profiel wijzigen" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Koppelen" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Met diensten verbinden" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Websiteinstellingen wijzigen" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Uitnodigen" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Vrienden en collega's uitnodigen om u te vergezellen op %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Afmelden" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Van de site afmelden" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Gebruiker aanmaken" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Bij de site aanmelden" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Help" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Help me!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Zoeken" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Naar gebruikers of tekst zoeken" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Mededeling van de website" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Lokale weergaven" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Mededeling van de pagina" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Secundaire sitenavigatie" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Over" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Veel gestelde vragen" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "Gebruiksvoorwaarden" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privacy" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Broncode" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contact" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Widget" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licentie van de StatusNet-software" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4732,12 +4756,12 @@ msgstr "" "**%%site.name%%** is een microblogdienst van [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** is een microblogdienst. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4748,45 +4772,45 @@ msgstr "" "versie %s, beschikbaar onder de [GNU Affero General Public License](http://" "www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licentie voor siteinhoud" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Inhoud en gegevens van %1$s zijn persoonlijk en vertrouwelijk." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Auteursrechten op inhoud en gegevens rusten bij %1$s. Alle rechten " "voorbehouden." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Auteursrechten op inhoud en gegevens rusten bij de respectievelijke " "gebruikers. Alle rechten voorbehouden." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Alle " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licentie." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginering" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Later" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Eerder" @@ -5091,83 +5115,88 @@ msgstr "Er is een fout opgetreden bij het opslaan van de mededeling." msgid "Specify the name of the user to subscribe to" msgstr "Geef de naam op van de gebruiker waarop u wilt abonneren" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Onbekende gebruiker." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Geabonneerd op %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" "Geef de naam op van de gebruiker waarvoor u het abonnement wilt opzeggen" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Uw abonnement op %s is opgezegd" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Dit commando is nog niet geïmplementeerd." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notificaties uitgeschakeld." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Het is niet mogelijk de mededelingen uit te schakelen." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notificaties ingeschakeld." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Het is niet mogelijk de notificatie uit te schakelen." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Het aanmeldcommando is uitgeschakeld" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Deze verwijzing kan slechts één keer gebruikt worden en is twee minuten " "geldig: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "U bent op geen enkele gebruiker geabonneerd." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "U bent geabonneerd op deze gebruiker:" msgstr[1] "U bent geabonneerd op deze gebruikers:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Niemand heeft een abonnenment op u." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Deze gebruiker is op u geabonneerd:" msgstr[1] "Deze gebruikers zijn op u geabonneerd:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "U bent lid van geen enkele groep." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "U bent lid van deze groep:" msgstr[1] "U bent lid van deze groepen:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5959,10 +5988,6 @@ msgstr "" msgid "Duplicate notice" msgstr "Duplicaatmelding" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "U mag zich niet abonneren." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Kon nieuw abonnement niet toevoegen." @@ -6139,34 +6164,6 @@ msgstr "Gebruikers met een abonnement op %s" msgid "Groups %s is a member of" msgstr "Groepen waar %s lid van is" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "U bent al gebonneerd!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Deze gebruiker negeert u." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Kan niet abonneren " - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Het was niet mogelijk om een ander op u te laten abonneren" - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Niet geabonneerd!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Het was niet mogelijk het abonnement op uzelf te verwijderen." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Kon abonnement niet verwijderen." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/nn/LC_MESSAGES/statusnet.po b/locale/nn/LC_MESSAGES/statusnet.po index b82d1f96a1..02da6a191f 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:56:57+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:37+0000\n" "Language-Team: Norwegian Nynorsk\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -105,7 +105,6 @@ msgstr "Dette emneord finst ikkje." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Brukaren finst ikkje." @@ -565,7 +564,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Konto" @@ -955,7 +954,7 @@ msgstr "Du er ikkje medlem av den gruppa." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Det var eit problem med sesjons billetten din." @@ -1736,7 +1735,7 @@ msgstr "%s medlemmar i gruppa, side %d" msgid "A list of the users in this group." msgstr "Ei liste over brukarane i denne gruppa." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2110,7 +2109,7 @@ msgstr "Feil brukarnamn eller passord" msgid "Error setting user. You are probably not authorized." msgstr "Ikkje autorisert." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Logg inn" @@ -3085,7 +3084,7 @@ msgstr "Feil med stadfestingskode." msgid "Registration successful" msgstr "Registreringa gikk bra" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrér" @@ -3977,7 +3976,8 @@ msgstr "Ingen innskriven kode" msgid "You are not subscribed to that profile." msgstr "Du tingar ikkje oppdateringar til den profilen." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Kunne ikkje lagra abonnement." @@ -4429,7 +4429,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Personleg" @@ -4493,22 +4493,22 @@ msgstr "Kunne ikkje oppdatere melding med ny URI." msgid "DB error inserting hashtag: %s" msgstr "databasefeil ved innsetjing av skigardmerkelapp (#merkelapp): %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Eit problem oppstod ved lagring av notis." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Feil ved lagring av notis. Ukjend brukar." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "For mange notisar for raskt; tek ei pause, og prøv igjen om eit par minutt." -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " @@ -4516,30 +4516,57 @@ msgid "" msgstr "" "For mange notisar for raskt; tek ei pause, og prøv igjen om eit par minutt." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Du kan ikkje lengre legge inn notisar på denne sida." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Eit problem oppstod ved lagring av notis." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Eit problem oppstod ved lagring av notis." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Databasefeil, kan ikkje lagra svar: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +#, fuzzy +msgid "You have been banned from subscribing." +msgstr "Brukaren tillet deg ikkje å tinga meldingane sine." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Brukar har blokkert deg." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Ikkje tinga." + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Kan ikkje sletta tinging." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Kan ikkje sletta tinging." + +#: classes/User.php:372 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Melding til %1$s på %2$s" @@ -4590,127 +4617,127 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Ingen tittel" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Navigasjon for hovudsida" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Heim" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Personleg profil og oversyn over vener" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Endra e-posten, avataren, passordet eller profilen" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Kopla til" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Klarte ikkje å omdirigera til tenaren: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Navigasjon for hovudsida" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Invitér" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Inviter vennar og kollega til å bli med deg på %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Logg ut" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Logg ut or sida" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Opprett ny konto" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Logg inn or sida" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Hjelp" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Hjelp meg!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Søk" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Søk etter folk eller innhald" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Statusmelding" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Lokale syningar" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Sidenotis" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Andrenivås side navigasjon" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Om" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "OSS" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Personvern" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Kjeldekode" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:752 +#: lib/action.php:751 #, fuzzy msgid "Badge" msgstr "Dult" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNets programvarelisens" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4719,12 +4746,12 @@ msgstr "" "**%%site.name%%** er ei mikrobloggingteneste av [%%site.broughtby%%](%%site." "broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** er ei mikrobloggingteneste. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4735,42 +4762,42 @@ msgstr "" "%s, tilgjengeleg under [GNU Affero General Public License](http://www.fsf." "org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "StatusNets programvarelisens" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Alle" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "lisens." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginering" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "« Etter" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Før »" @@ -5088,83 +5115,88 @@ msgstr "Eit problem oppstod ved lagring av notis." msgid "Specify the name of the user to subscribe to" msgstr "Spesifer namnet til brukaren du vil tinge" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Brukaren finst ikkje." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Tingar %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Spesifer namnet til brukar du vil fjerne tinging på" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Tingar ikkje %s lengre" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Kommando ikkje implementert." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notifikasjon av." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Kan ikkje skru av notifikasjon." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notifikasjon på." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Kan ikkje slå på notifikasjon." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Du tingar ikkje oppdateringar til den profilen." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Du tingar allereie oppdatering frå desse brukarane:" msgstr[1] "Du tingar allereie oppdatering frå desse brukarane:" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Kan ikkje tinga andre til deg." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Kan ikkje tinga andre til deg." msgstr[1] "Kan ikkje tinga andre til deg." -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Du er ikkje medlem av den gruppa." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Du er ikkje medlem av den gruppa." msgstr[1] "Du er ikkje medlem av den gruppa." -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5848,11 +5880,6 @@ msgstr "Feil med å henta inn ekstern profil" msgid "Duplicate notice" msgstr "Slett notis" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "Brukaren tillet deg ikkje å tinga meldingane sine." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Kan ikkje leggja til ny tinging." @@ -6040,36 +6067,6 @@ msgstr "Mennesker som tingar %s" msgid "Groups %s is a member of" msgstr "Grupper %s er medlem av" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Brukar har blokkert deg." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Kan ikkje tinga." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Kan ikkje tinga andre til deg." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Ikkje tinga." - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Kan ikkje sletta tinging." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Kan ikkje sletta tinging." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/pl/LC_MESSAGES/statusnet.po b/locale/pl/LC_MESSAGES/statusnet.po index a661850277..d404e00bd3 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:04+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:44+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.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -103,7 +103,6 @@ msgstr "Nie ma takiej strony" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Brak takiego użytkownika." @@ -562,7 +561,7 @@ msgstr "" "uzyskać możliwość %3$s danych konta %4$s. Dostęp do konta %4" "$s powinien być udostępniany tylko zaufanym osobom trzecim." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Konto" @@ -938,7 +937,7 @@ msgstr "Nie jesteś właścicielem tej aplikacji." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Wystąpił problem z tokenem sesji." @@ -1675,7 +1674,7 @@ msgstr "Członkowie grupy %1$s, strona %2$d" msgid "A list of the users in this group." msgstr "Lista użytkowników znajdujących się w tej grupie." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Administrator" @@ -2059,7 +2058,7 @@ msgstr "Niepoprawna nazwa użytkownika lub hasło." msgid "Error setting user. You are probably not authorized." msgstr "Błąd podczas ustawiania użytkownika. Prawdopodobnie brak upoważnienia." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Zaloguj się" @@ -3019,7 +3018,7 @@ msgstr "Nieprawidłowy kod zaproszenia." msgid "Registration successful" msgstr "Rejestracja powiodła się" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Zarejestruj się" @@ -3919,7 +3918,8 @@ msgstr "Nie podano kodu" msgid "You are not subscribed to that profile." msgstr "Nie jesteś subskrybowany do tego profilu." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Nie można zapisać subskrypcji." @@ -4380,7 +4380,7 @@ msgstr "" msgid "Plugins" msgstr "Wtyczki" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Wersja" @@ -4444,22 +4444,22 @@ msgstr "Nie można zaktualizować wiadomości za pomocą nowego adresu URL." msgid "DB error inserting hashtag: %s" msgstr "Błąd bazy danych podczas wprowadzania znacznika mieszania: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problem podczas zapisywania wpisu. Za długi." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problem podczas zapisywania wpisu. Nieznany użytkownik." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Za dużo wpisów w za krótkim czasie, weź głęboki oddech i wyślij ponownie za " "kilka minut." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4467,29 +4467,53 @@ msgstr "" "Za dużo takich samych wiadomości w za krótkim czasie, weź głęboki oddech i " "wyślij ponownie za kilka minut." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Zabroniono ci wysyłania wpisów na tej witrynie." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problem podczas zapisywania wpisu." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Problem podczas zapisywania skrzynki odbiorczej grupy." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Błąd bazy danych podczas wprowadzania odpowiedzi: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Zablokowano subskrybowanie." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Już subskrybowane." + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Użytkownik zablokował cię." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Niesubskrybowane." + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Nie można usunąć autosubskrypcji." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Nie można usunąć subskrypcji." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Witaj w %1$s, @%2$s." @@ -4539,124 +4563,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Strona bez nazwy" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Główna nawigacja witryny" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Strona domowa" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Profil osobisty i oś czasu przyjaciół" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Zmień adres e-mail, awatar, hasło, profil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Połącz" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Połącz z serwisami" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Zmień konfigurację witryny" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Zaproś" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Zaproś przyjaciół i kolegów do dołączenia do ciebie na %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Wyloguj się" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Wyloguj się z witryny" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Utwórz konto" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Zaloguj się na witrynie" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Pomoc" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Pomóż mi." -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Wyszukaj" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Wyszukaj osoby lub tekst" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Wpis witryny" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Lokalne widoki" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Wpis strony" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Druga nawigacja witryny" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "O usłudze" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "TOS" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Prywatność" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Kod źródłowy" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Odznaka" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licencja oprogramowania StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4665,12 +4689,12 @@ msgstr "" "**%%site.name%%** jest usługą mikroblogowania prowadzoną przez [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** jest usługą mikroblogowania. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4681,45 +4705,45 @@ msgstr "" "status.net/) w wersji %s, dostępnego na [Powszechnej Licencji Publicznej GNU " "Affero](http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licencja zawartości witryny" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Treść i dane %1$s są prywatne i poufne." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Prawa autorskie do treści i danych są własnością %1$s. Wszystkie prawa " "zastrzeżone." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Prawa autorskie do treści i danych są własnością współtwórców. Wszystkie " "prawa zastrzeżone." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Wszystko " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licencja." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginacja" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Później" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Wcześniej" @@ -5021,85 +5045,90 @@ msgstr "Błąd podczas zapisywania wpisu." msgid "Specify the name of the user to subscribe to" msgstr "Podaj nazwę użytkownika do subskrybowania." -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Brak takiego użytkownika." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Subskrybowano użytkownika %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Podaj nazwę użytkownika do usunięcia subskrypcji." -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Usunięto subskrypcję użytkownika %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Nie zaimplementowano polecenia." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Wyłączono powiadomienia." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Nie można wyłączyć powiadomień." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Włączono powiadomienia." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Nie można włączyć powiadomień." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Polecenie logowania jest wyłączone" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Tego odnośnika można użyć tylko raz i będzie prawidłowy tylko przez dwie " "minuty: %s." -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Nie subskrybujesz nikogo." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Subskrybujesz tę osobę:" msgstr[1] "Subskrybujesz te osoby:" msgstr[2] "Subskrybujesz te osoby:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Nikt cię nie subskrybuje." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Ta osoba cię subskrybuje:" msgstr[1] "Te osoby cię subskrybują:" msgstr[2] "Te osoby cię subskrybują:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Nie jesteś członkiem żadnej grupy." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Jesteś członkiem tej grupy:" msgstr[1] "Jesteś członkiem tych grup:" msgstr[2] "Jesteś członkiem tych grup:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5884,10 +5913,6 @@ msgstr "Błąd podczas wprowadzania zdalnego profilu" msgid "Duplicate notice" msgstr "Duplikat wpisu" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Zablokowano subskrybowanie." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Nie można wprowadzić nowej subskrypcji." @@ -6065,34 +6090,6 @@ msgstr "Osoby subskrybowane do %s" msgid "Groups %s is a member of" msgstr "Grupy %s są członkiem" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Już subskrybowane." - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Użytkownik zablokował cię." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Nie można subskrybować." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Nie można subskrybować innych do ciebie." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Niesubskrybowane." - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Nie można usunąć autosubskrypcji." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Nie można usunąć subskrypcji." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/pt/LC_MESSAGES/statusnet.po b/locale/pt/LC_MESSAGES/statusnet.po index 7b700eded3..5fb83226e5 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:07+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:46+0000\n" "Language-Team: Portuguese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -102,7 +102,6 @@ msgstr "Página não encontrada." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Utilizador não encontrado." @@ -558,7 +557,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Conta" @@ -940,7 +939,7 @@ msgstr "Não é membro deste grupo." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Ocorreu um problema com a sua sessão." @@ -1702,7 +1701,7 @@ msgstr "Membros do grupo %1$s, página %2$d" msgid "A list of the users in this group." msgstr "Uma lista dos utilizadores neste grupo." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Gestor" @@ -2086,7 +2085,7 @@ msgstr "Nome de utilizador ou senha incorrectos." msgid "Error setting user. You are probably not authorized." msgstr "Erro ao preparar o utilizador. Provavelmente não está autorizado." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Entrar" @@ -3061,7 +3060,7 @@ msgstr "Desculpe, código de convite inválido." msgid "Registration successful" msgstr "Registo efectuado" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registar" @@ -3964,7 +3963,8 @@ msgstr "Nenhum código introduzido" msgid "You are not subscribed to that profile." msgstr "Não subscreveu esse perfil." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Não foi possível gravar a subscrição." @@ -4424,7 +4424,7 @@ msgstr "" msgid "Plugins" msgstr "Plugins" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Versão" @@ -4489,22 +4489,22 @@ msgstr "Não foi possível actualizar a mensagem com a nova URI." msgid "DB error inserting hashtag: %s" msgstr "Erro na base de dados ao inserir a marca: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problema na gravação da nota. Demasiado longa." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problema na gravação da nota. Utilizador desconhecido." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Demasiadas notas, demasiado rápido; descanse e volte a publicar daqui a " "alguns minutos." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4512,30 +4512,54 @@ msgstr "" "Demasiadas mensagens duplicadas, demasiado rápido; descanse e volte a " "publicar daqui a alguns minutos." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Está proibido de publicar notas neste site." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problema na gravação da nota." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Problema na gravação da nota." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Ocorreu um erro na base de dados ao inserir a resposta: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Foi bloqueado de fazer subscrições" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Já subscrito!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "O utilizador bloqueou-o." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Não subscrito!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Não foi possível apagar a auto-subscrição." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Não foi possível apagar a subscrição." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "%1$s dá-lhe as boas-vindas, @%2$s!" @@ -4585,124 +4609,124 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "Página sem título" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Navegação primária deste site" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Início" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Perfil pessoal e notas dos amigos" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Altere o seu endereço electrónico, avatar, senha, perfil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Ligar" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Ligar aos serviços" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Alterar a configuração do site" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Convidar" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Convidar amigos e colegas para se juntarem a si em %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Sair" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Terminar esta sessão" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Criar uma conta" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Iniciar uma sessão" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Ajuda" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Ajudem-me!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Pesquisa" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Procurar pessoas ou pesquisar texto" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Aviso do site" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Vistas locais" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Aviso da página" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Navegação secundária deste site" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Sobre" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "Termos" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privacidade" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Código" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contacto" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Emblema" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licença de software do StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4711,12 +4735,12 @@ msgstr "" "**%%site.name%%** é um serviço de microblogues disponibilizado por [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** é um serviço de microblogues. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4727,41 +4751,41 @@ msgstr "" "disponibilizado nos termos da [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licença de conteúdos do site" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Tudo " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licença." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginação" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Posteriores" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Anteriores" @@ -5066,82 +5090,87 @@ msgstr "Erro ao gravar nota." msgid "Specify the name of the user to subscribe to" msgstr "Introduza o nome do utilizador para subscrever" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Utilizador não encontrado." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Subscreveu %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Introduza o nome do utilizador para deixar de subscrever" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Deixou de subscrever %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Comando ainda não implementado." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notificação desligada." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Não foi possível desligar a notificação." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notificação ligada." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Não foi possível ligar a notificação." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Comando para iniciar sessão foi desactivado" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Esta ligação é utilizável uma única vez e só durante os próximos 2 minutos: %" "s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Não subscreveu ninguém." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Subscreveu esta pessoa:" msgstr[1] "Subscreveu estas pessoas:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Ninguém subscreve as suas notas." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Esta pessoa subscreve as suas notas:" msgstr[1] "Estas pessoas subscrevem as suas notas:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Não está em nenhum grupo." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Está no grupo:" msgstr[1] "Está nos grupos:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5925,10 +5954,6 @@ msgstr "Erro ao inserir perfil remoto" msgid "Duplicate notice" msgstr "Nota duplicada" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Foi bloqueado de fazer subscrições" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Não foi possível inserir nova subscrição." @@ -6105,34 +6130,6 @@ msgstr "Pessoas que subscrevem %s" msgid "Groups %s is a member of" msgstr "Grupos de que %s é membro" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Já subscrito!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "O utilizador bloqueou-o." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Não foi possível subscrever." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Não foi possível que outro o subscrevesse." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Não subscrito!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Não foi possível apagar a auto-subscrição." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Não foi possível apagar a subscrição." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/pt_BR/LC_MESSAGES/statusnet.po b/locale/pt_BR/LC_MESSAGES/statusnet.po index 0d3d92e18b..93e575677d 100644 --- a/locale/pt_BR/LC_MESSAGES/statusnet.po +++ b/locale/pt_BR/LC_MESSAGES/statusnet.po @@ -11,12 +11,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:10+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:50+0000\n" "Language-Team: Brazilian Portuguese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -101,7 +101,6 @@ msgstr "Esta página não existe." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Este usuário não existe." @@ -567,7 +566,7 @@ msgstr "" "fornecer acesso à sua conta %4$s somente para terceiros nos quais você " "confia." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Conta" @@ -945,7 +944,7 @@ msgstr "Você não é o dono desta aplicação." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Ocorreu um problema com o seu token de sessão." @@ -1694,7 +1693,7 @@ msgstr "Membros do grupo %1$s, pág. %2$d" msgid "A list of the users in this group." msgstr "Uma lista dos usuários deste grupo." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Admin" @@ -2081,7 +2080,7 @@ msgid "Error setting user. You are probably not authorized." msgstr "" "Erro na configuração do usuário. Você provavelmente não tem autorização." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Entrar" @@ -3053,7 +3052,7 @@ msgstr "Desculpe, mas o código do convite é inválido." msgid "Registration successful" msgstr "Registro realizado com sucesso" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrar-se" @@ -3380,9 +3379,9 @@ msgid "Statistics" msgstr "Estatísticas" #: actions/showapplication.php:203 -#, fuzzy, php-format +#, php-format msgid "Created by %1$s - %2$s access by default - %3$d users" -msgstr "criado por %1$s - %2$s acessa por padrão - %3$d usuários" +msgstr "Criado por %1$s - acesso %2$s por padrão - %3$d usuários" #: actions/showapplication.php:213 msgid "Application actions" @@ -3425,14 +3424,13 @@ msgstr "" "assinatura em texto plano." #: actions/showapplication.php:309 -#, fuzzy msgid "Are you sure you want to reset your consumer key and secret?" -msgstr "Tem certeza que deseja excluir esta mensagem?" +msgstr "Tem certeza que deseja restaurar sua chave e segredo de consumidor?" #: actions/showfavorites.php:79 -#, fuzzy, php-format +#, php-format msgid "%1$s's favorite notices, page %2$d" -msgstr "Mensagens favoritas de %s" +msgstr "Mensagens favoritas de %1$s, pág. %2$d" #: actions/showfavorites.php:132 msgid "Could not retrieve favorite notices." @@ -3492,9 +3490,9 @@ msgid "%s group" msgstr "Grupo %s" #: actions/showgroup.php:84 -#, fuzzy, php-format +#, php-format msgid "%1$s group, page %2$d" -msgstr "Membros do grupo %1$s, pág. %2$d" +msgstr "Grupo %1$s, pág. %2$d" #: actions/showgroup.php:218 msgid "Group profile" @@ -3617,9 +3615,9 @@ msgid " tagged %s" msgstr " etiquetada %s" #: actions/showstream.php:79 -#, fuzzy, php-format +#, php-format msgid "%1$s, page %2$d" -msgstr "%1$s e amigos, pág. %2$d" +msgstr "%1$s, pág. %2$d" #: actions/showstream.php:122 #, php-format @@ -3953,7 +3951,8 @@ msgstr "Não foi digitado nenhum código" msgid "You are not subscribed to that profile." msgstr "Você não está assinando esse perfil." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Não foi possível salvar a assinatura." @@ -4055,9 +4054,9 @@ msgid "SMS" msgstr "SMS" #: actions/tag.php:68 -#, fuzzy, php-format +#, php-format msgid "Notices tagged with %1$s, page %2$d" -msgstr "Usuários auto-etiquetados com %1$s - pág. %2$d" +msgstr "Mensagens etiquetadas com %1$s, pág. %2$d" #: actions/tag.php:86 #, php-format @@ -4342,9 +4341,9 @@ msgid "Enjoy your hotdog!" msgstr "Aproveite o seu cachorro-quente!" #: actions/usergroups.php:64 -#, fuzzy, php-format +#, php-format msgid "%1$s groups, page %2$d" -msgstr "Membros do grupo %1$s, pág. %2$d" +msgstr "Grupos de %1$s, pág. %2$d" #: actions/usergroups.php:130 msgid "Search for more groups" @@ -4417,7 +4416,7 @@ msgstr "" msgid "Plugins" msgstr "Plugins" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Versão" @@ -4478,22 +4477,22 @@ msgstr "Não foi possível atualizar a mensagem com a nova URI." msgid "DB error inserting hashtag: %s" msgstr "Erro no banco de dados durante a inserção da hashtag: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problema no salvamento da mensagem. Ela é muito extensa." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problema no salvamento da mensagem. Usuário desconhecido." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Muitas mensagens em um período curto de tempo; dê uma respirada e publique " "novamente daqui a alguns minutos." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4501,30 +4500,53 @@ msgstr "" "Muitas mensagens duplicadas em um período curto de tempo; dê uma respirada e " "publique novamente daqui a alguns minutos." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Você está proibido de publicar mensagens neste site." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problema no salvamento da mensagem." -#: classes/Notice.php:790 -#, fuzzy +#: classes/Notice.php:811 msgid "Problem saving group inbox." -msgstr "Problema no salvamento da mensagem." +msgstr "Problema no salvamento das mensagens recebidas do grupo." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Erro no banco de dados na inserção da reposta: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Você está proibido de assinar." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Já assinado!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "O usuário bloqueou você." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Não assinado!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Não foi possível excluir a auto-assinatura." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Não foi possível excluir a assinatura." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Bem vindo(a) a %1$s, @%2$s!" @@ -4574,124 +4596,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Página sem título" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Navegação primária no site" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Início" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Perfil pessoal e fluxo de mensagens dos amigos" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Mude seu e-mail, avatar, senha, perfil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Conectar" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Conecte-se a outros serviços" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Mude as configurações do site" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Convidar" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Convide seus amigos e colegas para unir-se a você no %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Sair" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Sai do site" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Cria uma conta" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Autentique-se no site" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Ajuda" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Ajudem-me!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Procurar" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Procura por pessoas ou textos" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Mensagem do site" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Visualizações locais" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Notícia da página" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Navegação secundária no site" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Sobre" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "Termos de uso" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Privacidade" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Fonte" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Contato" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Mini-aplicativo" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Licença do software StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4700,12 +4722,12 @@ msgstr "" "**%%site.name%%** é um serviço de microblog disponibilizado por [%%site." "broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** é um serviço de microblog. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4716,43 +4738,43 @@ msgstr "" "versão %s, disponível sob a [GNU Affero General Public License] (http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licença do conteúdo do site" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "O conteúdo e os dados de %1$s são privados e confidenciais." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Conteúdo e dados licenciados sob %1$s. Todos os direitos reservados." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Conteúdo e dados licenciados pelos colaboradores. Todos os direitos " "reservados." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Todas " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licença." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Paginação" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Próximo" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Anterior" @@ -4785,32 +4807,33 @@ msgid "Design configuration" msgstr "Configuração da aparência" #: lib/adminpanelaction.php:322 -#, fuzzy msgid "User configuration" -msgstr "Configuração dos caminhos" +msgstr "Configuração do usuário" #: lib/adminpanelaction.php:327 -#, fuzzy msgid "Access configuration" -msgstr "Configuração da aparência" +msgstr "Configuração do acesso" #: lib/adminpanelaction.php:332 msgid "Paths configuration" msgstr "Configuração dos caminhos" #: lib/adminpanelaction.php:337 -#, fuzzy msgid "Sessions configuration" -msgstr "Configuração da aparência" +msgstr "Configuração das sessões" #: lib/apiauth.php:95 msgid "API resource requires read-write access, but you only have read access." msgstr "" +"Os recursos de API exigem acesso de leitura e escrita, mas você possui " +"somente acesso de leitura." #: lib/apiauth.php:273 #, php-format msgid "Failed API auth attempt, nickname = %1$s, proxy = %2$s, ip = %3$s" msgstr "" +"A tentativa de autenticação na API falhou, identificação = %1$s, proxy = %2" +"$s, ip = %3$s" #: lib/applicationeditform.php:136 msgid "Edit application" @@ -5055,82 +5078,87 @@ msgstr "Erro no salvamento da mensagem." msgid "Specify the name of the user to subscribe to" msgstr "Especifique o nome do usuário que será assinado" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Este usuário não existe." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Efetuada a assinatura de %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Especifique o nome do usuário cuja assinatura será cancelada" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Cancelada a assinatura de %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "O comando não foi implementado ainda." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notificação desligada." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Não é possível desligar a notificação." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notificação ligada." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Não é possível ligar a notificação." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "O comando para autenticação está desabilitado" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Este link é utilizável somente uma vez e é válido somente por dois minutos: %" "s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Você não está assinando ninguém." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Você já está assinando esta pessoa:" msgstr[1] "Você já está assinando estas pessoas:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Ninguém o assinou ainda." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Esta pessoa está assinando você:" msgstr[1] "Estas pessoas estão assinando você:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Você não é membro de nenhum grupo." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Você é membro deste grupo:" msgstr[1] "Você é membro destes grupos:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5917,10 +5945,6 @@ msgstr "Erro na inserção do perfil remoto" msgid "Duplicate notice" msgstr "Duplicar a mensagem" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Você está proibido de assinar." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Não foi possível inserir a nova assinatura." @@ -6028,7 +6052,7 @@ msgstr "Repetir esta mensagem" #: lib/router.php:665 msgid "No single user defined for single-user mode." -msgstr "" +msgstr "Nenhum usuário definido para o modo de usuário único." #: lib/sandboxform.php:67 msgid "Sandbox" @@ -6097,34 +6121,6 @@ msgstr "Assinantes de %s" msgid "Groups %s is a member of" msgstr "Grupos dos quais %s é membro" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Já assinado!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "O usuário bloqueou você." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Não foi possível assinar." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Não foi possível fazer com que outros o assinem." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Não assinado!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Não foi possível excluir a auto-assinatura." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Não foi possível excluir a assinatura." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/ru/LC_MESSAGES/statusnet.po b/locale/ru/LC_MESSAGES/statusnet.po index e1dd38e99f..57cb89884d 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:13+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:52+0000\n" "Language-Team: Russian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -104,7 +104,6 @@ msgstr "Нет такой страницы" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Нет такого пользователя." @@ -565,7 +564,7 @@ msgstr "" "предоставлять разрешение на доступ к вашей учётной записи %4$s только тем " "сторонним приложениям, которым вы доверяете." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Настройки" @@ -942,7 +941,7 @@ msgstr "Вы не являетесь владельцем этого прило #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Проблема с Вашей сессией. Попробуйте ещё раз, пожалуйста." @@ -1695,7 +1694,7 @@ msgstr "Участники группы %1$s, страница %2$d" msgid "A list of the users in this group." msgstr "Список пользователей, являющихся членами этой группы." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Настройки" @@ -2081,7 +2080,7 @@ msgstr "Некорректное имя или пароль." msgid "Error setting user. You are probably not authorized." msgstr "Ошибка установки пользователя. Вы, вероятно, не авторизованы." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Вход" @@ -3036,7 +3035,7 @@ msgstr "Извините, неверный пригласительный код msgid "Registration successful" msgstr "Регистрация успешна!" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Регистрация" @@ -3942,7 +3941,8 @@ msgstr "Код не введён" msgid "You are not subscribed to that profile." msgstr "Вы не подписаны на этот профиль." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Не удаётся сохранить подписку." @@ -4403,7 +4403,7 @@ msgstr "" msgid "Plugins" msgstr "Плагины" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Версия" @@ -4464,22 +4464,22 @@ msgstr "Не удаётся обновить сообщение с новым UR msgid "DB error inserting hashtag: %s" msgstr "Ошибка баз данных при вставке хеш-тегов для %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Проблемы с сохранением записи. Слишком длинно." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Проблема при сохранении записи. Неизвестный пользователь." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Слишком много записей за столь короткий срок; передохните немного и " "попробуйте вновь через пару минут." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4487,29 +4487,53 @@ msgstr "" "Слишком много одинаковых записей за столь короткий срок; передохните немного " "и попробуйте вновь через пару минут." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Вам запрещено поститься на этом сайте (бан)" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Проблемы с сохранением записи." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Проблемы с сохранением входящих сообщений группы." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Ошибка баз данных при вставке ответа для %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Вы заблокированы от подписки." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Уже подписаны!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Пользователь заблокировал Вас." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Не подписаны!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Невозможно удалить самоподписку." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Не удаётся удалить подписку." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Добро пожаловать на %1$s, @%2$s!" @@ -4559,124 +4583,124 @@ msgstr "%1$s — %2$s" msgid "Untitled page" msgstr "Страница без названия" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Главная навигация" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Моё" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Личный профиль и лента друзей" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Изменить ваш email, аватару, пароль, профиль" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Соединить" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Соединить с сервисами" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Изменить конфигурацию сайта" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Пригласить" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Пригласите друзей и коллег стать такими же как вы участниками %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Выход" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Выйти" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Создать новый аккаунт" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Войти" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Помощь" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Помощь" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Поиск" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Искать людей или текст" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Новая запись" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Локальные виды" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Новая запись" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Навигация по подпискам" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "О проекте" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "ЧаВо" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "TOS" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Пользовательское соглашение" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Исходный код" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Контактная информация" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Бедж" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNet лицензия" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4685,12 +4709,12 @@ msgstr "" "**%%site.name%%** — это сервис микроблогинга, созданный для вас при помощи [%" "%site.broughtby%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** — сервис микроблогинга. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4702,44 +4726,44 @@ msgstr "" "лицензией [GNU Affero General Public License](http://www.fsf.org/licensing/" "licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Лицензия содержимого сайта" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Содержание и данные %1$s являются личными и конфиденциальными." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" "Авторские права на содержание и данные принадлежат %1$s. Все права защищены." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Авторские права на содержание и данные принадлежат разработчикам. Все права " "защищены." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "All " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "license." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Разбиение на страницы" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Сюда" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Туда" @@ -5041,83 +5065,88 @@ msgstr "Проблемы с сохранением записи." msgid "Specify the name of the user to subscribe to" msgstr "Укажите имя пользователя для подписки." -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Нет такого пользователя." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Подписано на %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Укажите имя пользователя для отмены подписки." -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Отписано от %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Команда ещё не выполнена." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Оповещение отсутствует." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Нет оповещения." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Есть оповещение." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Есть оповещение." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Команда входа отключена" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "Эта ссылка действительна только один раз в течение 2 минут: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Вы ни на кого не подписаны." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Вы подписаны на этих людей:" msgstr[1] "Вы подписаны на этих людей:" msgstr[2] "Вы подписаны на этих людей:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Никто не подписан на вас." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Эти люди подписались на вас:" msgstr[1] "Эти люди подписались на вас:" msgstr[2] "Эти люди подписались на вас:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Вы не состоите ни в одной группе." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Вы являетесь участником следующих групп:" msgstr[1] "Вы являетесь участником следующих групп:" msgstr[2] "Вы являетесь участником следующих групп:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5901,10 +5930,6 @@ msgstr "Ошибка вставки удалённого профиля" msgid "Duplicate notice" msgstr "Дублировать запись" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Вы заблокированы от подписки." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Не удаётся вставить новую подписку." @@ -6081,34 +6106,6 @@ msgstr "Люди подписанные на %s" msgid "Groups %s is a member of" msgstr "Группы, в которых состоит %s" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Уже подписаны!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Пользователь заблокировал Вас." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Подписка неудачна." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Не удаётся подписать других на вашу ленту." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Не подписаны!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Невозможно удалить самоподписку." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Не удаётся удалить подписку." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/statusnet.po b/locale/statusnet.po index 6fbf800659..13b038cbf7 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-02-18 22:55+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -96,7 +96,6 @@ msgstr "" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "" @@ -536,7 +535,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "" @@ -909,7 +908,7 @@ msgstr "" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1625,7 +1624,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -1955,7 +1954,7 @@ msgstr "" msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "" @@ -2873,7 +2872,7 @@ msgstr "" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -3697,7 +3696,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "" @@ -4119,7 +4119,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "" @@ -4178,48 +4178,72 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "" -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "" + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "" + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "" + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4269,136 +4293,136 @@ msgstr "" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." "broughtby%%](%%site.broughtbyurl%%). " msgstr "" -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "" -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4406,41 +4430,41 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "" @@ -4734,80 +4758,84 @@ msgstr "" msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +msgid "No such user" +msgstr "" + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "" msgstr[1] "" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "" msgstr[1] "" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "" msgstr[1] "" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5459,10 +5487,6 @@ msgstr "" msgid "Duplicate notice" msgstr "" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "" @@ -5639,34 +5663,6 @@ msgstr "" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "" - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "" - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/sv/LC_MESSAGES/statusnet.po b/locale/sv/LC_MESSAGES/statusnet.po index cc959b8eaf..ed733a719c 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:16+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:03:56+0000\n" "Language-Team: Swedish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -100,7 +100,6 @@ msgstr "Ingen sådan sida" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Ingen sådan användare." @@ -553,7 +552,7 @@ msgstr "" "möjligheten att %3$s din %4$s kontoinformation. Du bör bara " "ge tillgång till ditt %4$s-konto till tredje-parter du litar på." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Konto" @@ -931,7 +930,7 @@ msgstr "Du är inte ägaren av denna applikation." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Det var ett problem med din sessions-token." @@ -1674,7 +1673,7 @@ msgstr "%1$s gruppmedlemmar, sida %2$d" msgid "A list of the users in this group." msgstr "En lista av användarna i denna grupp." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Administratör" @@ -2059,7 +2058,7 @@ msgstr "Felaktigt användarnamn eller lösenord." msgid "Error setting user. You are probably not authorized." msgstr "Fel vid inställning av användare. Du har sannolikt inte tillstånd." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Logga in" @@ -3019,7 +3018,7 @@ msgstr "Tyvärr, ogiltig inbjudningskod." msgid "Registration successful" msgstr "Registreringen genomförd" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Registrera" @@ -3918,7 +3917,8 @@ msgstr "Ingen kod ifylld" msgid "You are not subscribed to that profile." msgstr "Du är inte prenumerat hos den profilen." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Kunde inte spara prenumeration." @@ -4382,7 +4382,7 @@ msgstr "" msgid "Plugins" msgstr "Insticksmoduler" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Version" @@ -4443,22 +4443,22 @@ msgstr "Kunde inte uppdatera meddelande med ny URI." msgid "DB error inserting hashtag: %s" msgstr "Databasfel vid infogning av hashtag: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Problem vid sparande av notis. För långt." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Problem vid sparande av notis. Okänd användare." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "För många notiser för snabbt; ta en vilopaus och posta igen om ett par " "minuter." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4466,29 +4466,53 @@ msgstr "" "För många duplicerade meddelanden för snabbt; ta en vilopaus och posta igen " "om ett par minuter." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Du är utestängd från att posta notiser på denna webbplats." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Problem med att spara notis." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Problem med att spara gruppinkorg." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Databasfel vid infogning av svar: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 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 +msgid "Already subscribed!" +msgstr "Redan prenumerant!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Användaren har blockerat dig." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Inte prenumerant!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Kunde inte ta bort själv-prenumeration." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Kunde inte ta bort prenumeration." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Välkommen till %1$s, @%2$s!" @@ -4538,124 +4562,124 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "Namnlös sida" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Primär webbplatsnavigation" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Hem" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Personlig profil och vänners tidslinje" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Ändra din e-post, avatar, lösenord, profil" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Anslut" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "Anslut till tjänster" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Ändra webbplatskonfiguration" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Bjud in" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Bjud in vänner och kollegor att gå med dig på %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Logga ut" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Logga ut från webbplatsen" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Skapa ett konto" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Logga in på webbplatsen" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Hjälp" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Hjälp mig!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Sök" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Sök efter personer eller text" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Webbplatsnotis" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Lokala vyer" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Sidnotis" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Sekundär webbplatsnavigation" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Om" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "Frågor & svar" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "Användarvillkor" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Sekretess" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Källa" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Kontakt" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Emblem" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Programvarulicens för StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4664,12 +4688,12 @@ msgstr "" "**%%site.name%%** är en mikrobloggtjänst tillhandahållen av [%%site.broughtby" "%%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** är en mikrobloggtjänst. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4680,42 +4704,42 @@ msgstr "" "version %s, tillgänglig under [GNU Affero General Public License](http://www." "fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Licens för webbplatsinnehåll" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Innehåll och data av %1$s är privat och konfidensiell." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Innehåll och data copyright av %1$s. Alla rättigheter reserverade." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Innehåll och data copyright av medarbetare. Alla rättigheter reserverade." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Alla " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "licens." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Numrering av sidor" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Senare" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Tidigare" @@ -5016,81 +5040,86 @@ msgstr "Fel vid sparande av notis." msgid "Specify the name of the user to subscribe to" msgstr "Ange namnet på användaren att prenumerara på" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Ingen sådan användare." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Prenumerar på %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Ange namnet på användaren att avsluta prenumeration på" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Prenumeration hos %s avslutad" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Kommando inte implementerat än." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Notifikation av." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Kan inte sätta på notifikation." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Notifikation på." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Kan inte stänga av notifikation." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Inloggningskommando är inaktiverat" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Denna länk är endast användbar en gång, och gäller bara i 2 minuter: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Du prenumererar inte på någon." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Du prenumererar på denna person:" msgstr[1] "Du prenumererar på dessa personer:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "Ingen prenumerar på dig." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Denna person prenumererar på dig:" msgstr[1] "Dessa personer prenumererar på dig:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Du är inte medlem i några grupper." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Du är en medlem i denna grupp:" msgstr[1] "Du är en medlem i dessa grupper:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5872,10 +5901,6 @@ msgstr "Fel vid infogning av fjärrprofilen" msgid "Duplicate notice" msgstr "Duplicerad notis" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Du har blivit utestängd från att prenumerera." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Kunde inte infoga ny prenumeration." @@ -6052,34 +6077,6 @@ msgstr "Personer som prenumererar på %s" msgid "Groups %s is a member of" msgstr "Grupper %s är en medlem i" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Redan prenumerant!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Användaren har blockerat dig." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Kunde inte prenumerera." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Kunde inte göra andra till prenumeranter hos dig." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Inte prenumerant!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Kunde inte ta bort själv-prenumeration." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Kunde inte ta bort prenumeration." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/te/LC_MESSAGES/statusnet.po b/locale/te/LC_MESSAGES/statusnet.po index fce5e5d696..19debf94dd 100644 --- a/locale/te/LC_MESSAGES/statusnet.po +++ b/locale/te/LC_MESSAGES/statusnet.po @@ -8,12 +8,12 @@ msgid "" msgstr "" "Project-Id-Version: StatusNet\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:19+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:04:04+0000\n" "Language-Team: Telugu\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -101,7 +101,6 @@ msgstr "అటువంటి పేజీ లేదు" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "అటువంటి వాడుకరి లేరు." @@ -551,7 +550,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "ఖాతా" @@ -927,7 +926,7 @@ msgstr "మీరు ఈ ఉపకరణం యొక్క యజమాని #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1657,7 +1656,7 @@ msgstr "%1$s గుంపు సభ్యులు, పేజీ %2$d" msgid "A list of the users in this group." msgstr "ఈ గుంపులో వాడుకరులు జాబితా." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -1996,7 +1995,7 @@ msgstr "వాడుకరిపేరు లేదా సంకేతపదం msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "ప్రవేశించండి" @@ -2947,7 +2946,7 @@ msgstr "క్షమించండి, తప్పు ఆహ్వాన స msgid "Registration successful" msgstr "నమోదు విజయవంతం" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "నమోదు" @@ -3802,7 +3801,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "చందాని సృష్టించలేకపోయాం." @@ -4232,7 +4232,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "సంచిక" @@ -4291,51 +4291,77 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "సందేశాన్ని భద్రపరచడంలో పొరపాటు." -#: classes/Notice.php:218 +#: classes/Notice.php:219 #, fuzzy msgid "Problem saving notice. Unknown user." msgstr "సందేశాన్ని భద్రపరచడంలో పొరపాటు." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "ఈ సైటులో నోటీసులు రాయడం నుండి మిమ్మల్ని నిషేధించారు." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "సందేశాన్ని భద్రపరచడంలో పొరపాటు." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "సందేశాన్ని భద్రపరచడంలో పొరపాటు." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "చందాచేరడం నుండి మిమ్మల్ని నిషేధించారు." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "ఇప్పటికే చందాచేరారు!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "వాడుకరి మిమ్మల్ని నిరోధించారు." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "చందాదార్లు" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "చందాని తొలగించలేకపోయాం." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "చందాని తొలగించలేకపోయాం." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "@%2$s, %1$sకి స్వాగతం!" @@ -4386,126 +4412,126 @@ msgstr "%1$s - %2$s" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "ముంగిలి" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "మీ ఈమెయిలు, అవతారం, సంకేతపదం మరియు ప్రౌఫైళ్ళను మార్చుకోండి" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "అనుసంధానించు" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "చందాలు" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "ఆహ్వానించు" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "నిష్క్రమించు" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "సైటు నుండి నిష్క్రమించు" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "కొత్త ఖాతా సృష్టించు" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "సైటులోని ప్రవేశించు" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "సహాయం" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "సహాయం కావాలి!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "వెతుకు" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "సైటు గమనిక" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "స్థానిక వీక్షణలు" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "పేజీ గమనిక" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "చందాలు" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "గురించి" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "ప్రశ్నలు" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "సేవా నియమాలు" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "అంతరంగికత" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "మూలము" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "సంప్రదించు" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "బాడ్జి" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "స్టేటస్‌నెట్ మృదూపకరణ లైసెన్సు" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4514,12 +4540,12 @@ msgstr "" "**%%site.name%%** అనేది [%%site.broughtby%%](%%site.broughtbyurl%%) వారు " "అందిస్తున్న మైక్రో బ్లాగింగు సదుపాయం. " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** అనేది మైక్రో బ్లాగింగు సదుపాయం." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4530,42 +4556,42 @@ msgstr "" "html) కింద లభ్యమయ్యే [స్టేటస్‌నెట్](http://status.net/) మైక్రోబ్లాగింగ్ ఉపకరణం సంచిక %s " "పై నడుస్తుంది." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "కొత్త సందేశం" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "అన్నీ " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "పేజీకరణ" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "తర్వాత" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "ఇంతక్రితం" @@ -4875,80 +4901,85 @@ msgstr "సందేశాన్ని భద్రపరచడంలో పొ msgid "Specify the name of the user to subscribe to" msgstr "ఏవరికి చందా చేరాలనుకుంటున్నారో ఆ వాడుకరి పేరు తెలియజేయండి" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "అటువంటి వాడుకరి లేరు." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "%sకి చందా చేరారు" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "ఎవరి నుండి చందా విరమించాలనుకుంటున్నారో ఆ వాడుకరి పేరు తెలియజేయండి" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "%s నుండి చందా విరమించారు" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "ఈ లంకెని ఒకే సారి ఉపయోగించగలరు, మరియు అది పనిచేసేది 2 నిమిషాలు మాత్రమే: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "మీరు ఎవరికీ చందాచేరలేదు." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "%sకి స్పందనలు" msgstr[1] "%sకి స్పందనలు" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "మీకు చందాదార్లు ఎవరూ లేరు." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "%sకి స్పందనలు" msgstr[1] "%sకి స్పందనలు" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "మీరు ఏ గుంపులోనూ సభ్యులు కాదు." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "మీరు ఇప్పటికే లోనికి ప్రవేశించారు!" msgstr[1] "మీరు ఇప్పటికే లోనికి ప్రవేశించారు!" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5635,10 +5666,6 @@ msgstr "దూరపు ప్రొపైలుని చేర్చటంల msgid "Duplicate notice" msgstr "కొత్త సందేశం" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "చందాచేరడం నుండి మిమ్మల్ని నిషేధించారు." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "" @@ -5821,36 +5848,6 @@ msgstr "%sకి చందాచేరిన వ్యక్తులు" msgid "Groups %s is a member of" msgstr "%s సభ్యులుగా ఉన్న గుంపులు" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "ఇప్పటికే చందాచేరారు!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "వాడుకరి మిమ్మల్ని నిరోధించారు." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "చందా చేర్చలేకపోయాం." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "చందాదార్లు" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "చందాని తొలగించలేకపోయాం." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "చందాని తొలగించలేకపోయాం." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/tr/LC_MESSAGES/statusnet.po b/locale/tr/LC_MESSAGES/statusnet.po index d65a14b408..441b4458f0 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:22+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:04:14+0000\n" "Language-Team: Turkish\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -106,7 +106,6 @@ msgstr "Böyle bir durum mesajı yok." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Böyle bir kullanıcı yok." @@ -567,7 +566,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 #, fuzzy msgid "Account" msgstr "Hakkında" @@ -962,7 +961,7 @@ msgstr "Bize o profili yollamadınız" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1728,7 +1727,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2080,7 +2079,7 @@ msgstr "Yanlış kullanıcı adı veya parola." msgid "Error setting user. You are probably not authorized." msgstr "Yetkilendirilmemiş." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Giriş" @@ -3048,7 +3047,7 @@ msgstr "Onay kodu hatası." msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Kayıt" @@ -3905,7 +3904,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "Bize o profili yollamadınız" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "Abonelik oluşturulamadı." @@ -4350,7 +4350,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Kişisel" @@ -4413,51 +4413,78 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Durum mesajını kaydederken hata oluştu." -#: classes/Notice.php:218 +#: classes/Notice.php:219 #, fuzzy msgid "Problem saving notice. Unknown user." msgstr "Durum mesajını kaydederken hata oluştu." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Durum mesajını kaydederken hata oluştu." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Durum mesajını kaydederken hata oluştu." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Cevap eklenirken veritabanı hatası: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +#, fuzzy +msgid "User has blocked you." +msgstr "Kullanıcının profili yok." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Bu kullanıcıyı zaten takip etmiyorsunuz!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Abonelik silinemedi." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Abonelik silinemedi." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4511,131 +4538,131 @@ msgstr "%1$s'in %2$s'deki durum mesajları " msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Başlangıç" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Bağlan" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Sunucuya yönlendirme yapılamadı: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Abonelikler" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Çıkış" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "Yeni hesap oluştur" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Yardım" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "Yardım" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Ara" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "Yeni durum mesajı" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "Yeni durum mesajı" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "Abonelikler" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Hakkında" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "SSS" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Gizlilik" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Kaynak" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "İletişim" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4644,12 +4671,12 @@ msgstr "" "**%%site.name%%** [%%site.broughtby%%](%%site.broughtbyurl%%)\" tarafından " "hazırlanan anında mesajlaşma ağıdır. " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** bir aninda mesajlaşma sosyal ağıdır." -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4660,43 +4687,43 @@ msgstr "" "licenses/agpl-3.0.html) lisansı ile korunan [StatusNet](http://status.net/) " "microbloglama yazılımının %s. versiyonunu kullanmaktadır." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "Yeni durum mesajı" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 #, fuzzy msgid "After" msgstr "« Sonra" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "Önce »" @@ -5013,80 +5040,85 @@ msgstr "Durum mesajını kaydederken hata oluştu." msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Böyle bir kullanıcı yok." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Bize o profili yollamadınız" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Bize o profili yollamadınız" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Uzaktan abonelik" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Uzaktan abonelik" -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Bize o profili yollamadınız" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Bize o profili yollamadınız" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5772,10 +5804,6 @@ msgstr "Uzak profil eklemede hata oluştu" msgid "Duplicate notice" msgstr "Yeni durum mesajı" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Yeni abonelik eklenemedi." @@ -5962,37 +5990,6 @@ msgstr "Uzaktan abonelik" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -#, fuzzy -msgid "User has blocked you." -msgstr "Kullanıcının profili yok." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Bu kullanıcıyı zaten takip etmiyorsunuz!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Abonelik silinemedi." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Abonelik silinemedi." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/uk/LC_MESSAGES/statusnet.po b/locale/uk/LC_MESSAGES/statusnet.po index 9899d51dbe..3efac8de1a 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:25+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:04:18+0000\n" "Language-Team: Ukrainian\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -103,7 +103,6 @@ msgstr "Немає такої сторінки" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Такого користувача немає." @@ -562,7 +561,7 @@ msgstr "" "на доступ до Вашого акаунту %4$s лише тим стороннім додаткам, яким Ви " "довіряєте." -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "Акаунт" @@ -940,7 +939,7 @@ msgstr "Ви не є власником цього додатку." #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "Виникли певні проблеми з токеном поточної сесії." @@ -1679,7 +1678,7 @@ msgstr "Учасники групи %1$s, сторінка %2$d" msgid "A list of the users in this group." msgstr "Список учасників цієї групи." -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "Адмін" @@ -2066,7 +2065,7 @@ msgstr "Неточне ім’я або пароль." msgid "Error setting user. You are probably not authorized." msgstr "Помилка. Можливо, Ви не авторизовані." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Увійти" @@ -3030,7 +3029,7 @@ msgstr "Даруйте, помилка у коді запрошення." msgid "Registration successful" msgstr "Реєстрація успішна" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Реєстрація" @@ -3928,7 +3927,8 @@ msgstr "Код не введено" msgid "You are not subscribed to that profile." msgstr "Ви не підписані до цього профілю." -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 msgid "Could not save subscription." msgstr "Не вдалося зберегти підписку." @@ -4389,7 +4389,7 @@ msgstr "" msgid "Plugins" msgstr "Додатки" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 msgid "Version" msgstr "Версія" @@ -4450,22 +4450,22 @@ msgstr "Не можна оновити повідомлення з новим UR msgid "DB error inserting hashtag: %s" msgstr "Помилка бази даних при додаванні теґу: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 msgid "Problem saving notice. Too long." msgstr "Проблема при збереженні допису. Надто довге." -#: classes/Notice.php:218 +#: classes/Notice.php:219 msgid "Problem saving notice. Unknown user." msgstr "Проблема при збереженні допису. Невідомий користувач." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" "Дуже багато дописів за короткий термін; ходіть подихайте повітрям і " "повертайтесь за кілька хвилин." -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." @@ -4473,29 +4473,53 @@ msgstr "" "Дуже багато повідомлень за короткий термін; ходіть подихайте повітрям і " "повертайтесь за кілька хвилин." -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "Вам заборонено надсилати дописи до цього сайту." -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Проблема при збереженні допису." -#: classes/Notice.php:790 +#: classes/Notice.php:811 msgid "Problem saving group inbox." msgstr "Проблема при збереженні вхідних дописів для групи." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Помилка бази даних при додаванні відповіді: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "RT @%1$s %2$s" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "Вас позбавлено можливості підписатись." + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "Вже підписаний!" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "Користувач заблокував Вас." + +#: classes/Subscription.php:157 +msgid "Not subscribed!" +msgstr "Не підписано!" + +#: classes/Subscription.php:163 +msgid "Couldn't delete self-subscription." +msgstr "Не можу видалити самопідписку." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Не вдалося видалити підписку." + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "Вітаємо на %1$s, @%2$s!" @@ -4545,124 +4569,124 @@ msgstr "%1$s — %2$s" msgid "Untitled page" msgstr "Сторінка без заголовку" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "Відправна навігація по сайту" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Дім" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "Персональний профіль і стрічка друзів" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "Змінити електронну адресу, аватару, пароль, профіль" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "З’єднання" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect to services" msgstr "З’єднання з сервісами" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "Змінити конфігурацію сайту" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Запросити" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "Запросіть друзів та колег приєднатись до Вас на %s" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Вийти" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "Вийти з сайту" -#: lib/action.php:464 +#: lib/action.php:463 msgid "Create an account" msgstr "Створити новий акаунт" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "Увійти на сайт" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Допомога" -#: lib/action.php:470 +#: lib/action.php:469 msgid "Help me!" msgstr "Допоможіть!" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Пошук" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "Пошук людей або текстів" -#: lib/action.php:494 +#: lib/action.php:493 msgid "Site notice" msgstr "Зауваження сайту" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "Огляд" -#: lib/action.php:626 +#: lib/action.php:625 msgid "Page notice" msgstr "Зауваження сторінки" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "Другорядна навігація по сайту" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Про" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "ЧаПи" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "Умови" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Конфіденційність" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Джерело" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Контакт" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "Бедж" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "Ліцензія програмного забезпечення StatusNet" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4671,12 +4695,12 @@ msgstr "" "**%%site.name%%** — це сервіс мікроблоґів наданий вам [%%site.broughtby%%](%%" "site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** — це сервіс мікроблоґів. " -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4687,42 +4711,42 @@ msgstr "" "для мікроблоґів, версія %s, доступному під [GNU Affero General Public " "License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 msgid "Site content license" msgstr "Ліцензія змісту сайту" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "Зміст і дані %1$s є приватними і конфіденційними." -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "Авторські права на зміст і дані належать %1$s. Всі права захищено." -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" "Авторські права на зміст і дані належать розробникам. Всі права захищено." -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "Всі " -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "ліцензія." -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "Нумерація сторінок" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "Вперед" -#: lib/action.php:1150 +#: lib/action.php:1149 msgid "Before" msgstr "Назад" @@ -5023,84 +5047,89 @@ msgstr "Проблема при збереженні допису." msgid "Specify the name of the user to subscribe to" msgstr "Зазначте ім’я користувача, до якого бажаєте підписатись" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Такого користувача немає." + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "Підписано до %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "Зазначте ім’я користувача, від якого бажаєте відписатись" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "Відписано від %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "Виконання команди ще не завершено." -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "Сповіщення вимкнуто." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "Не можна вимкнути сповіщення." -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "Сповіщення увімкнуто." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "Не можна увімкнути сповіщення." -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "Команду входу відключено" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" "Це посилання можна використати лише раз, воно дійсне протягом 2 хвилин: %s" -#: lib/command.php:668 +#: lib/command.php:681 msgid "You are not subscribed to anyone." msgstr "Ви не маєте жодних підписок." -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Ви підписані до цієї особи:" msgstr[1] "Ви підписані до цих людей:" msgstr[2] "Ви підписані до цих людей:" -#: lib/command.php:690 +#: lib/command.php:703 msgid "No one is subscribed to you." msgstr "До Вас ніхто не підписаний." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Ця особа є підписаною до Вас:" msgstr[1] "Ці люди підписані до Вас:" msgstr[2] "Ці люди підписані до Вас:" -#: lib/command.php:712 +#: lib/command.php:725 msgid "You are not a member of any groups." msgstr "Ви не є учасником жодної групи." -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Ви є учасником групи:" msgstr[1] "Ви є учасником таких груп:" msgstr[2] "Ви є учасником таких груп:" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5881,10 +5910,6 @@ msgstr "Помилка при додаванні віддаленого проф msgid "Duplicate notice" msgstr "Дублікат допису" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "Вас позбавлено можливості підписатись." - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Не вдалося додати нову підписку." @@ -6061,34 +6086,6 @@ msgstr "Люди підписані до %s" msgid "Groups %s is a member of" msgstr "%s бере участь в цих групах" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "Вже підписаний!" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "Користувач заблокував Вас." - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "Невдала підписка." - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "Не вдалося підписати інших до Вас." - -#: lib/subs.php:137 -msgid "Not subscribed!" -msgstr "Не підписано!" - -#: lib/subs.php:142 -msgid "Couldn't delete self-subscription." -msgstr "Не можу видалити самопідписку." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Не вдалося видалити підписку." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/vi/LC_MESSAGES/statusnet.po b/locale/vi/LC_MESSAGES/statusnet.po index dcfb3d7675..34e7f41231 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:29+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:04:21+0000\n" "Language-Team: Vietnamese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -105,7 +105,6 @@ msgstr "Không có tin nhắn nào." #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "Không có user nào." @@ -569,7 +568,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 #, fuzzy msgid "Account" msgstr "Giới thiệu" @@ -966,7 +965,7 @@ msgstr "Bạn chưa cập nhật thông tin riêng" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 #, fuzzy msgid "There was a problem with your session token." msgstr "Có lỗi xảy ra khi thao tác. Hãy thử lại lần nữa." @@ -1771,7 +1770,7 @@ msgstr "Thành viên" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2161,7 +2160,7 @@ msgstr "Sai tên đăng nhập hoặc mật khẩu." msgid "Error setting user. You are probably not authorized." msgstr "Chưa được phép." -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "Đăng nhập" @@ -3148,7 +3147,7 @@ msgstr "Lỗi xảy ra với mã xác nhận." msgid "Registration successful" msgstr "Đăng ký thành công" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "Đăng ký" @@ -4044,7 +4043,8 @@ msgstr "Không có mã nào được nhập" 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 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "Không thể tạo đăng nhận." @@ -4499,7 +4499,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "Cá nhân" @@ -4565,51 +4565,78 @@ msgstr "Không thể cập nhật thông tin user với địa chỉ email đã msgid "DB error inserting hashtag: %s" msgstr "Lỗi cơ sở dữ liệu khi chèn trả lời: %s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "Có lỗi xảy ra khi lưu tin nhắn." -#: classes/Notice.php:218 +#: classes/Notice.php:219 #, fuzzy msgid "Problem saving notice. Unknown user." msgstr "Có lỗi xảy ra khi lưu tin nhắn." -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "Có lỗi xảy ra khi lưu tin nhắn." -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "Có lỗi xảy ra khi lưu tin nhắn." -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "Lỗi cơ sở dữ liệu khi chèn trả lời: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%s (%s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +#, fuzzy +msgid "User has blocked you." +msgstr "Người dùng không có thông tin." + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "Chưa đăng nhận!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "Không thể xóa đăng nhận." + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "Không thể xóa đăng nhận." + +#: classes/User.php:372 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "%s chào mừng bạn " @@ -4664,135 +4691,135 @@ msgstr "%s (%s)" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "Trang chủ" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 #, fuzzy msgid "Change your email, avatar, password, profile" msgstr "Thay đổi mật khẩu của bạn" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "Kết nối" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "Không thể chuyển đến máy chủ: %s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "Tôi theo" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "Thư mời" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, fuzzy, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" "Điền địa chỉ email và nội dung tin nhắn để gửi thư mời bạn bè và đồng nghiệp " "của bạn tham gia vào dịch vụ này." -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "Thoát" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "Tạo tài khoản mới" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "Hướng dẫn" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "Hướng dẫn" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "Tìm kiếm" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "Thông báo mới" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "Thông báo mới" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "Tôi theo" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "Giới thiệu" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "Riêng tư" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "Nguồn" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "Liên hệ" -#: lib/action.php:752 +#: lib/action.php:751 #, fuzzy msgid "Badge" msgstr "Tin đã gửi" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4801,12 +4828,12 @@ msgstr "" "**%%site.name%%** là dịch vụ gửi tin nhắn được cung cấp từ [%%site.broughtby%" "%](%%site.broughtbyurl%%). " -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** là dịch vụ gửi tin nhắn. " -#: lib/action.php:787 +#: lib/action.php:786 #, fuzzy, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4817,43 +4844,43 @@ msgstr "" "quyền [GNU Affero General Public License](http://www.fsf.org/licensing/" "licenses/agpl-3.0.html)." -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "Tìm theo nội dung của tin nhắn" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 #, fuzzy msgid "After" msgstr "Sau" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "Trước" @@ -5176,82 +5203,87 @@ msgstr "Có lỗi xảy ra khi lưu tin nhắn." msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "Không có user nào." + +#: lib/command.php:561 #, fuzzy, php-format msgid "Subscribed to %s" msgstr "Theo nhóm này" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, fuzzy, php-format msgid "Unsubscribed from %s" msgstr "Hết theo" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 #, fuzzy msgid "Notification off." msgstr "Không có mã số xác nhận." -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 #, fuzzy msgid "Notification on." msgstr "Không có mã số xác nhận." -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "Bạn chưa cập nhật thông tin riêng" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "Bạn đã theo những người này:" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "Không thể tạo favorite." -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "Không thể tạo favorite." -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "Bạn chưa cập nhật thông tin riêng" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "Bạn chưa cập nhật thông tin riêng" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -6001,10 +6033,6 @@ msgstr "Lỗi xảy ra khi thêm mới hồ sơ cá nhân" msgid "Duplicate notice" msgstr "Xóa tin nhắn" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "Không thể chèn thêm vào đăng nhận." @@ -6197,39 +6225,6 @@ msgstr "Theo nhóm này" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -#, fuzzy -msgid "User has blocked you." -msgstr "Người dùng không có thông tin." - -#: lib/subs.php:63 -#, fuzzy -msgid "Could not subscribe." -msgstr "Chưa đăng nhận!" - -#: lib/subs.php:82 -#, fuzzy -msgid "Could not subscribe other to you." -msgstr "Không thể tạo favorite." - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "Chưa đăng nhận!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "Không thể xóa đăng nhận." - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "Không thể xóa đăng nhận." - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/zh_CN/LC_MESSAGES/statusnet.po b/locale/zh_CN/LC_MESSAGES/statusnet.po index 038dd64982..838ed646d5 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:32+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:04:24+0000\n" "Language-Team: Simplified Chinese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -107,7 +107,6 @@ msgstr "没有该页面" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "没有这个用户。" @@ -567,7 +566,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 msgid "Account" msgstr "帐号" @@ -962,7 +961,7 @@ msgstr "您未告知此个人信息" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 #, fuzzy msgid "There was a problem with your session token." msgstr "会话标识有问题,请重试。" @@ -1748,7 +1747,7 @@ msgstr "%s 组成员, 第 %d 页" msgid "A list of the users in this group." msgstr "该组成员列表。" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "admin管理员" @@ -2119,7 +2118,7 @@ msgstr "用户名或密码不正确。" msgid "Error setting user. You are probably not authorized." msgstr "未认证。" -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "登录" @@ -3086,7 +3085,7 @@ msgstr "验证码出错。" msgid "Registration successful" msgstr "注册成功。" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "注册" @@ -3973,7 +3972,8 @@ msgstr "没有输入验证码" msgid "You are not subscribed to that profile." msgstr "您未告知此个人信息" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "无法删除订阅。" @@ -4426,7 +4426,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "个人" @@ -4490,52 +4490,80 @@ msgstr "无法添加新URI的信息。" msgid "DB error inserting hashtag: %s" msgstr "添加标签时数据库出错:%s" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "保存通告时出错。" -#: classes/Notice.php:218 +#: classes/Notice.php:219 #, fuzzy msgid "Problem saving notice. Unknown user." msgstr "保存通告时出错。" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "你在短时间里发布了过多的消息,请深呼吸,过几分钟再发消息。" -#: classes/Notice.php:229 +#: classes/Notice.php:230 #, fuzzy msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "你在短时间里发布了过多的消息,请深呼吸,过几分钟再发消息。" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "在这个网站你被禁止发布消息。" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "保存通告时出错。" -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "保存通告时出错。" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "添加回复时数据库出错:%s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, fuzzy, php-format msgid "RT @%1$s %2$s" msgstr "%1$s (%2$s)" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +#, fuzzy +msgid "You have been banned from subscribing." +msgstr "那个用户阻止了你的订阅。" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +#, fuzzy +msgid "User has blocked you." +msgstr "用户没有个人信息。" + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "未订阅!" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "无法删除订阅。" + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "无法删除订阅。" + +#: classes/User.php:372 #, fuzzy, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "发送给 %1$s 的 %2$s 消息" @@ -4587,133 +4615,133 @@ msgstr "%1$s (%2$s)" msgid "Untitled page" msgstr "无标题页" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "主站导航" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "主页" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "个人资料及朋友年表" -#: lib/action.php:442 +#: lib/action.php:441 #, fuzzy msgid "Change your email, avatar, password, profile" msgstr "修改资料" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "连接" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "无法重定向到服务器:%s" -#: lib/action.php:449 +#: lib/action.php:448 #, fuzzy msgid "Change site configuration" msgstr "主站导航" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "邀请" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, fuzzy, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "使用这个表单来邀请好友和同事加入。" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "登出" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "登出本站" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "创建新帐号" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "登入本站" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "帮助" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "帮助" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "搜索" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "检索人或文字" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "新通告" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "本地显示" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "新通告" -#: lib/action.php:728 +#: lib/action.php:727 #, fuzzy msgid "Secondary site navigation" msgstr "次项站导航" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "关于" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "常见问题FAQ" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "隐私" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "来源" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "联系人" -#: lib/action.php:752 +#: lib/action.php:751 #, fuzzy msgid "Badge" msgstr "呼叫" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "StatusNet软件注册证" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4722,12 +4750,12 @@ msgstr "" "**%%site.name%%** 是一个微博客服务,提供者为 [%%site.broughtby%%](%%site." "broughtbyurl%%)。" -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%** 是一个微博客服务。" -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4738,43 +4766,43 @@ msgstr "" "General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)" "授权。" -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "StatusNet软件注册证" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "全部" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "注册证" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "分页" -#: lib/action.php:1142 +#: lib/action.php:1141 #, fuzzy msgid "After" msgstr "« 之后" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "之前 »" @@ -5093,80 +5121,85 @@ msgstr "保存通告时出错。" msgid "Specify the name of the user to subscribe to" msgstr "指定要订阅的用户名" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "没有这个用户。" + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "订阅 %s" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "指定要取消订阅的用户名" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "取消订阅 %s" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "命令尚未实现。" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "通告关闭。" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "无法关闭通告。" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "通告开启。" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "无法开启通告。" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "您未告知此个人信息" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "您已订阅这些用户:" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "无法订阅他人更新。" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "无法订阅他人更新。" -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "您未告知此个人信息" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "您未告知此个人信息" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5867,11 +5900,6 @@ msgstr "添加远程的个人信息出错" msgid "Duplicate notice" msgstr "删除通告" -#: lib/oauthstore.php:465 lib/subs.php:48 -#, fuzzy -msgid "You have been banned from subscribing." -msgstr "那个用户阻止了你的订阅。" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "无法添加新的订阅。" @@ -6063,37 +6091,6 @@ msgstr "订阅 %s" msgid "Groups %s is a member of" msgstr "%s 组是成员组成了" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -#, fuzzy -msgid "User has blocked you." -msgstr "用户没有个人信息。" - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "无法订阅。" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "无法订阅他人更新。" - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "未订阅!" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "无法删除订阅。" - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "无法删除订阅。" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" diff --git a/locale/zh_TW/LC_MESSAGES/statusnet.po b/locale/zh_TW/LC_MESSAGES/statusnet.po index e6996e1524..be69293d2b 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-02-18 22:55+0000\n" -"PO-Revision-Date: 2010-02-18 22:57:35+0000\n" +"POT-Creation-Date: 2010-02-21 23:02+0000\n" +"PO-Revision-Date: 2010-02-21 23:04:27+0000\n" "Language-Team: Traditional Chinese\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: MediaWiki 1.16alpha (r62678); Translate extension (2010-01-16)\n" +"X-Generator: MediaWiki 1.16alpha (r62792); 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" @@ -103,7 +103,6 @@ msgstr "無此通知" #: lib/command.php:163 lib/command.php:302 lib/command.php:355 #: lib/command.php:401 lib/command.php:462 lib/command.php:518 #: lib/galleryaction.php:59 lib/mailbox.php:82 lib/profileaction.php:77 -#: lib/subs.php:34 lib/subs.php:125 msgid "No such user." msgstr "無此使用者" @@ -559,7 +558,7 @@ msgid "" "give access to your %4$s account to third parties you trust." msgstr "" -#: actions/apioauthauthorize.php:310 lib/action.php:442 +#: actions/apioauthauthorize.php:310 lib/action.php:441 #, fuzzy msgid "Account" msgstr "關於" @@ -952,7 +951,7 @@ msgstr "無法連結到伺服器:%s" #: actions/deleteapplication.php:102 actions/editapplication.php:127 #: actions/newapplication.php:110 actions/showapplication.php:118 -#: lib/action.php:1198 +#: lib/action.php:1197 msgid "There was a problem with your session token." msgstr "" @@ -1710,7 +1709,7 @@ msgstr "" msgid "A list of the users in this group." msgstr "" -#: actions/groupmembers.php:175 lib/action.php:449 lib/groupnav.php:107 +#: actions/groupmembers.php:175 lib/action.php:448 lib/groupnav.php:107 msgid "Admin" msgstr "" @@ -2048,7 +2047,7 @@ msgstr "使用者名稱或密碼錯誤" msgid "Error setting user. You are probably not authorized." msgstr "" -#: actions/login.php:188 actions/login.php:241 lib/action.php:467 +#: actions/login.php:188 actions/login.php:241 lib/action.php:466 #: lib/logingroupnav.php:79 msgid "Login" msgstr "登入" @@ -2989,7 +2988,7 @@ msgstr "確認碼發生錯誤" msgid "Registration successful" msgstr "" -#: actions/register.php:114 actions/register.php:503 lib/action.php:464 +#: actions/register.php:114 actions/register.php:503 lib/action.php:463 #: lib/logingroupnav.php:85 msgid "Register" msgstr "" @@ -3836,7 +3835,8 @@ msgstr "" msgid "You are not subscribed to that profile." msgstr "" -#: actions/subedit.php:83 +#: actions/subedit.php:83 classes/Subscription.php:89 +#: classes/Subscription.php:116 #, fuzzy msgid "Could not save subscription." msgstr "註冊失敗" @@ -4272,7 +4272,7 @@ msgstr "" msgid "Plugins" msgstr "" -#: actions/version.php:196 lib/action.php:748 +#: actions/version.php:196 lib/action.php:747 #, fuzzy msgid "Version" msgstr "地點" @@ -4335,51 +4335,77 @@ msgstr "" msgid "DB error inserting hashtag: %s" msgstr "" -#: classes/Notice.php:214 +#: classes/Notice.php:215 #, fuzzy msgid "Problem saving notice. Too long." msgstr "儲存使用者發生錯誤" -#: classes/Notice.php:218 +#: classes/Notice.php:219 #, fuzzy msgid "Problem saving notice. Unknown user." msgstr "儲存使用者發生錯誤" -#: classes/Notice.php:223 +#: classes/Notice.php:224 msgid "" "Too many notices too fast; take a breather and post again in a few minutes." msgstr "" -#: classes/Notice.php:229 +#: classes/Notice.php:230 msgid "" "Too many duplicate messages too quickly; take a breather and post again in a " "few minutes." msgstr "" -#: classes/Notice.php:235 +#: classes/Notice.php:236 msgid "You are banned from posting notices on this site." msgstr "" -#: classes/Notice.php:294 classes/Notice.php:320 +#: classes/Notice.php:302 classes/Notice.php:328 msgid "Problem saving notice." msgstr "" -#: classes/Notice.php:790 +#: classes/Notice.php:811 #, fuzzy msgid "Problem saving group inbox." msgstr "儲存使用者發生錯誤" -#: classes/Notice.php:850 +#: classes/Notice.php:871 #, php-format msgid "DB error inserting reply: %s" msgstr "增加回覆時,資料庫發生錯誤: %s" -#: classes/Notice.php:1274 +#: classes/Notice.php:1328 #, php-format msgid "RT @%1$s %2$s" msgstr "" -#: classes/User.php:385 +#: classes/Subscription.php:66 lib/oauthstore.php:465 +msgid "You have been banned from subscribing." +msgstr "" + +#: classes/Subscription.php:70 +msgid "Already subscribed!" +msgstr "" + +#: classes/Subscription.php:74 +msgid "User has blocked you." +msgstr "" + +#: classes/Subscription.php:157 +#, fuzzy +msgid "Not subscribed!" +msgstr "此帳號已註冊" + +#: classes/Subscription.php:163 +#, fuzzy +msgid "Couldn't delete self-subscription." +msgstr "無法刪除帳號" + +#: classes/Subscription.php:179 +msgid "Couldn't delete subscription." +msgstr "無法刪除帳號" + +#: classes/User.php:372 #, php-format msgid "Welcome to %1$s, @%2$s!" msgstr "" @@ -4433,129 +4459,129 @@ msgstr "%1$s的狀態是%2$s" msgid "Untitled page" msgstr "" -#: lib/action.php:434 +#: lib/action.php:433 msgid "Primary site navigation" msgstr "" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Home" msgstr "主頁" -#: lib/action.php:440 +#: lib/action.php:439 msgid "Personal profile and friends timeline" msgstr "" -#: lib/action.php:442 +#: lib/action.php:441 msgid "Change your email, avatar, password, profile" msgstr "" -#: lib/action.php:445 +#: lib/action.php:444 msgid "Connect" msgstr "連結" -#: lib/action.php:445 +#: lib/action.php:444 #, fuzzy msgid "Connect to services" msgstr "無法連結到伺服器:%s" -#: lib/action.php:449 +#: lib/action.php:448 msgid "Change site configuration" msgstr "" -#: lib/action.php:453 lib/subgroupnav.php:105 +#: lib/action.php:452 lib/subgroupnav.php:105 msgid "Invite" msgstr "" -#: lib/action.php:454 lib/subgroupnav.php:106 +#: lib/action.php:453 lib/subgroupnav.php:106 #, php-format msgid "Invite friends and colleagues to join you on %s" msgstr "" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout" msgstr "登出" -#: lib/action.php:459 +#: lib/action.php:458 msgid "Logout from the site" msgstr "" -#: lib/action.php:464 +#: lib/action.php:463 #, fuzzy msgid "Create an account" msgstr "新增帳號" -#: lib/action.php:467 +#: lib/action.php:466 msgid "Login to the site" msgstr "" -#: lib/action.php:470 lib/action.php:733 +#: lib/action.php:469 lib/action.php:732 msgid "Help" msgstr "求救" -#: lib/action.php:470 +#: lib/action.php:469 #, fuzzy msgid "Help me!" msgstr "求救" -#: lib/action.php:473 lib/searchaction.php:127 +#: lib/action.php:472 lib/searchaction.php:127 msgid "Search" msgstr "" -#: lib/action.php:473 +#: lib/action.php:472 msgid "Search for people or text" msgstr "" -#: lib/action.php:494 +#: lib/action.php:493 #, fuzzy msgid "Site notice" msgstr "新訊息" -#: lib/action.php:560 +#: lib/action.php:559 msgid "Local views" msgstr "" -#: lib/action.php:626 +#: lib/action.php:625 #, fuzzy msgid "Page notice" msgstr "新訊息" -#: lib/action.php:728 +#: lib/action.php:727 msgid "Secondary site navigation" msgstr "" -#: lib/action.php:735 +#: lib/action.php:734 msgid "About" msgstr "關於" -#: lib/action.php:737 +#: lib/action.php:736 msgid "FAQ" msgstr "常見問題" -#: lib/action.php:741 +#: lib/action.php:740 msgid "TOS" msgstr "" -#: lib/action.php:744 +#: lib/action.php:743 msgid "Privacy" msgstr "" -#: lib/action.php:746 +#: lib/action.php:745 msgid "Source" msgstr "" -#: lib/action.php:750 +#: lib/action.php:749 msgid "Contact" msgstr "好友名單" -#: lib/action.php:752 +#: lib/action.php:751 msgid "Badge" msgstr "" -#: lib/action.php:780 +#: lib/action.php:779 msgid "StatusNet software license" msgstr "" -#: lib/action.php:783 +#: lib/action.php:782 #, php-format msgid "" "**%%site.name%%** is a microblogging service brought to you by [%%site." @@ -4564,12 +4590,12 @@ msgstr "" "**%%site.name%%**是由[%%site.broughtby%%](%%site.broughtbyurl%%)所提供的微型" "部落格服務" -#: lib/action.php:785 +#: lib/action.php:784 #, php-format msgid "**%%site.name%%** is a microblogging service. " msgstr "**%%site.name%%**是個微型部落格" -#: lib/action.php:787 +#: lib/action.php:786 #, php-format msgid "" "It runs the [StatusNet](http://status.net/) microblogging software, version %" @@ -4577,42 +4603,42 @@ msgid "" "org/licensing/licenses/agpl-3.0.html)." msgstr "" -#: lib/action.php:802 +#: lib/action.php:801 #, fuzzy msgid "Site content license" msgstr "新訊息" -#: lib/action.php:807 +#: lib/action.php:806 #, php-format msgid "Content and data of %1$s are private and confidential." msgstr "" -#: lib/action.php:812 +#: lib/action.php:811 #, php-format msgid "Content and data copyright by %1$s. All rights reserved." msgstr "" -#: lib/action.php:815 +#: lib/action.php:814 msgid "Content and data copyright by contributors. All rights reserved." msgstr "" -#: lib/action.php:828 +#: lib/action.php:827 msgid "All " msgstr "" -#: lib/action.php:834 +#: lib/action.php:833 msgid "license." msgstr "" -#: lib/action.php:1133 +#: lib/action.php:1132 msgid "Pagination" msgstr "" -#: lib/action.php:1142 +#: lib/action.php:1141 msgid "After" msgstr "" -#: lib/action.php:1150 +#: lib/action.php:1149 #, fuzzy msgid "Before" msgstr "之前的內容»" @@ -4919,80 +4945,85 @@ msgstr "儲存使用者發生錯誤" msgid "Specify the name of the user to subscribe to" msgstr "" -#: lib/command.php:554 +#: lib/command.php:554 lib/command.php:589 +#, fuzzy +msgid "No such user" +msgstr "無此使用者" + +#: lib/command.php:561 #, php-format msgid "Subscribed to %s" msgstr "" -#: lib/command.php:575 +#: lib/command.php:582 msgid "Specify the name of the user to unsubscribe from" msgstr "" -#: lib/command.php:582 +#: lib/command.php:595 #, php-format msgid "Unsubscribed from %s" msgstr "" -#: lib/command.php:600 lib/command.php:623 +#: lib/command.php:613 lib/command.php:636 msgid "Command not yet implemented." msgstr "" -#: lib/command.php:603 +#: lib/command.php:616 msgid "Notification off." msgstr "" -#: lib/command.php:605 +#: lib/command.php:618 msgid "Can't turn off notification." msgstr "" -#: lib/command.php:626 +#: lib/command.php:639 msgid "Notification on." msgstr "" -#: lib/command.php:628 +#: lib/command.php:641 msgid "Can't turn on notification." msgstr "" -#: lib/command.php:641 +#: lib/command.php:654 msgid "Login command is disabled" msgstr "" -#: lib/command.php:652 +#: lib/command.php:665 #, php-format msgid "This link is useable only once, and is good for only 2 minutes: %s" msgstr "" -#: lib/command.php:668 +#: lib/command.php:681 #, fuzzy msgid "You are not subscribed to anyone." msgstr "此帳號已註冊" -#: lib/command.php:670 +#: lib/command.php:683 msgid "You are subscribed to this person:" msgid_plural "You are subscribed to these people:" msgstr[0] "此帳號已註冊" -#: lib/command.php:690 +#: lib/command.php:703 #, fuzzy msgid "No one is subscribed to you." msgstr "無此訂閱" -#: lib/command.php:692 +#: lib/command.php:705 msgid "This person is subscribed to you:" msgid_plural "These people are subscribed to you:" msgstr[0] "無此訂閱" -#: lib/command.php:712 +#: lib/command.php:725 #, fuzzy msgid "You are not a member of any groups." msgstr "無法連結到伺服器:%s" -#: lib/command.php:714 +#: lib/command.php:727 msgid "You are a member of this group:" msgid_plural "You are a member of these groups:" msgstr[0] "無法連結到伺服器:%s" -#: lib/command.php:728 +#: lib/command.php:741 msgid "" "Commands:\n" "on - turn on notifications\n" @@ -5671,10 +5702,6 @@ msgstr "新增外部個人資料發生錯誤(Error inserting remote profile)" msgid "Duplicate notice" msgstr "新訊息" -#: lib/oauthstore.php:465 lib/subs.php:48 -msgid "You have been banned from subscribing." -msgstr "" - #: lib/oauthstore.php:490 msgid "Couldn't insert new subscription." msgstr "無法新增訂閱" @@ -5858,36 +5885,6 @@ msgstr "此帳號已註冊" msgid "Groups %s is a member of" msgstr "" -#: lib/subs.php:52 -msgid "Already subscribed!" -msgstr "" - -#: lib/subs.php:56 -msgid "User has blocked you." -msgstr "" - -#: lib/subs.php:63 -msgid "Could not subscribe." -msgstr "" - -#: lib/subs.php:82 -msgid "Could not subscribe other to you." -msgstr "" - -#: lib/subs.php:137 -#, fuzzy -msgid "Not subscribed!" -msgstr "此帳號已註冊" - -#: lib/subs.php:142 -#, fuzzy -msgid "Couldn't delete self-subscription." -msgstr "無法刪除帳號" - -#: lib/subs.php:158 -msgid "Couldn't delete subscription." -msgstr "無法刪除帳號" - #: lib/subscriberspeopleselftagcloudsection.php:48 #: lib/subscriptionspeopleselftagcloudsection.php:48 msgid "People Tagcloud as self-tagged" From f6ebe815382a61574df5f9452ee9a0ea4ae38f0c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 15:21:18 -0800 Subject: [PATCH 100/190] Performance fix for FriendFeed sup interface: MySQL query optimizer was doing a table scan on notice; explicit subquery makes it run much more efficiently, only scanning items within the period under consideration. Standard subquery should be PostgreSQL-compatible. --- actions/sup.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/actions/sup.php b/actions/sup.php index 5daf0a1c1d..4e428dfa58 100644 --- a/actions/sup.php +++ b/actions/sup.php @@ -66,10 +66,12 @@ class SupAction extends Action $divider = common_sql_date(time() - $seconds); $notice->query('SELECT profile_id, max(id) AS max_id ' . - 'FROM notice ' . + 'FROM ( ' . + 'SELECT profile_id, id FROM notice ' . ((common_config('db','type') == 'pgsql') ? 'WHERE extract(epoch from created) > (extract(epoch from now()) - ' . $seconds . ') ' : 'WHERE created > "'.$divider.'" ' ) . + ') AS latest ' . 'GROUP BY profile_id'); $updates = array(); From fde64ddf2688fa0bd78e3d59f4003c3392fe2d30 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 21:36:36 -0500 Subject: [PATCH 101/190] make some of the Webfinger magic strings constants --- plugins/OStatus/lib/webfinger.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/OStatus/lib/webfinger.php b/plugins/OStatus/lib/webfinger.php index 417d54904b..0386881d14 100644 --- a/plugins/OStatus/lib/webfinger.php +++ b/plugins/OStatus/lib/webfinger.php @@ -32,11 +32,16 @@ define('WEBFINGER_SERVICE_REL_VALUE', 'lrdd'); /** * Implement the webfinger protocol. */ + class Webfinger { + const PROFILEPAGE = 'http://webfinger.net/rel/profile-page'; + const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from'; + /** * Perform a webfinger lookup given an account. - */ + */ + public function lookup($id) { $id = $this->normalize($id); @@ -46,7 +51,7 @@ class Webfinger if (!$links) { return false; } - + $services = array(); foreach ($links as $link) { if ($link['template']) { @@ -64,7 +69,7 @@ class Webfinger function normalize($id) { if (substr($id, 0, 7) == 'acct://') { - return substr($id, 7); + return substr($id, 7); } else if (substr($id, 0, 5) == 'acct:') { return substr($id, 5); } @@ -86,7 +91,7 @@ class Webfinger if ($result->host != $domain) { return false; } - + $links = array(); foreach ($result->links as $link) { if ($link['rel'] == WEBFINGER_SERVICE_REL_VALUE) { @@ -140,4 +145,3 @@ class Webfinger } } - From bf23c35495bf713ec662649b2e8964e90da93239 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 21:37:12 -0500 Subject: [PATCH 102/190] Add OStatus_profile::ensureWebfinger() --- plugins/OStatus/classes/Ostatus_profile.php | 103 ++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index b67e202026..700168c118 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -845,4 +845,107 @@ class Ostatus_profile extends Memcached_DataObject return null; } } + + public static function ensureWebfinger($addr) + { + // First, look it up + + $oprofile = Ostatus_profile::staticGet('uri', 'acct:'.$addr); + + if (!empty($oprofile)) { + return $oprofile; + } + + // Now, try some discovery + + $wf = new Webfinger(); + + $result = $wf->lookup($addr); + + if (!$result) { + return null; + } + + foreach ($result->links as $link) { + switch ($link['rel']) { + case Webfinger::PROFILEPAGE: + $profileUrl = $link['href']; + break; + case 'salmon': + $salmonEndpoint = $link['href']; + break; + case Webfinger::UPDATESFROM: + $feedUrl = $link['href']; + break; + default: + common_log(LOG_NOTICE, "Don't know what to do with rel = '{$link['rel']}'"); + break; + } + } + + // If we got a feed URL, try that + + if (isset($feedUrl)) { + try { + $oprofile = self::ensureProfile($feedUrl); + return $oprofile; + } catch (Exception $e) { + common_log(LOG_WARNING, "Failed creating profile from feed URL '$feedUrl': " . $e->getMessage()); + // keep looking + } + } + + // If we got a profile page, try that! + + if (isset($profileUrl)) { + try { + $oprofile = self::ensureProfile($profileUrl); + return $oprofile; + } catch (Exception $e) { + common_log(LOG_WARNING, "Failed creating profile from profile URL '$profileUrl': " . $e->getMessage()); + // keep looking + } + } + + // XXX: try hcard + // XXX: try FOAF + + if (isset($salmonEndpoint)) { + + // An account URL, a salmon endpoint, and a dream? Not much to go + // on, but let's give it a try + + $uri = 'acct:'.$addr; + + $profile = new Profile(); + + $profile->nickname = self::nicknameFromUri($uri); + $profile->created = common_sql_now(); + + $profile_id = $profile->insert(); + + if (!$profile_id) { + common_log_db_error($profile, 'INSERT', __FILE__); + throw new Exception("Couldn't save profile for '$addr'"); + } + + $oprofile = new Ostatus_profile(); + + $oprofile->uri = $uri; + $oprofile->salmonuri = $salmonEndpoint; + $oprofile->profile_id = $profile_id; + $oprofile->created = common_sql_now(); + + $result = $oprofile->insert(); + + if (!$result) { + common_log_db_error($oprofile, 'INSERT', __FILE__); + throw new Exception("Couldn't save ostatus_profile for '$addr'"); + } + + return $oprofile; + } + + return null; + } } From bd74f05a665df73078134c37f059cc1797d1a0ea Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 21:38:16 -0500 Subject: [PATCH 103/190] Do mention lookup for Webfinger accounts in OStatusPlugin --- plugins/OStatus/OStatusPlugin.php | 79 +++++++++++++++---------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index c5a2db3d84..60bb144a83 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -136,25 +136,6 @@ class OStatusPlugin extends Plugin return true; } - /** - * Add the feed settings page to the Connect Settings menu - * - * @param Action &$action The calling page - * - * @return boolean hook return - */ - function onEndConnectSettingsNav(&$action) - { - $action_name = $action->trimmed('action'); - - $action->menuItem(common_local_url('feedsubsettings'), - _m('Feeds'), - _m('Feed subscription options'), - $action_name === 'feedsubsettings'); - - return true; - } - /** * Automatically load the actions and libraries used by the plugin * @@ -215,33 +196,16 @@ class OStatusPlugin extends Plugin * @fixme push webfinger lookup & sending to a background queue * @fixme also detect short-form name for remote subscribees where not ambiguous */ + function onEndNoticeSave($notice) { - $count = preg_match_all('/(\w+\.)*\w+@(\w+\.)*\w+(\w+\-\w+)*\.\w+/', $notice->content, $matches); - if ($count) { - foreach ($matches[0] as $webfinger) { + $mentioned = $notice->getReplies(); - // FIXME: look up locally first + foreach ($mentioned as $profile) { - // Check to see if we've got an actual webfinger - $w = new Webfinger; + $oprofile = Ostatus_profile::staticGet('profile_id', $profile->id); - $endpoint_uri = ''; - - $result = $w->lookup($webfinger); - if (empty($result)) { - continue; - } - - foreach ($result->links as $link) { - if ($link['rel'] == 'salmon') { - $endpoint_uri = $link['href']; - } - } - - if (empty($endpoint_uri)) { - continue; - } + if (!empty($oprofile) && !empty($oprofile->salmonuri)) { // FIXME: this needs to go out in a queue handler @@ -249,11 +213,42 @@ class OStatusPlugin extends Plugin $xml .= $notice->asAtomEntry(); $salmon = new Salmon(); - $salmon->post($endpoint_uri, $xml); + $salmon->post($oprofile->salmonuri, $xml); } } } + /** + * + */ + + function onEndFindMentions($sender, $text, &$mentions) + { + preg_match_all('/(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)/', + $text, + $wmatches, + PREG_OFFSET_CAPTURE); + + foreach ($wmatches[1] as $wmatch) { + + $webfinger = $wmatch[0]; + + $oprofile = Ostatus_profile::ensureWebfinger($webfinger); + + if (!empty($oprofile)) { + + $profile = $oprofile->localProfile(); + + $mentions[] = array('mentioned' => array($profile), + 'text' => $wmatch[0], + 'position' => $wmatch[1], + 'url' => $profile->profileurl); + } + } + + return true; + } + /** * Notify remote server and garbage collect unused feeds on unsubscribe. * @fixme send these operations to background queues From 912814fb7f3580e6925b5fae7092966df9bf3aab Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 21:38:59 -0500 Subject: [PATCH 104/190] use some constants and do some extra output in webfinger output --- plugins/OStatus/actions/webfinger.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php index f4dc61b7d1..cf60b8069d 100644 --- a/plugins/OStatus/actions/webfinger.php +++ b/plugins/OStatus/actions/webfinger.php @@ -37,7 +37,7 @@ class WebfingerAction extends Action return true; } - + function handle() { $acct = Webfinger::normalize($this->uri); @@ -55,16 +55,22 @@ class WebfingerAction extends Action $xrd->subject = $this->uri; $xrd->alias[] = common_profile_url($nick); - $xrd->links[] = array('rel' => 'http://webfinger.net/rel/profile-page', + $xrd->links[] = array('rel' => Webfinger::PROFILEPAGE, 'type' => 'text/html', 'href' => common_profile_url($nick)); + $xrd->links[] = array('rel' => Webfinger::UPDATESFROM, + 'href' => common_local_url('ApiTimelineUser', + array('id' => $this->user->id, + 'format' => 'atom')), + 'type' => 'application/atom+xml'); + $salmon_url = common_local_url('salmon', array('id' => $this->user->id)); $xrd->links[] = array('rel' => 'salmon', 'href' => $salmon_url); - + // TODO - finalize where the redirect should go on the publisher $url = common_local_url('ostatussub') . '?profile={uri}'; $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe', From 78ca45c7a05dea911c58097a8c57be470dafee01 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 14:46:26 -0800 Subject: [PATCH 105/190] OStatus PuSH fixes: - hub now defers subscription state updates until after verification, per spec - hub now supports synchronous verification when requested (if async is not requested after) - client now requests synchronous verification (it's a bit safer) - cleanup on subscription logging/error responses --- plugins/OStatus/actions/pushcallback.php | 38 +++--- plugins/OStatus/actions/pushhub.php | 151 +++++++++++++---------- plugins/OStatus/classes/FeedSub.php | 11 +- plugins/OStatus/classes/HubSub.php | 125 +++++++++++-------- 4 files changed, 185 insertions(+), 140 deletions(-) diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index 35c92c7323..4184f0e0c0 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -72,7 +72,7 @@ class PushCallbackAction extends Action } /** - * Handler for GET verification requests from the hub + * Handler for GET verification requests from the hub. */ function handleGet() { @@ -81,31 +81,37 @@ class PushCallbackAction extends Action $challenge = $this->arg('hub_challenge'); $lease_seconds = $this->arg('hub_lease_seconds'); $verify_token = $this->arg('hub_verify_token'); - + if ($mode != 'subscribe' && $mode != 'unsubscribe') { - common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with mode \"$mode\""); - throw new ServerException("Bogus hub callback: bad mode", 404); + throw new ClientException("Bad hub.mode $mode", 404); } - + $feedsub = FeedSub::staticGet('uri', $topic); if (!$feedsub) { - common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback for unknown feed $topic"); - throw new ServerException("Bogus hub callback: unknown feed", 404); + throw new ClientException("Bad hub.topic feed $topic", 404); } if ($feedsub->verify_token !== $verify_token) { - common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad token \"$verify_token\" for feed $topic"); - throw new ServerException("Bogus hub callback: bad token", 404); + throw new ClientException("Bad hub.verify_token $token for $topic", 404); } - if ($mode != $feedsub->sub_state) { - common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad mode \"$mode\" for feed $topic in state \"{$feedsub->sub_state}\""); - throw new ServerException("Bogus hub callback: mode doesn't match subscription state.", 404); - } - - // OK! if ($mode == 'subscribe') { - common_log(LOG_INFO, __METHOD__ . ': sub confirmed'); + // We may get re-sub requests legitimately. + if ($feedsub->sub_state != 'subscribe' && $feedsub->sub_state != 'active') { + throw new ClientException("Unexpected subscribe request for $topic.", 404); + } + } else { + if ($feedsub->sub_state != 'unsubscribe') { + throw new ClientException("Unexpected unsubscribe request for $topic.", 404); + } + } + + if ($mode == 'subscribe') { + if ($feedsub->sub_state == 'active') { + common_log(LOG_INFO, __METHOD__ . ': sub update confirmed'); + } else { + common_log(LOG_INFO, __METHOD__ . ': sub confirmed'); + } $feedsub->confirmSubscribe($lease_seconds); } else { common_log(LOG_INFO, __METHOD__ . ": unsub confirmed; deleting sub record for $topic"); diff --git a/plugins/OStatus/actions/pushhub.php b/plugins/OStatus/actions/pushhub.php index 19599d815f..f33690bc49 100644 --- a/plugins/OStatus/actions/pushhub.php +++ b/plugins/OStatus/actions/pushhub.php @@ -59,102 +59,121 @@ class PushHubAction extends Action $mode = $this->trimmed('hub.mode'); switch ($mode) { case "subscribe": - $this->subscribe(); - break; case "unsubscribe": - $this->unsubscribe(); + $this->subunsub($mode); break; case "publish": - throw new ServerException("Publishing outside feeds not supported.", 400); + throw new ClientException("Publishing outside feeds not supported.", 400); default: - throw new ServerException("Unrecognized mode '$mode'.", 400); + throw new ClientException("Unrecognized mode '$mode'.", 400); } } /** - * Process a PuSH feed subscription request. + * Process a request for a new or modified PuSH feed subscription. + * If asynchronous verification is requested, updates won't be saved immediately. * * HTTP return codes: * 202 Accepted - request saved and awaiting verification * 204 No Content - already subscribed - * 403 Forbidden - rejecting this (not specifically spec'd) + * 400 Bad Request - rejecting this (not specifically spec'd) */ - function subscribe() + function subunsub($mode) { - $feed = $this->argUrl('hub.topic'); $callback = $this->argUrl('hub.callback'); + + $topic = $this->argUrl('hub.topic'); + if (!$this->recognizedFeed($topic)) { + throw new ClientException("Unsupported hub.topic $topic; this hub only serves local user and group Atom feeds."); + } + + $verify = $this->arg('hub.verify'); // @fixme may be multiple + if ($verify != 'sync' && $verify != 'async') { + throw new ClientException("Invalid hub.verify $verify; must be sync or async."); + } + + $lease = $this->arg('hub.lease_seconds', null); + if ($mode == 'subscribe' && $lease != '' && !preg_match('/^\d+$/', $lease)) { + throw new ClientException("Invalid hub.lease $lease; must be empty or positive integer."); + } + $token = $this->arg('hub.verify_token', null); - common_log(LOG_DEBUG, __METHOD__ . ": checking sub'd to $feed $callback"); - if ($this->getSub($feed, $callback)) { - // Already subscribed; return 204 per spec. + $secret = $this->arg('hub.secret', null); + if ($secret != '' && strlen($secret) >= 200) { + throw new ClientException("Invalid hub.secret $secret; must be under 200 bytes."); + } + + $sub = HubSub::staticGet($sub->topic, $sub->callback); + if (!$sub) { + // Creating a new one! + $sub = new HubSub(); + $sub->topic = $topic; + $sub->callback = $callback; + } + if ($mode == 'subscribe') { + if ($secret) { + $sub->secret = $secret; + } + if ($lease) { + $sub->setLease(intval($lease)); + } + } + + if (!common_config('queue', 'enabled')) { + // Won't be able to background it. + $verify = 'sync'; + } + if ($verify == 'async') { + $sub->scheduleVerify($mode, $token); + header('HTTP/1.1 202 Accepted'); + } else { + $sub->verify($mode, $token); header('HTTP/1.1 204 No Content'); - common_log(LOG_DEBUG, __METHOD__ . ': already subscribed'); - return; } - - common_log(LOG_DEBUG, __METHOD__ . ': setting up'); - $sub = new HubSub(); - $sub->topic = $feed; - $sub->callback = $callback; - $sub->secret = $this->arg('hub.secret', null); - if (strlen($sub->secret) > 200) { - throw new ClientException("hub.secret must be no longer than 200 chars", 400); - } - $sub->setLease(intval($this->arg('hub.lease_seconds'))); - - // @fixme check for feeds we don't manage - // @fixme check the verification mode, might want a return immediately? - - common_log(LOG_DEBUG, __METHOD__ . ': inserting'); - $ok = $sub->insert(); - - if (!$ok) { - throw new ServerException("Failed to save subscription record", 500); - } - - // @fixme check errors ;) - - $data = array('sub' => $sub, 'mode' => 'subscribe', 'token' => $token); - $qm = QueueManager::get(); - $qm->enqueue($data, 'hubverify'); - - header('HTTP/1.1 202 Accepted'); - common_log(LOG_DEBUG, __METHOD__ . ': done'); } /** - * Process a PuSH feed unsubscription request. + * Check whether the given URL represents one of our canonical + * user or group Atom feeds. * - * HTTP return codes: - * 202 Accepted - request saved and awaiting verification - * 204 No Content - already subscribed - * 400 Bad Request - invalid params or rejected feed - * - * @fixme background this + * @param string $feed URL + * @return boolean true if it matches */ - function unsubscribe() + function recognizedFeed($feed) { - $feed = $this->argUrl('hub.topic'); - $callback = $this->argUrl('hub.callback'); - $sub = $this->getSub($feed, $callback); - - if ($sub) { - $token = $this->arg('hub.verify_token', null); - if ($sub->verify('unsubscribe', $token)) { - $sub->delete(); - common_log(LOG_INFO, "PuSH unsubscribed $feed for $callback"); - } else { - throw new ServerException("Failed PuSH unsubscription: verification failed! $feed for $callback"); + $matches = array(); + if (preg_match('!/(\d+)\.atom$!', $feed, $matches)) { + $id = $matches[1]; + $params = array('id' => $id, 'format' => 'atom'); + $userFeed = common_local_url('ApiTimelineUser', $params); + $groupFeed = common_local_url('ApiTimelineGroup', $params); + + if ($feed == $userFeed) { + $user = User::staticGet('id', $id); + if (!$user) { + throw new ClientException("Invalid hub.topic $feed; user doesn't exist."); + } else { + return true; + } } - } else { - throw new ServerException("Failed PuSH unsubscription: not subscribed! $feed for $callback"); + if ($feed == $groupFeed) { + $user = User_group::staticGet('id', $id); + if (!$user) { + throw new ClientException("Invalid hub.topic $feed; group doesn't exist."); + } else { + return true; + } + } + common_log(LOG_DEBUG, "Not a user or group feed? $feed $userFeed $groupFeed"); } + common_log(LOG_DEBUG, "LOST $feed"); + return false; } /** * Grab and validate a URL from POST parameters. - * @throws ServerException for malformed or non-http/https URLs + * @throws ClientException for malformed or non-http/https URLs */ protected function argUrl($arg) { @@ -164,7 +183,7 @@ class PushHubAction extends Action if (Validate::uri($url, $params)) { return $url; } else { - throw new ServerException("Invalid URL passed for $arg: '$url'", 400); + throw new ClientException("Invalid URL passed for $arg: '$url'"); } } diff --git a/plugins/OStatus/classes/FeedSub.php b/plugins/OStatus/classes/FeedSub.php index 31241d3de7..b848b6b1d3 100644 --- a/plugins/OStatus/classes/FeedSub.php +++ b/plugins/OStatus/classes/FeedSub.php @@ -291,10 +291,9 @@ class FeedSub extends Memcached_DataObject $headers = array('Content-Type: application/x-www-form-urlencoded'); $post = array('hub.mode' => $mode, 'hub.callback' => $callback, - 'hub.verify' => 'async', + 'hub.verify' => 'sync', 'hub.verify_token' => $this->verify_token, 'hub.secret' => $this->secret, - //'hub.lease_seconds' => 0, 'hub.topic' => $this->uri); $client = new HTTPClient(); $response = $client->post($this->huburi, $headers, $post); @@ -317,8 +316,8 @@ class FeedSub extends Memcached_DataObject common_log(LOG_ERR, __METHOD__ . ": error \"{$e->getMessage()}\" hitting hub $this->huburi subscribing to $this->uri"); $orig = clone($this); - $this->verify_token = null; - $this->sub_state = null; + $this->verify_token = ''; + $this->sub_state = 'inactive'; $this->update($orig); unset($orig); @@ -343,7 +342,7 @@ class FeedSub extends Memcached_DataObject } else { $this->sub_end = null; } - $this->lastupdate = common_sql_now(); + $this->modified = common_sql_now(); return $this->update($original); } @@ -362,7 +361,7 @@ class FeedSub extends Memcached_DataObject $this->sub_state = ''; $this->sub_start = ''; $this->sub_end = ''; - $this->lastupdate = common_sql_now(); + $this->modified = common_sql_now(); return $this->update($original); } diff --git a/plugins/OStatus/classes/HubSub.php b/plugins/OStatus/classes/HubSub.php index a81de68e69..eae2928c32 100644 --- a/plugins/OStatus/classes/HubSub.php +++ b/plugins/OStatus/classes/HubSub.php @@ -30,11 +30,11 @@ class HubSub extends Memcached_DataObject public $topic; public $callback; public $secret; - public $challenge; public $lease; public $sub_start; public $sub_end; public $created; + public $modified; public /*static*/ function staticGet($topic, $callback) { @@ -61,11 +61,11 @@ class HubSub extends Memcached_DataObject 'topic' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'callback' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'secret' => DB_DATAOBJECT_STR, - 'challenge' => DB_DATAOBJECT_STR, 'lease' => DB_DATAOBJECT_INT, 'sub_start' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, 'sub_end' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, - 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); + 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, + 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); } static function schemaDef() @@ -82,8 +82,6 @@ class HubSub extends Memcached_DataObject 255, false), new ColumnDef('secret', 'text', null, true), - new ColumnDef('challenge', 'varchar', - 32, true), new ColumnDef('lease', 'int', null, true), new ColumnDef('sub_start', 'datetime', @@ -91,6 +89,8 @@ class HubSub extends Memcached_DataObject new ColumnDef('sub_end', 'datetime', null, true), new ColumnDef('created', 'datetime', + null, false), + new ColumnDef('modified', 'datetime', null, false)); } @@ -148,84 +148,105 @@ class HubSub extends Memcached_DataObject } /** - * Send a verification ping to subscriber + * Schedule a future verification ping to the subscriber. + * If queues are disabled, will be immediate. + * * @param string $mode 'subscribe' or 'unsubscribe' * @param string $token hub.verify_token value, if provided by client */ + function scheduleVerify($mode, $token=null, $retries=null) + { + if ($retries === null) { + $retries = intval(common_config('ostatus', 'hub_retries')); + } + $data = array('sub' => clone($this), + 'mode' => $mode, + 'token' => $token, + 'retries' => $retries); + $qm = QueueManager::get(); + $qm->enqueue($data, 'hubverify'); + } + + /** + * Send a verification ping to subscriber, and if confirmed apply the changes. + * This may create, update, or delete the database record. + * + * @param string $mode 'subscribe' or 'unsubscribe' + * @param string $token hub.verify_token value, if provided by client + * @throws ClientException on failure + */ function verify($mode, $token=null) { assert($mode == 'subscribe' || $mode == 'unsubscribe'); - // Is this needed? data object fun... - $clone = clone($this); - $clone->challenge = common_good_rand(16); - $clone->update($this); - $this->challenge = $clone->challenge; - unset($clone); - + $challenge = common_good_rand(32); $params = array('hub.mode' => $mode, 'hub.topic' => $this->topic, - 'hub.challenge' => $this->challenge); + 'hub.challenge' => $challenge); if ($mode == 'subscribe') { $params['hub.lease_seconds'] = $this->lease; } if ($token !== null) { $params['hub.verify_token'] = $token; } - $url = $this->callback . '?' . http_build_query($params, '', '&'); // @fixme ugly urls - try { - $request = new HTTPClient(); - $response = $request->get($url); - $status = $response->getStatus(); - - if ($status >= 200 && $status < 300) { - $fail = false; - } else { - // @fixme how can we schedule a second attempt? - // Or should we? - $fail = "Returned HTTP $status"; - } - } catch (Exception $e) { - $fail = $e->getMessage(); - } - if ($fail) { - // @fixme how can we schedule a second attempt? - // or save a fail count? - // Or should we? - common_log(LOG_ERR, "Failed to verify $mode for $this->topic at $this->callback: $fail"); - return false; + // Any existing query string parameters must be preserved + $url = $this->callback; + if (strpos('?', $url) !== false) { + $url .= '&'; } else { - if ($mode == 'subscribe') { - // Establish or renew the subscription! - // This seems unnecessary... dataobject fun! - $clone = clone($this); - $clone->challenge = null; - $clone->setLease($this->lease); - $clone->update($this); - unset($clone); + $url .= '?'; + } + $url .= http_build_query($params, '', '&'); - $this->challenge = null; - $this->setLease($this->lease); - common_log(LOG_ERR, "Verified $mode of $this->callback:$this->topic for $this->lease seconds"); - } else if ($mode == 'unsubscribe') { - common_log(LOG_ERR, "Verified $mode of $this->callback:$this->topic"); - $this->delete(); + $request = new HTTPClient(); + $response = $request->get($url); + $status = $response->getStatus(); + + if ($status >= 200 && $status < 300) { + common_log(LOG_INFO, "Verified $mode of $this->callback:$this->topic"); + } else { + throw new ClientException("Hub subscriber verification returned HTTP $status"); + } + + $old = HubSub::staticGet($this->topic, $this->callback); + if ($mode == 'subscribe') { + if ($old) { + $this->update($old); + } else { + $ok = $this->insert(); + } + } else if ($mode == 'unsubscribe') { + if ($old) { + $old->delete(); + } else { + // That's ok, we're already unsubscribed. } - return true; } } /** * Insert wrapper; transparently set the hash key from topic and callback columns. - * @return boolean success + * @return mixed success */ function insert() { $this->hashkey = self::hashkey($this->topic, $this->callback); + $this->created = common_sql_now(); + $this->modified = common_sql_now(); return parent::insert(); } + /** + * Update wrapper; transparently update modified column. + * @return boolean success + */ + function update($old=null) + { + $this->modified = common_sql_now(); + return parent::update($old); + } + /** * Schedule delivery of a 'fat ping' to the subscriber's callback * endpoint. If queues are disabled, this will run immediately. From be70dd3677242fe46d41a0a8882abe6e46428b5f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 21:57:09 -0500 Subject: [PATCH 106/190] work harder to preserve info when creating new Ostatus_profile --- plugins/OStatus/classes/Ostatus_profile.php | 67 +++++++++++++++++---- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 700168c118..3bed1c2aa0 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -522,7 +522,7 @@ class Ostatus_profile extends Memcached_DataObject * @return Ostatus_profile * @throws FeedSubException */ - public static function ensureProfile($profile_uri) + public static function ensureProfile($profile_uri, $hints=array()) { // Get the canonical feed URI and check it $discover = new FeedDiscovery(); @@ -545,7 +545,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($subject)) { $subjObject = new ActivityObject($subject); - return self::ensureActivityObjectProfile($subjObject, $feeduri, $salmonuri); + return self::ensureActivityObjectProfile($subjObject, $feeduri, $salmonuri, $hints); } // Otherwise, try the feed author @@ -554,7 +554,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($author)) { $authorObject = new ActivityObject($author); - return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri); + return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri, $hints); } // Sheesh. Not a very nice feed! Let's try fingerpoken in the @@ -570,7 +570,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($actor)) { $actorObject = new ActivityObject($actor); - return self::ensureActivityObjectProfile($actorObject, $feeduri, $salmonuri); + return self::ensureActivityObjectProfile($actorObject, $feeduri, $salmonuri, $hints); } @@ -578,7 +578,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($author)) { $authorObject = new ActivityObject($author); - return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri); + return self::ensureActivityObjectProfile($authorObject, $feeduri, $salmonuri, $hints); } } @@ -688,11 +688,11 @@ class Ostatus_profile extends Memcached_DataObject return self::ensureActivityObjectProfile($activity->actor, $feeduri, $salmonuri); } - public static function ensureActivityObjectProfile($object, $feeduri=null, $salmonuri=null) + public static function ensureActivityObjectProfile($object, $feeduri=null, $salmonuri=null, $hints=array()) { $profile = self::getActivityObjectProfile($object); if (!$profile) { - $profile = self::createActivityObjectProfile($object, $feeduri, $salmonuri); + $profile = self::createActivityObjectProfile($object, $feeduri, $salmonuri, $hints); } return $profile; } @@ -745,10 +745,10 @@ class Ostatus_profile extends Memcached_DataObject self::createActivityObjectProfile($actor, $feeduri, $salmonuri); } - protected static function createActivityObjectProfile($object, $feeduri=null, $salmonuri=null) + protected static function createActivityObjectProfile($object, $feeduri=null, $salmonuri=null, $hints=array()) { $homeuri = $object->id; - $nickname = self::getActivityObjectNickname($object); + $nickname = self::getActivityObjectNickname($object, $hints); $avatar = self::getActivityObjectAvatar($object); if (!$homeuri) { @@ -756,6 +756,18 @@ class Ostatus_profile extends Memcached_DataObject throw new ServerException("No profile URI"); } + if (empty($feeduri)) { + if (array_key_exists('feedurl', $hints)) { + $feeduri = $hints['feedurl']; + } + } + + if (empty($salmonuri)) { + if (array_key_exists('salmon', $hints)) { + $salmonuri = $hints['salmon']; + } + } + if (!$feeduri || !$salmonuri) { // Get the canonical feed URI and check it $discover = new FeedDiscovery(); @@ -773,7 +785,11 @@ class Ostatus_profile extends Memcached_DataObject $profile = new Profile(); $profile->nickname = $nickname; $profile->fullname = $object->title; - $profile->profileurl = $object->link; + if (!empty($object->link)) { + $profile->profileurl = $object->link; + } else if (array_key_exists('profileurl', $hints)) { + $profile->profileurl = $hints['profileurl']; + } $profile->created = common_sql_now(); // @fixme bio @@ -812,12 +828,24 @@ class Ostatus_profile extends Memcached_DataObject } } - protected static function getActivityObjectNickname($object) + protected static function getActivityObjectNickname($object, $hints=array()) { // XXX: check whatever PoCo calls a nickname first + // Try the definitive ID + $nickname = self::nicknameFromURI($object->id); + // Try a Webfinger if one was passed (way) down + + if (empty($nickname)) { + if (array_key_exists('webfinger', $hints)) { + $nickname = self::nicknameFromURI($hints['webfinger']); + } + } + + // Try the name + if (empty($nickname)) { $nickname = common_nicknamize($object->title); } @@ -883,11 +911,16 @@ class Ostatus_profile extends Memcached_DataObject } } + $hints = array('webfinger' => $addr, + 'profileurl' => $profileUrl, + 'feedurl' => $feedUrl, + 'salmon' => $salmonEndpoint); + // If we got a feed URL, try that if (isset($feedUrl)) { try { - $oprofile = self::ensureProfile($feedUrl); + $oprofile = self::ensureProfile($feedUrl, $hints); return $oprofile; } catch (Exception $e) { common_log(LOG_WARNING, "Failed creating profile from feed URL '$feedUrl': " . $e->getMessage()); @@ -899,7 +932,7 @@ class Ostatus_profile extends Memcached_DataObject if (isset($profileUrl)) { try { - $oprofile = self::ensureProfile($profileUrl); + $oprofile = self::ensureProfile($profileUrl, $hints); return $oprofile; } catch (Exception $e) { common_log(LOG_WARNING, "Failed creating profile from profile URL '$profileUrl': " . $e->getMessage()); @@ -922,6 +955,10 @@ class Ostatus_profile extends Memcached_DataObject $profile->nickname = self::nicknameFromUri($uri); $profile->created = common_sql_now(); + if (isset($profileUrl)) { + $profile->profileurl = $profileUrl; + } + $profile_id = $profile->insert(); if (!$profile_id) { @@ -936,6 +973,10 @@ class Ostatus_profile extends Memcached_DataObject $oprofile->profile_id = $profile_id; $oprofile->created = common_sql_now(); + if (isset($feedUrl)) { + $profile->feeduri = $feedUrl; + } + $result = $oprofile->insert(); if (!$result) { From ad10e6e8da5d1bc238fb90d7d9ef168c2525ceb4 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 19:01:32 -0800 Subject: [PATCH 107/190] OStatus: drop the remnants of feedsubsettings, replaced by ostatussub and no longer linked in UI --- plugins/OStatus/OStatusPlugin.php | 2 - plugins/OStatus/actions/feedsubsettings.php | 230 -------------------- 2 files changed, 232 deletions(-) delete mode 100644 plugins/OStatus/actions/feedsubsettings.php diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 60bb144a83..304cf14aef 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -58,8 +58,6 @@ class OStatusPlugin extends Plugin $m->connect('main/push/callback/:feed', array('action' => 'pushcallback'), array('feed' => '[0-9]+')); - $m->connect('settings/feedsub', - array('action' => 'feedsubsettings')); // Salmon endpoint $m->connect('main/salmon/user/:id', diff --git a/plugins/OStatus/actions/feedsubsettings.php b/plugins/OStatus/actions/feedsubsettings.php deleted file mode 100644 index aee4cee9af..0000000000 --- a/plugins/OStatus/actions/feedsubsettings.php +++ /dev/null @@ -1,230 +0,0 @@ -. - */ - -/** - * @package FeedSubPlugin - * @maintainer Brion Vibber - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -class FeedSubSettingsAction extends ConnectSettingsAction -{ - protected $profile_uri; - protected $preview; - protected $munger; - - /** - * Title of the page - * - * @return string Title of the page - */ - - function title() - { - return _m('Feed subscriptions'); - } - - /** - * Instructions for use - * - * @return instructions for use - */ - - function getInstructions() - { - return _m('You can subscribe to feeds from other sites; ' . - 'updates will appear in your personal timeline.'); - } - - /** - * Content area of the page - * - * Shows a form for associating a Twitter account with this - * StatusNet account. Also lets the user set preferences. - * - * @return void - */ - - function showContent() - { - $user = common_current_user(); - - $profile = $user->getProfile(); - - $this->elementStart('form', array('method' => 'post', - 'id' => 'form_settings_feedsub', - 'class' => 'form_settings', - 'action' => - common_local_url('feedsubsettings'))); - - $this->hidden('token', common_session_token()); - - $this->elementStart('fieldset', array('id' => 'settings_feeds')); - - $this->elementStart('ul', 'form_data'); - $this->elementStart('li', array('id' => 'settings_twitter_login_button')); - $this->input('profile_uri', - _m('Feed URL'), - $this->profile_uri, - _m('Enter the profile URL of a PubSubHubbub-enabled feed')); - $this->elementEnd('li'); - $this->elementEnd('ul'); - - if ($this->preview) { - $this->submit('subscribe', _m('Subscribe')); - } else { - $this->submit('validate', _m('Continue')); - } - - $this->elementEnd('fieldset'); - - $this->elementEnd('form'); - - if ($this->preview) { - $this->previewFeed(); - } - } - - /** - * Handle posts to this form - * - * Based on the button that was pressed, muxes out to other functions - * to do the actual task requested. - * - * All sub-functions reload the form with a message -- success or failure. - * - * @return void - */ - - function handlePost() - { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - - if ($this->arg('validate')) { - $this->validateAndPreview(); - } else if ($this->arg('subscribe')) { - $this->saveFeed(); - } else { - $this->showForm(_('Unexpected form submission.')); - } - } - - /** - * Set up and add a feed - * - * @return boolean true if feed successfully read - * Sends you back to input form if not. - */ - function validateFeed() - { - $profile_uri = trim($this->arg('profile_uri')); - - if ($profile_uri == '') { - $this->showForm(_m('Empty remote profile URL!')); - return; - } - $this->profile_uri = $profile_uri; - - // @fixme validate, normalize bla bla - try { - $oprofile = Ostatus_profile::ensureProfile($this->profile_uri); - $this->oprofile = $oprofile; - return true; - } catch (FeedSubBadURLException $e) { - $err = _m('Invalid URL or could not reach server.'); - } catch (FeedSubBadResponseException $e) { - $err = _m('Cannot read feed; server returned error.'); - } catch (FeedSubEmptyException $e) { - $err = _m('Cannot read feed; server returned an empty page.'); - } catch (FeedSubBadHTMLException $e) { - $err = _m('Bad HTML, could not find feed link.'); - } catch (FeedSubNoFeedException $e) { - $err = _m('Could not find a feed linked from this URL.'); - } catch (FeedSubUnrecognizedTypeException $e) { - $err = _m('Not a recognized feed type.'); - } catch (FeedSubException $e) { - // Any new ones we forgot about - $err = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage()); - } - - $this->showForm($err); - return false; - } - - function saveFeed() - { - if ($this->validateFeed()) { - $this->preview = true; - - // And subscribe the current user to the local profile - $user = common_current_user(); - - if (!$this->oprofile->subscribe()) { - $this->showForm(_m("Failed to set up server-to-server subscription.")); - return; - } - - if ($this->oprofile->isGroup()) { - $group = $this->oprofile->localGroup(); - if ($user->isMember($group)) { - $this->showForm(_m('Already a member!')); - } elseif (Group_member::join($this->profile->group_id, $user->id)) { - $this->showForm(_m('Joined remote group!')); - } else { - $this->showForm(_m('Remote group join failed!')); - } - } else { - $local = $this->oprofile->localProfile(); - if ($user->isSubscribed($local)) { - $this->showForm(_m('Already subscribed!')); - } elseif ($this->oprofile->subscribeLocalToRemote($user)) { - $this->showForm(_m('Remote user subscribed!')); - } else { - $this->showForm(_m('Remote subscription failed!')); - } - } - } - } - - function validateAndPreview() - { - if ($this->validateFeed()) { - $this->preview = true; - $this->showForm(_m('Previewing feed:')); - } - } - - function previewFeed() - { - $this->text('Profile preview should go here'); - } - - function showScripts() - { - parent::showScripts(); - $this->autofocus('feedurl'); - } -} From bd21f48ceed83699ca4c4613805b1edc1bf49f8c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 22:34:40 -0500 Subject: [PATCH 108/190] Notice::getReplies() returns array of profile IDs --- plugins/OStatus/OStatusPlugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 60bb144a83..fdc07b813f 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -201,9 +201,9 @@ class OStatusPlugin extends Plugin { $mentioned = $notice->getReplies(); - foreach ($mentioned as $profile) { + foreach ($mentioned as $profile_id) { - $oprofile = Ostatus_profile::staticGet('profile_id', $profile->id); + $oprofile = Ostatus_profile::staticGet('profile_id', $profile_id); if (!empty($oprofile) && !empty($oprofile->salmonuri)) { From de522d7978e0a843e338561b35a98b3e47a1e93c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 22:38:18 -0500 Subject: [PATCH 109/190] Wasn't putting in namespaces for reply salmons --- plugins/OStatus/OStatusPlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index ec6f3f3b0a..641765daeb 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -208,7 +208,7 @@ class OStatusPlugin extends Plugin // FIXME: this needs to go out in a queue handler $xml = ''; - $xml .= $notice->asAtomEntry(); + $xml .= $notice->asAtomEntry(true, true); $salmon = new Salmon(); $salmon->post($oprofile->salmonuri, $xml); From 13fb7bef783faae497069485546b92b897662987 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 22:41:02 -0500 Subject: [PATCH 110/190] reversed in_array() arguments in UsersalmonAction --- plugins/OStatus/actions/usersalmon.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 12c74798f2..3c0f72855b 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -80,7 +80,7 @@ class UsersalmonAction extends SalmonAction throw new ClientException("In reply to a notice not by this user"); } } else if (!empty($context->attention)) { - if (!in_array($context->attention, $this->user->uri)) { + if (!in_array($this->user->uri, $context->attention)) { throw new ClientException("To the attention of user(s) not including this one!"); } } else { From 232b5efa7e5d2771ef50b8a5da90147bbff7af3f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 22:44:58 -0500 Subject: [PATCH 111/190] Add error info for missing URI in attention --- plugins/OStatus/actions/usersalmon.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 3c0f72855b..ca0370bb4e 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -81,6 +81,7 @@ class UsersalmonAction extends SalmonAction } } else if (!empty($context->attention)) { if (!in_array($this->user->uri, $context->attention)) { + common_log(LOG_ERR, "{$this->user->uri} not in attention list (".implode(',', $context->attention).")"); throw new ClientException("To the attention of user(s) not including this one!"); } } else { From a745d38d6d1ff336898b24decb54549c72ad1f99 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 22:52:27 -0500 Subject: [PATCH 112/190] slight rearrangement of getting profile URIs --- classes/Profile.php | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/classes/Profile.php b/classes/Profile.php index 6b396c8c34..5ff746e309 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -841,28 +841,22 @@ class Profile extends Memcached_DataObject { $uri = null; - // check for a local user first - $user = User::staticGet('id', $this->id); + // give plugins a chance to set the URI + if (Event::handle('StartGetProfileUri', array($this, &$uri))) { - if (!empty($user)) { - $uri = common_local_url( - 'userbyid', - array('id' => $user->id) - ); - } else { - - // give plugins a chance to set the URI - if (Event::handle('StartGetProfileUri', array($this, &$uri))) { + // check for a local user first + $user = User::staticGet('id', $this->id); + if (!empty($user)) { + $uri = $user->uri; + } else { // return OMB profile if any $remote = Remote_profile::staticGet('id', $this->id); - if (!empty($remote)) { $uri = $remote->uri; } - - Event::handle('EndGetProfileUri', array($this, &$uri)); } + Event::handle('EndGetProfileUri', array($this, &$uri)); } return $uri; From cc18f757a8e6ef854cae89d8947efac505b1fd7c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 22:52:52 -0500 Subject: [PATCH 113/190] hook in OStatusPlugin to return Ostatus_profile URIs where applicable --- plugins/OStatus/OStatusPlugin.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 641765daeb..a8c292301d 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -484,4 +484,14 @@ class OStatusPlugin extends Plugin return true; } + + function onStartGetProfileUri($profile, &$uri) + { + $oprofile = Ostatus_profile::staticGet('profile_id', $profile->id); + if (!empty($oprofile)) { + $uri = $oprofile->uri; + return false; + } + return true; + } } From 5207783765328a3d6f0101f143edb8807247bcfe Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 21 Feb 2010 19:51:11 -0800 Subject: [PATCH 114/190] OStatus: record source profile & saving method in ostatus_source table; this allows us to distinguish posts that have come through an unverified group feed --- plugins/OStatus/OStatusPlugin.php | 1 + plugins/OStatus/classes/Ostatus_profile.php | 4 +- plugins/OStatus/classes/Ostatus_source.php | 114 ++++++++++++++++++++ plugins/OStatus/lib/salmonaction.php | 13 ++- 4 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 plugins/OStatus/classes/Ostatus_source.php diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 641765daeb..5b9e3be2bc 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -305,6 +305,7 @@ class OStatusPlugin extends Plugin function onCheckSchema() { $schema = Schema::get(); $schema->ensureTable('ostatus_profile', Ostatus_profile::schemaDef()); + $schema->ensureTable('ostatus_source', Ostatus_source::schemaDef()); $schema->ensureTable('feedsub', FeedSub::schemaDef()); $schema->ensureTable('hubsub', HubSub::schemaDef()); return true; diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 3bed1c2aa0..71885bcdce 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -508,13 +508,15 @@ class Ostatus_profile extends Memcached_DataObject } } - // @fixme save detailed ostatus source info // @fixme ensure that groups get handled correctly $saved = Notice::saveNew($oprofile->localProfile()->id, $content, 'ostatus', $params); + + // Record which feed this came through... + Ostatus_source::saveNew($saved, $this, 'push'); } /** diff --git a/plugins/OStatus/classes/Ostatus_source.php b/plugins/OStatus/classes/Ostatus_source.php new file mode 100644 index 0000000000..e6ce7d442b --- /dev/null +++ b/plugins/OStatus/classes/Ostatus_source.php @@ -0,0 +1,114 @@ +. + */ + +/** + * @package OStatusPlugin + * @maintainer Brion Vibber + */ + +class Ostatus_source extends Memcached_DataObject +{ + public $__table = 'ostatus_source'; + + public $notice_id; // notice we're referring to + public $profile_uri; // uri of the ostatus_profile this came through -- may be a group feed + public $method; // push or salmon + + public /*static*/ function staticGet($k, $v=null) + { + return parent::staticGet(__CLASS__, $k, $v); + } + + /** + * return table definition for DB_DataObject + * + * DB_DataObject needs to know something about the table to manipulate + * instances. This method provides all the DB_DataObject needs to know. + * + * @return array array of column definitions + */ + + function table() + { + return array('notice_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'profile_uri' => DB_DATAOBJECT_STR, + 'method' => DB_DATAOBJECT_STR); + } + + static function schemaDef() + { + return array(new ColumnDef('notice_id', 'integer', + null, false, 'PRI'), + new ColumnDef('profile_uri', 'varchar', + 255, false), + new ColumnDef('method', "ENUM('push','salmon')", + null, false)); + } + + /** + * return key definitions for DB_DataObject + * + * DB_DataObject needs to know about keys that the table has; this function + * defines them. + * + * @return array key definitions + */ + + function keys() + { + return array_keys($this->keyTypes()); + } + + /** + * return key definitions for Memcached_DataObject + * + * Our caching system uses the same key definitions, but uses a different + * method to get them. + * + * @return array key definitions + */ + + function keyTypes() + { + return array('notice_id' => 'K'); + } + + function sequenceKey() + { + return array(false, false, false); + } + + /** + * Save a remote notice source record; this helps indicate how trusted we are. + * @param string $method + */ + public static function saveNew(Notice $notice, Ostatus_profile $oprofile, $method) + { + $osource = new Ostatus_source(); + $osource->notice_id = $notice->id; + $osource->profile_uri = $oprofile->uri; + $osource->method = $method; + if ($osource->insert()) { + return true; + } else { + common_log_db_error($osource, 'INSERT', __FILE__); + return false; + } + } +} diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 11c411c7db..d93cc9aa4a 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -202,9 +202,14 @@ class SalmonAction extends Action $options['created'] = common_sql_time($this->act->time); } - return Notice::saveNew($oprofile->profile_id, - $content, - 'ostatus+salmon', - $options); + $saved = Notice::saveNew($oprofile->profile_id, + $content, + 'ostatus+salmon', + $options); + + // Record that this was saved through a validated Salmon source + // @fixme actually do the signature validation! + Ostatus_source::saveNew($saved, $oprofile, 'salmon'); + return $saved; } } From 17c329ba89f575c7fcbf05522a0cf50db6d6a74a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 23:07:46 -0500 Subject: [PATCH 115/190] add HTMLPurifier config --- plugins/OStatus/lib/salmonaction.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 11c411c7db..8734223c62 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -173,7 +173,10 @@ class SalmonAction extends Action $html = $this->act->object->content; - $rendered = HTMLPurifier::purify($html); + $htmlConfig = HTMLPurifier_Config::createDefault(); + + $rendered = HTMLPurifier::purify($html, $htmlConfig); + $content = html_entity_decode(strip_tags($rendered)); $options = array('is_local' => Notice::REMOTE_OMB, From e39e6cdcc590a5330ab5a20a2519346bfc7965e0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 23:16:42 -0500 Subject: [PATCH 116/190] was using HTMLPurifier::purify() as a static method, which it is not --- plugins/OStatus/lib/salmonaction.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 273be588b6..08bfa332fa 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -173,9 +173,9 @@ class SalmonAction extends Action $html = $this->act->object->content; - $htmlConfig = HTMLPurifier_Config::createDefault(); + $purifier = new HTMLPurifier(); - $rendered = HTMLPurifier::purify($html, $htmlConfig); + $rendered = $purifier->purify($html); $content = html_entity_decode(strip_tags($rendered)); From 48839a1fcf0c94b877c7c3232cf3e34eb0a9f23e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 23:19:29 -0500 Subject: [PATCH 117/190] change erroneous common_sql_time() to common_sql_date() --- plugins/OStatus/lib/salmonaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 08bfa332fa..b128cbd13f 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -202,7 +202,7 @@ class SalmonAction extends Action } if (!empty($this->act->time)) { - $options['created'] = common_sql_time($this->act->time); + $options['created'] = common_sql_date($this->act->time); } $saved = Notice::saveNew($oprofile->profile_id, From e4c4f90c8a303e566fa117fadb0004694b89ccc8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 23:32:20 -0500 Subject: [PATCH 118/190] don't save Notices that already exist in Salmon --- plugins/OStatus/actions/usersalmon.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index ca0370bb4e..8368eeccf0 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -88,6 +88,12 @@ class UsersalmonAction extends SalmonAction throw new ClientException("Not to anyone in reply to anything!"); } + $existing = Notice::staticGet('uri', $this->act->object->id); + + if (!empty($existing)) { + common_log(LOG_ERR, "Not saving notice '{$existing->uri}'; already exists."); + } + $this->saveNotice(); } From a9599d53c5e33eff2927f02393b9ae6984ba3a6e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 23:39:52 -0500 Subject: [PATCH 119/190] some info code for usersalmon.php --- plugins/OStatus/OStatusPlugin.php | 2 ++ plugins/OStatus/actions/usersalmon.php | 3 +++ 2 files changed, 5 insertions(+) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 548c877118..3ac2bb87d7 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -205,6 +205,8 @@ class OStatusPlugin extends Plugin if (!empty($oprofile) && !empty($oprofile->salmonuri)) { + common_log(LOG_INFO, "Sending notice '{$notice->uri}' to remote profile '{$oprofile->uri}'."); + // FIXME: this needs to go out in a queue handler $xml = ''; diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 8368eeccf0..c8a16e06fa 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -55,6 +55,8 @@ class UsersalmonAction extends SalmonAction */ function handlePost() { + common_log(LOG_INFO, "Received post of '{$this->act->object->id}' from '{$this->act->actor->id}'"); + switch ($this->act->object->type) { case ActivityObject::ARTICLE: case ActivityObject::BLOGENTRY: @@ -92,6 +94,7 @@ class UsersalmonAction extends SalmonAction if (!empty($existing)) { common_log(LOG_ERR, "Not saving notice '{$existing->uri}'; already exists."); + return; } $this->saveNotice(); From 891e0028838e51788e917d947cc280dbd53c1792 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Feb 2010 23:56:48 -0500 Subject: [PATCH 120/190] don't calculate replies for remote notices --- classes/Notice.php | 27 +++++++++++++++++++++++++++ lib/distribqueuehandler.php | 4 ++-- plugins/OStatus/lib/salmonaction.php | 3 ++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 6f1ef81fc5..a12839d729 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -333,8 +333,15 @@ class Notice extends Memcached_DataObject # Clear the cache for subscribed users, so they'll update at next request # XXX: someone clever could prepend instead of clearing the cache + $notice->blowOnInsert(); + if (isset($replies)) { + $notice->saveKnownReplies($replies); + } else { + $notice->saveReplies(); + } + $notice->distribute(); return $notice; @@ -817,6 +824,26 @@ class Notice extends Memcached_DataObject return true; } + function saveKnownReplies($uris) + { + foreach ($uris as $uri) { + + $user = User::staticGet('uri', $uri); + + if (!empty($user)) { + + $reply = new Reply(); + + $reply->notice_id = $this->id; + $reply->profile_id = $user->id; + + $id = $reply->insert(); + } + } + + return; + } + /** * @return array of integer profile IDs */ diff --git a/lib/distribqueuehandler.php b/lib/distribqueuehandler.php index 4477468d0a..c31b675c1a 100644 --- a/lib/distribqueuehandler.php +++ b/lib/distribqueuehandler.php @@ -75,7 +75,7 @@ class DistribQueueHandler } try { - $recipients = $notice->saveReplies(); + $recipients = $notice->getReplies(); } catch (Exception $e) { $this->logit($notice, $e); } @@ -107,7 +107,7 @@ class DistribQueueHandler return true; } - + protected function logit($notice, $e) { common_log(LOG_ERR, "Distrib queue exception saving notice $notice->id: " . diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index b128cbd13f..4aba20cc40 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -182,7 +182,8 @@ class SalmonAction extends Action $options = array('is_local' => Notice::REMOTE_OMB, 'uri' => $this->act->object->id, 'url' => $this->act->object->link, - 'rendered' => $rendered); + 'rendered' => $rendered, + 'replies' => $this->act->context->attention); if (!empty($this->act->context->location)) { $options['lat'] = $location->lat; From 17ed30dffc1c05259baf2f0387089547e39684d7 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 22 Feb 2010 06:00:13 +0000 Subject: [PATCH 121/190] OStatus: fix remote subscription when putting webfinger address in the little box --- plugins/OStatus/actions/ostatusinit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/actions/ostatusinit.php b/plugins/OStatus/actions/ostatusinit.php index 4afde2c36e..abd8cb5419 100644 --- a/plugins/OStatus/actions/ostatusinit.php +++ b/plugins/OStatus/actions/ostatusinit.php @@ -119,7 +119,7 @@ class OStatusInitAction extends Action } else { $this->connectProfile($this->acct); } - } elseif (strpos('@', $this->acct) !== false) { + } elseif (strpos($this->acct, '@') !== false) { $this->connectWebfinger($this->acct); } } @@ -139,7 +139,7 @@ class OStatusInitAction extends Action $user = User::staticGet('nickname', $this->nickname); $target_profile = common_local_url('userbyid', array('id' => $user->id)); - $url = $w->applyTemplate($link['template'], $feed_url); + $url = $w->applyTemplate($link['template'], $target_profile); common_redirect($url, 303); } From effa4f5d1efffcb52d4a95562e0b4831f7bd3435 Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 01:39:00 -0500 Subject: [PATCH 122/190] adding extlib for Crypt_RSA --- plugins/OStatus/OStatusPlugin.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 60bb144a83..24ed23a002 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -24,6 +24,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/'); + class FeedSubException extends Exception { } From 47300a2ae9a51108fbf59a57cf5ab6e8867b54a6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Feb 2010 01:21:34 -0800 Subject: [PATCH 123/190] Upgrade profile-based activity noun to have more complete set of profile fields --- classes/Profile.php | 45 ++++++++++++++++++++++++++++++++++++-- lib/atom10feed.php | 4 ++-- lib/atomusernoticefeed.php | 3 +-- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/classes/Profile.php b/classes/Profile.php index 6b396c8c34..4f67fc0bcc 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -792,9 +792,11 @@ class Profile extends Memcached_DataObject * Returns an XML string fragment with profile information as an * Activity Streams noun object with the given element type. * - * Assumes that 'activity' namespace has been previously defined. + * Assumes that 'activity', 'georss', and 'poco' namespace has been + * previously defined. * * @param string $element one of 'actor', 'subject', 'object', 'target' + * * @return string */ function asActivityNoun($element) @@ -811,9 +813,46 @@ class Profile extends Memcached_DataObject 'id', null, $this->getUri() - ); + ); + + // title should contain fullname $xs->element('title', null, $this->getBestName()); + // Portable Contacts stuff + + if (isset($this->bio)) { + + // XXX: Possible to use OpenSocial's aboutMe? + + $xs->element('poco:note', null, $this->bio); + } + + if (isset($this->homepage)) { + + $xs->elementStart('poco:urls'); + $xs->element('poco:value', null, $this->homepage); + $xs->element('poco:type', null, 'homepage'); + $xs->element('poco:primary', null, 'true'); + $xs->elementEnd('poco:urls'); + } + + if (isset($this->location)) { + $xs->elementStart('poco:address'); + $xs->element('poco:formatted', null, $this->location); + $xs->elementEnd('poco:address'); + } + + if (isset($this->lat) && isset($this->lon)) { + $this->element( + 'georss:point', + null, + (float)$this->lat . ' ' . (float)$this->lon + ); + } + + // XXX: Should we send all avatar sizes we have? I think + // cliqset does -Z + $avatar = $this->getAvatar(AVATAR_PROFILE_SIZE); $xs->element( @@ -829,6 +868,8 @@ class Profile extends Memcached_DataObject $xs->elementEnd('activity:' . $element); + // XXX: Add people tags with plural? + return $xs->getString(); } diff --git a/lib/atom10feed.php b/lib/atom10feed.php index 5e17b20d3a..8842840d56 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -109,11 +109,11 @@ class Atom10Feed extends XMLStringer ); } - if (!is_null($uri)) { + if (isset($uri)) { $xs->element('uri', null, $uri); } - if (!is_null(email)) { + if (isset($email)) { $xs->element('email', null, $email); } diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php index f71c721fec..2ad8de4550 100644 --- a/lib/atomusernoticefeed.php +++ b/lib/atomusernoticefeed.php @@ -60,8 +60,7 @@ class AtomUserNoticeFeed extends AtomNoticeFeed $this->user = $user; if (!empty($user)) { $profile = $user->getProfile(); - $this->addAuthor($profile->getBestName(), - $user->uri); + $this->addAuthor($profile->nickname, $user->uri); } } From f54c9b70dbabb70de93fcdd896297adfff5494f4 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 11:53:34 +0100 Subject: [PATCH 124/190] Fixed error/warning message location in OStatus autorize subscription page --- plugins/OStatus/actions/ostatussub.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index bbbd1b7e69..8cb8e2ae7c 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -58,6 +58,13 @@ class OStatusSubAction extends Action $this->showPage(); } + function showPageNotice() + { + if ($this->error) { + $this->element('p', 'error', $this->error); + } + } + /** * Content area of the page * @@ -69,11 +76,6 @@ class OStatusSubAction extends Action function showContent() { - // @fixme is this right place? - if ($this->error) { - $this->text($this->error); - } - $user = common_current_user(); $profile = $user->getProfile(); @@ -255,7 +257,7 @@ class OStatusSubAction extends Action { if ($this->validateFeed()) { $this->preview = true; - $this->showForm(_m('Previewing feed:')); + $this->showForm(); } } From e94800ced9884f20df73cd6325d0fefb33ac2236 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Feb 2010 07:08:57 -0500 Subject: [PATCH 125/190] fix broken link in OpenID documentation --- plugins/OpenID/doc-src/openid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OpenID/doc-src/openid b/plugins/OpenID/doc-src/openid index c741e36741..f2dc610a55 100644 --- a/plugins/OpenID/doc-src/openid +++ b/plugins/OpenID/doc-src/openid @@ -3,7 +3,7 @@ If you already have an account on %%site.name%%, you can [login](%%action.login%%) with your username and password as usual. To use OpenID in the future, you can [add an OpenID to your account](%%action.openidsettings%%) after you have logged in normally. -There are many [Public OpenID providers](http://wiki.openid.net/Public_OpenID_providers), and you may already have an OpenID-enabled account on another service. +There are many [Public OpenID providers](http://wiki.openid.net/OpenID-Providers), and you may already have an OpenID-enabled account on another service. * On wikis: If you have an account on an OpenID-enabled wiki, like [Wikitravel](http://wikitravel.org/), [wikiHow](http://www.wikihow.com/), [Vinismo](http://vinismo.com/), [AboutUs](http://aboutus.org/) or [Keiki](http://kei.ki/), you can log in to %%site.name%% by entering the **full URL** of your user page on that other wiki in the box above. For example, *http://kei.ki/en/User:Evan*. * [Yahoo!](http://openid.yahoo.com/) : If you have an account with Yahoo!, you can log in to this site by entering your Yahoo!-provided OpenID in the box above. Yahoo! OpenID URLs have the form *https://me.yahoo.com/yourusername*. From fae5a15a885b0c108efc4c5e28094f15ffbe8694 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Feb 2010 07:40:20 -0500 Subject: [PATCH 126/190] add strongly-suggested link to Profile::asActivityNoun() --- classes/Profile.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classes/Profile.php b/classes/Profile.php index 1ba3281ff6..faa6367b9c 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -818,6 +818,10 @@ class Profile extends Memcached_DataObject // title should contain fullname $xs->element('title', null, $this->getBestName()); + $xs->element('link', array('rel' => 'alternate', + 'type' => 'text/html'), + $this->profileurl); + // Portable Contacts stuff if (isset($this->bio)) { From b79d4ed6a1e61c600fdd382f3bdfde62aaa15b3d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Feb 2010 07:43:12 -0500 Subject: [PATCH 127/190] add PoCo preferredUsername for nickname in Profile::asActivityNoun() --- classes/Profile.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/classes/Profile.php b/classes/Profile.php index faa6367b9c..7fb2b87bc3 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -822,6 +822,8 @@ class Profile extends Memcached_DataObject 'type' => 'text/html'), $this->profileurl); + $xs->element('poco:preferredUsername', null, $this->nickname); + // Portable Contacts stuff if (isset($this->bio)) { From 75fdef209245bf9424d4b995a42e4dfd980469d2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Feb 2010 07:57:44 -0500 Subject: [PATCH 128/190] handle poco nicknames in Ostatus_profile --- plugins/OStatus/classes/Ostatus_profile.php | 4 +++- plugins/OStatus/lib/activity.php | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 71885bcdce..0e12f8fc6e 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -832,7 +832,9 @@ class Ostatus_profile extends Memcached_DataObject protected static function getActivityObjectNickname($object, $hints=array()) { - // XXX: check whatever PoCo calls a nickname first + if (!empty($object->nickname)) { + return common_nicknamize($object->nickname); + } // Try the definitive ID diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index af83f8bc66..a26248f199 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -31,6 +31,12 @@ if (!defined('STATUSNET')) { exit(1); } +class PoCo +{ + const NS = 'http://portablecontacts.net/spec/1.0'; + const USERNAME = 'preferredUsername'; +} + /** * Utilities for turning DOMish things into Activityish things * @@ -319,7 +325,8 @@ class ActivityObject $this->displayName = $this->title; // @fixme we may have multiple avatars with different resolutions specified - $this->avatar = ActivityUtils::getLink($element, 'avatar'); + $this->avatar = ActivityUtils::getLink($element, 'avatar'); + $this->nickname = ActivityUtils::childContent($element, PoCo::USERNAME, PoCo::NS); } } From e0388cc1d3922002596c2ec0531ac2f06d91806a Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 09:05:32 -0500 Subject: [PATCH 129/190] adding magic sig stuff --- plugins/OStatus/extlib/Crypt/RSA.php | 524 ++++++++++++ .../OStatus/extlib/Crypt/RSA/ErrorHandler.php | 234 +++++ plugins/OStatus/extlib/Crypt/RSA/Key.php | 315 +++++++ plugins/OStatus/extlib/Crypt/RSA/KeyPair.php | 804 ++++++++++++++++++ .../OStatus/extlib/Crypt/RSA/Math/BCMath.php | 482 +++++++++++ .../OStatus/extlib/Crypt/RSA/Math/BigInt.php | 313 +++++++ plugins/OStatus/extlib/Crypt/RSA/Math/GMP.php | 361 ++++++++ .../OStatus/extlib/Crypt/RSA/MathLoader.php | 135 +++ plugins/OStatus/lib/magicenvelope.php | 174 ++++ plugins/OStatus/lib/magicsig.php | 159 ++++ 10 files changed, 3501 insertions(+) create mode 100644 plugins/OStatus/extlib/Crypt/RSA.php create mode 100644 plugins/OStatus/extlib/Crypt/RSA/ErrorHandler.php create mode 100644 plugins/OStatus/extlib/Crypt/RSA/Key.php create mode 100644 plugins/OStatus/extlib/Crypt/RSA/KeyPair.php create mode 100644 plugins/OStatus/extlib/Crypt/RSA/Math/BCMath.php create mode 100644 plugins/OStatus/extlib/Crypt/RSA/Math/BigInt.php create mode 100644 plugins/OStatus/extlib/Crypt/RSA/Math/GMP.php create mode 100644 plugins/OStatus/extlib/Crypt/RSA/MathLoader.php create mode 100644 plugins/OStatus/lib/magicenvelope.php create mode 100644 plugins/OStatus/lib/magicsig.php diff --git a/plugins/OStatus/extlib/Crypt/RSA.php b/plugins/OStatus/extlib/Crypt/RSA.php new file mode 100644 index 0000000000..16dfa54d48 --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA.php @@ -0,0 +1,524 @@ + + * @copyright 2005, 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version 1.2.0b + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * loader for math wrappers + */ +require_once 'Crypt/RSA/MathLoader.php'; + +/** + * helper class for mange single key + */ +require_once 'Crypt/RSA/Key.php'; + +/** + * helper class for manage key pair + */ +require_once 'Crypt/RSA/KeyPair.php'; + +/** + * Crypt_RSA class, derived from Crypt_RSA_ErrorHandler + * + * Provides the following functions: + * - setParams($params) - sets parameters of current object + * - encrypt($plain_data, $key = null) - encrypts data + * - decrypt($enc_data, $key = null) - decrypts data + * - createSign($doc, $private_key = null) - signs document by private key + * - validateSign($doc, $signature, $public_key = null) - validates signature of document + * + * Example usage: + * // creating an error handler + * $error_handler = create_function('$obj', 'echo "error: ", $obj->getMessage(), "\n"'); + * + * // 1024-bit key pair generation + * $key_pair = new Crypt_RSA_KeyPair(1024); + * + * // check consistence of Crypt_RSA_KeyPair object + * $error_handler($key_pair); + * + * // creating Crypt_RSA object + * $rsa_obj = new Crypt_RSA; + * + * // check consistence of Crypt_RSA object + * $error_handler($rsa_obj); + * + * // set error handler on Crypt_RSA object ( see Crypt/RSA/ErrorHandler.php for details ) + * $rsa_obj->setErrorHandler($error_handler); + * + * // encryption (usually using public key) + * $enc_data = $rsa_obj->encrypt($plain_data, $key_pair->getPublicKey()); + * + * // decryption (usually using private key) + * $plain_data = $rsa_obj->decrypt($enc_data, $key_pair->getPrivateKey()); + * + * // signing + * $signature = $rsa_obj->createSign($document, $key_pair->getPrivateKey()); + * + * // signature checking + * $is_valid = $rsa_obj->validateSign($document, $signature, $key_pair->getPublicKey()); + * + * // signing many documents by one private key + * $rsa_obj = new Crypt_RSA(array('private_key' => $key_pair->getPrivateKey())); + * // check consistence of Crypt_RSA object + * $error_handler($rsa_obj); + * // set error handler ( see Crypt/RSA/ErrorHandler.php for details ) + * $rsa_obj->setErrorHandler($error_handler); + * // sign many documents + * $sign_1 = $rsa_obj->sign($doc_1); + * $sign_2 = $rsa_obj->sign($doc_2); + * //... + * $sign_n = $rsa_obj->sign($doc_n); + * + * // changing default hash function, which is used for sign + * // creating/validation + * $rsa_obj->setParams(array('hash_func' => 'md5')); + * + * // using factory() method instead of constructor (it returns PEAR_Error object on failure) + * $rsa_obj = &Crypt_RSA::factory(); + * if (PEAR::isError($rsa_obj)) { + * echo "error: ", $rsa_obj->getMessage(), "\n"; + * } + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright 2005, 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @link http://pear.php.net/package/Crypt_RSA + * @version @package_version@ + * @access public + */ +class Crypt_RSA extends Crypt_RSA_ErrorHandler +{ + /** + * Reference to math wrapper, which is used to + * manipulate large integers in RSA algorithm. + * + * @var object of Crypt_RSA_Math_* class + * @access private + */ + var $_math_obj; + + /** + * key for encryption, which is used by encrypt() method + * + * @var object of Crypt_RSA_KEY class + * @access private + */ + var $_enc_key; + + /** + * key for decryption, which is used by decrypt() method + * + * @var object of Crypt_RSA_KEY class + * @access private + */ + var $_dec_key; + + /** + * public key, which is used by validateSign() method + * + * @var object of Crypt_RSA_KEY class + * @access private + */ + var $_public_key; + + /** + * private key, which is used by createSign() method + * + * @var object of Crypt_RSA_KEY class + * @access private + */ + var $_private_key; + + /** + * name of hash function, which is used by validateSign() + * and createSign() methods. Default hash function is SHA-1 + * + * @var string + * @access private + */ + var $_hash_func = 'sha1'; + + /** + * Crypt_RSA constructor. + * + * @param array $params + * Optional associative array of parameters, such as: + * enc_key, dec_key, private_key, public_key, hash_func. + * See setParams() method for more detailed description of + * these parameters. + * @param string $wrapper_name + * Name of math wrapper, which will be used to + * perform different operations with big integers. + * See contents of Crypt/RSA/Math folder for examples of wrappers. + * Read docs/Crypt_RSA/docs/math_wrappers.txt for details. + * @param string $error_handler name of error handler function + * + * @access public + */ + function Crypt_RSA($params = null, $wrapper_name = 'default', $error_handler = '') + { + // set error handler + $this->setErrorHandler($error_handler); + // try to load math wrapper + $obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper_name); + if ($this->isError($obj)) { + // error during loading of math wrapper + // Crypt_RSA object is partially constructed. + $this->pushError($obj); + return; + } + $this->_math_obj = &$obj; + + if (!is_null($params)) { + if (!$this->setParams($params)) { + // error in Crypt_RSA::setParams() function + return; + } + } + } + + /** + * Crypt_RSA factory. + * + * @param array $params + * Optional associative array of parameters, such as: + * enc_key, dec_key, private_key, public_key, hash_func. + * See setParams() method for more detailed description of + * these parameters. + * @param string $wrapper_name + * Name of math wrapper, which will be used to + * perform different operations with big integers. + * See contents of Crypt/RSA/Math folder for examples of wrappers. + * Read docs/Crypt_RSA/docs/math_wrappers.txt for details. + * @param string $error_handler name of error handler function + * + * @return object new Crypt_RSA object on success or PEAR_Error object on failure + * @access public + */ + function &factory($params = null, $wrapper_name = 'default', $error_handler = '') + { + $obj = &new Crypt_RSA($params, $wrapper_name, $error_handler); + if ($obj->isError()) { + // error during creating a new object. Retrurn PEAR_Error object + return $obj->getLastError(); + } + // object created successfully. Return it + return $obj; + } + + /** + * Accepts any combination of available parameters as associative array: + * enc_key - encryption key for encrypt() method + * dec_key - decryption key for decrypt() method + * public_key - key for validateSign() method + * private_key - key for createSign() method + * hash_func - name of hash function, which will be used to create and validate sign + * + * @param array $params + * associative array of permitted parameters (see above) + * + * @return bool true on success or false on error + * @access public + */ + function setParams($params) + { + if (!is_array($params)) { + $this->pushError('parameters must be passed to function as associative array', CRYPT_RSA_ERROR_WRONG_PARAMS); + return false; + } + + if (isset($params['enc_key'])) { + if (Crypt_RSA_Key::isValid($params['enc_key'])) { + $this->_enc_key = $params['enc_key']; + } + else { + $this->pushError('wrong encryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return false; + } + } + if (isset($params['dec_key'])) { + if (Crypt_RSA_Key::isValid($params['dec_key'])) { + $this->_dec_key = $params['dec_key']; + } + else { + $this->pushError('wrong decryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return false; + } + } + if (isset($params['private_key'])) { + if (Crypt_RSA_Key::isValid($params['private_key'])) { + if ($params['private_key']->getKeyType() != 'private') { + $this->pushError('private key must have "private" attribute', CRYPT_RSA_ERROR_WRONG_KEY_TYPE); + return false; + } + $this->_private_key = $params['private_key']; + } + else { + $this->pushError('wrong private key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return false; + } + } + if (isset($params['public_key'])) { + if (Crypt_RSA_Key::isValid($params['public_key'])) { + if ($params['public_key']->getKeyType() != 'public') { + $this->pushError('public key must have "public" attribute', CRYPT_RSA_ERROR_WRONG_KEY_TYPE); + return false; + } + $this->_public_key = $params['public_key']; + } + else { + $this->pushError('wrong public key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return false; + } + } + if (isset($params['hash_func'])) { + if (!function_exists($params['hash_func'])) { + $this->pushError('cannot find hash function with name [' . $params['hash_func'] . ']', CRYPT_RSA_ERROR_WRONG_HASH_FUNC); + return false; + } + $this->_hash_func = $params['hash_func']; + } + return true; // all ok + } + + /** + * Ecnrypts $plain_data by the key $this->_enc_key or $key. + * + * @param string $plain_data data, which must be encrypted + * @param object $key encryption key (object of Crypt_RSA_Key class) + * @return mixed + * encrypted data as string on success or false on error + * + * @access public + */ + function encrypt($plain_data, $key = null) + { + $enc_data = $this->encryptBinary($plain_data, $key); + if ($enc_data !== false) { + return base64_encode($enc_data); + } + // error during encripting data + return false; + } + + /** + * Ecnrypts $plain_data by the key $this->_enc_key or $key. + * + * @param string $plain_data data, which must be encrypted + * @param object $key encryption key (object of Crypt_RSA_Key class) + * @return mixed + * encrypted data as binary string on success or false on error + * + * @access public + */ + function encryptBinary($plain_data, $key = null) + { + if (is_null($key)) { + // use current encryption key + $key = $this->_enc_key; + } + else if (!Crypt_RSA_Key::isValid($key)) { + $this->pushError('invalid encryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return false; + } + + // append tail \x01 to plain data. It needs for correctly decrypting of data + $plain_data .= "\x01"; + + $plain_data = $this->_math_obj->bin2int($plain_data); + $exp = $this->_math_obj->bin2int($key->getExponent()); + $modulus = $this->_math_obj->bin2int($key->getModulus()); + + // divide plain data into chunks + $data_len = $this->_math_obj->bitLen($plain_data); + $chunk_len = $key->getKeyLength() - 1; + $block_len = (int) ceil($chunk_len / 8); + $curr_pos = 0; + $enc_data = ''; + while ($curr_pos < $data_len) { + $tmp = $this->_math_obj->subint($plain_data, $curr_pos, $chunk_len); + $enc_data .= str_pad( + $this->_math_obj->int2bin($this->_math_obj->powmod($tmp, $exp, $modulus)), + $block_len, + "\0" + ); + $curr_pos += $chunk_len; + } + return $enc_data; + } + + /** + * Decrypts $enc_data by the key $this->_dec_key or $key. + * + * @param string $enc_data encrypted data as string + * @param object $key decryption key (object of RSA_Crypt_Key class) + * @return mixed + * decrypted data as string on success or false on error + * + * @access public + */ + function decrypt($enc_data, $key = null) + { + $enc_data = base64_decode($enc_data); + return $this->decryptBinary($enc_data, $key); + } + + /** + * Decrypts $enc_data by the key $this->_dec_key or $key. + * + * @param string $enc_data encrypted data as binary string + * @param object $key decryption key (object of RSA_Crypt_Key class) + * @return mixed + * decrypted data as string on success or false on error + * + * @access public + */ + function decryptBinary($enc_data, $key = null) + { + if (is_null($key)) { + // use current decryption key + $key = $this->_dec_key; + } + else if (!Crypt_RSA_Key::isValid($key)) { + $this->pushError('invalid decryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return false; + } + + $exp = $this->_math_obj->bin2int($key->getExponent()); + $modulus = $this->_math_obj->bin2int($key->getModulus()); + + $data_len = strlen($enc_data); + $chunk_len = $key->getKeyLength() - 1; + $block_len = (int) ceil($chunk_len / 8); + $curr_pos = 0; + $bit_pos = 0; + $plain_data = $this->_math_obj->bin2int("\0"); + while ($curr_pos < $data_len) { + $tmp = $this->_math_obj->bin2int(substr($enc_data, $curr_pos, $block_len)); + $tmp = $this->_math_obj->powmod($tmp, $exp, $modulus); + $plain_data = $this->_math_obj->bitOr($plain_data, $tmp, $bit_pos); + $bit_pos += $chunk_len; + $curr_pos += $block_len; + } + $result = $this->_math_obj->int2bin($plain_data); + + // delete tail, containing of \x01 + $tail = ord($result{strlen($result) - 1}); + if ($tail != 1) { + $this->pushError("Error tail of decrypted text = {$tail}. Expected 1", CRYPT_RSA_ERROR_WRONG_TAIL); + return false; + } + return substr($result, 0, -1); + } + + /** + * Creates sign for document $document, using $this->_private_key or $private_key + * as private key and $this->_hash_func or $hash_func as hash function. + * + * @param string $document document, which must be signed + * @param object $private_key private key (object of Crypt_RSA_Key type) + * @param string $hash_func name of hash function, which will be used during signing + * @return mixed + * signature of $document as string on success or false on error + * + * @access public + */ + function createSign($document, $private_key = null, $hash_func = null) + { + // check private key + if (is_null($private_key)) { + $private_key = $this->_private_key; + } + else if (!Crypt_RSA_Key::isValid($private_key)) { + $this->pushError('invalid private key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return false; + } + if ($private_key->getKeyType() != 'private') { + $this->pushError('signing key must be private', CRYPT_RSA_ERROR_NEED_PRV_KEY); + return false; + } + + // check hash_func + if (is_null($hash_func)) { + $hash_func = $this->_hash_func; + } + if (!function_exists($hash_func)) { + $this->pushError("cannot find hash function with name [$hash_func]", CRYPT_RSA_ERROR_WRONG_HASH_FUNC); + return false; + } + + return $this->encrypt($hash_func($document), $private_key); + } + + /** + * Validates $signature for document $document with public key $this->_public_key + * or $public_key and hash function $this->_hash_func or $hash_func. + * + * @param string $document document, signature of which must be validated + * @param string $signature signature, which must be validated + * @param object $public_key public key (object of Crypt_RSA_Key class) + * @param string $hash_func hash function, which will be used during validating signature + * @return mixed + * true, if signature of document is valid + * false, if signature of document is invalid + * null on error + * + * @access public + */ + function validateSign($document, $signature, $public_key = null, $hash_func = null) + { + // check public key + if (is_null($public_key)) { + $public_key = $this->_public_key; + } + else if (!Crypt_RSA_Key::isValid($public_key)) { + $this->pushError('invalid public key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); + return null; + } + if ($public_key->getKeyType() != 'public') { + $this->pushError('validating key must be public', CRYPT_RSA_ERROR_NEED_PUB_KEY); + return null; + } + + // check hash_func + if (is_null($hash_func)) { + $hash_func = $this->_hash_func; + } + if (!function_exists($hash_func)) { + $this->pushError("cannot find hash function with name [$hash_func]", CRYPT_RSA_ERROR_WRONG_HASH_FUNC); + return null; + } + + return $hash_func($document) == $this->decrypt($signature, $public_key); + } +} + +?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/Crypt/RSA/ErrorHandler.php b/plugins/OStatus/extlib/Crypt/RSA/ErrorHandler.php new file mode 100644 index 0000000000..8f39741e02 --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA/ErrorHandler.php @@ -0,0 +1,234 @@ + + * @copyright 2005 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: ErrorHandler.php,v 1.4 2009/01/05 08:30:29 clockwerx Exp $ + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * uses PEAR's error handling + */ +require_once 'PEAR.php'; + +/** + * cannot load required extension for math wrapper + */ +define('CRYPT_RSA_ERROR_NO_EXT', 1); + +/** + * cannot load any math wrappers. + * Possible reasons: + * - there is no any wrappers (they must exist in Crypt/RSA/Math folder ) + * - all available wrappers are incorrect (read docs/Crypt_RSA/docs/math_wrappers.txt ) + * - cannot load any extension, required by available wrappers + */ +define('CRYPT_RSA_ERROR_NO_WRAPPERS', 2); + +/** + * cannot find file, containing requested math wrapper + */ +define('CRYPT_RSA_ERROR_NO_FILE', 3); + +/** + * cannot find math wrapper class in the math wrapper file + */ +define('CRYPT_RSA_ERROR_NO_CLASS', 4); + +/** + * invalid key type passed to function (it must be 'public' or 'private') + */ +define('CRYPT_RSA_ERROR_WRONG_KEY_TYPE', 5); + +/** + * key modulus must be greater than key exponent + */ +define('CRYPT_RSA_ERROR_EXP_GE_MOD', 6); + +/** + * missing $key_len parameter in Crypt_RSA_KeyPair::generate($key_len) function + */ +define('CRYPT_RSA_ERROR_MISSING_KEY_LEN', 7); + +/** + * wrong key object passed to function (it must be an object of Crypt_RSA_Key class) + */ +define('CRYPT_RSA_ERROR_WRONG_KEY', 8); + +/** + * wrong name of hash function passed to Crypt_RSA::setParams() function + */ +define('CRYPT_RSA_ERROR_WRONG_HASH_FUNC', 9); + +/** + * key, used for signing, must be private + */ +define('CRYPT_RSA_ERROR_NEED_PRV_KEY', 10); + +/** + * key, used for sign validating, must be public + */ +define('CRYPT_RSA_ERROR_NEED_PUB_KEY', 11); + +/** + * parameters must be passed to function as associative array + */ +define('CRYPT_RSA_ERROR_WRONG_PARAMS', 12); + +/** + * error tail of decrypted text. Maybe, wrong decryption key? + */ +define('CRYPT_RSA_ERROR_WRONG_TAIL', 13); + +/** + * Crypt_RSA_ErrorHandler class. + * + * This class is used as base for Crypt_RSA, Crypt_RSA_Key + * and Crypt_RSA_KeyPair classes. + * + * It provides following functions: + * - isError() - returns true, if list contains errors, else returns false + * - getErrorList() - returns error list + * - getLastError() - returns last error from error list or false, if list is empty + * - pushError($errstr) - pushes $errstr into the error list + * - setErrorHandler($new_error_handler) - sets error handler function + * - getErrorHandler() - returns name of error handler function + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright 2005 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/Crypt_RSA + * @access public + */ +class Crypt_RSA_ErrorHandler +{ + /** + * array of error objects, pushed by $this->pushError() + * + * @var array + * @access private + */ + var $_errors = array(); + + /** + * name of error handler - function, which calls on $this->pushError() call + * + * @var string + * @access private + */ + var $_error_handler = ''; + + /** + * Returns true if list of errors is not empty, else returns false + * + * @param mixed $err Check if the object is an error + * + * @return bool true, if list of errors is not empty or $err is PEAR_Error object, else false + * @access public + */ + function isError($err = null) + { + return is_null($err) ? (sizeof($this->_errors) > 0) : PEAR::isError($err); + } + + /** + * Returns list of all errors, pushed to error list by $this->pushError() + * + * @return array list of errors (usually it contains objects of PEAR_Error class) + * @access public + */ + function getErrorList() + { + return $this->_errors; + } + + /** + * Returns last error from errors list or false, if list is empty + * + * @return mixed + * last error from errors list (usually it is PEAR_Error object) + * or false, if list is empty. + * + * @access public + */ + function getLastError() + { + $len = sizeof($this->_errors); + return $len ? $this->_errors[$len - 1] : false; + } + + /** + * pushes error object $error to the error list + * + * @param string $errstr error string + * @param int $errno error number + * + * @return bool true on success, false on error + * @access public + */ + function pushError($errstr, $errno = 0) + { + $this->_errors[] = PEAR::raiseError($errstr, $errno); + + if ($this->_error_handler != '') { + // call user defined error handler + $func = $this->_error_handler; + $func($this); + } + return true; + } + + /** + * sets error handler to function with name $func_name. + * Function $func_name must accept one parameter - current + * object, which triggered error. + * + * @param string $func_name name of error handler function + * + * @return bool true on success, false on error + * @access public + */ + function setErrorHandler($func_name = '') + { + if ($func_name == '') { + $this->_error_handler = ''; + } + if (!function_exists($func_name)) { + return false; + } + $this->_error_handler = $func_name; + return true; + } + + /** + * returns name of current error handler, or null if there is no error handler + * + * @return mixed error handler name as string or null, if there is no error handler + * @access public + */ + function getErrorHandler() + { + return $this->_error_handler; + } +} + +?> diff --git a/plugins/OStatus/extlib/Crypt/RSA/Key.php b/plugins/OStatus/extlib/Crypt/RSA/Key.php new file mode 100644 index 0000000000..6595302291 --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA/Key.php @@ -0,0 +1,315 @@ + + * @copyright 2005 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Key.php,v 1.6 2009/01/05 08:30:29 clockwerx Exp $ + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * loader for RSA math wrappers + */ +require_once 'Crypt/RSA/MathLoader.php'; + +/** + * Crypt_RSA_Key class, derived from Crypt_RSA_ErrorHandler + * + * Provides the following functions: + * - getKeyLength() - returns bit key length + * - getExponent() - returns key exponent as binary string + * - getModulus() - returns key modulus as binary string + * - getKeyType() - returns type of the key (public or private) + * - toString() - returns serialized key as string + * - fromString($key_str) - static function; returns key, unserialized from string + * - isValid($key) - static function for validating of $key + * + * Example usage: + * // create new 1024-bit key pair + * $key_pair = new Crypt_RSA_KeyPair(1024); + * + * // get public key (its class is Crypt_RSA_Key) + * $key = $key_pair->getPublicKey(); + * + * // get key length + * $len = $key->getKeyLength(); + * + * // get modulus as string + * $modulus = $key->getModulus(); + * + * // get exponent as string + * $exponent = $key->getExponent(); + * + * // get string represenation of key (use it instead of serialization of Crypt_RSA_Key object) + * $key_in_str = $key->toString(); + * + * // restore key object from string using 'BigInt' math wrapper + * $key = Crypt_RSA_Key::fromString($key_in_str, 'BigInt'); + * + * // error check + * if ($key->isError()) { + * echo "error while unserializing key object:\n"; + * $erorr = $key->getLastError(); + * echo $error->getMessage(), "\n"; + * } + * + * // validate key + * if (Crypt_RSA_Key::isValid($key)) echo 'valid key'; + * else echo 'invalid key'; + * + * // using factory() method instead of constructor (it returns PEAR_Error object on failure) + * $rsa_obj = &Crypt_RSA_Key::factory($modulus, $exp, $key_type); + * if (PEAR::isError($rsa_obj)) { + * echo "error: ", $rsa_obj->getMessage(), "\n"; + * } + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright 2005 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/Crypt_RSA + * @access public + */ +class Crypt_RSA_Key extends Crypt_RSA_ErrorHandler +{ + /** + * Reference to math wrapper object, which is used to + * manipulate large integers in RSA algorithm. + * + * @var object of Crypt_RSA_Math_* class + * @access private + */ + var $_math_obj; + + /** + * shared modulus + * + * @var string + * @access private + */ + var $_modulus; + + /** + * exponent + * + * @var string + * @access private + */ + var $_exp; + + /** + * key type (private or public) + * + * @var string + * @access private + */ + var $_key_type; + + /** + * key length in bits + * + * @var int + * @access private + */ + var $_key_len; + + /** + * Crypt_RSA_Key constructor. + * + * You should pass in the name of math wrapper, which will be used to + * perform different operations with big integers. + * See contents of Crypt/RSA/Math folder for examples of wrappers. + * Read docs/Crypt_RSA/docs/math_wrappers.txt for details. + * + * @param string $modulus key modulus + * @param string $exp key exponent + * @param string $key_type type of the key (public or private) + * @param string $wrapper_name wrapper to use + * @param string $error_handler name of error handler function + * + * @access public + */ + function Crypt_RSA_Key($modulus, $exp, $key_type, $wrapper_name = 'default', $error_handler = '') + { + // set error handler + $this->setErrorHandler($error_handler); + // try to load math wrapper $wrapper_name + $obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper_name); + if ($this->isError($obj)) { + // error during loading of math wrapper + $this->pushError($obj); // push error object into error list + return; + } + $this->_math_obj = &$obj; + + $this->_modulus = $modulus; + $this->_exp = $exp; + + if (!in_array($key_type, array('private', 'public'))) { + $this->pushError('invalid key type. It must be private or public', CRYPT_RSA_ERROR_WRONG_KEY_TYPE); + return; + } + $this->_key_type = $key_type; + + /* check length of modulus & exponent ( abs(modulus) > abs(exp) ) */ + $mod_num = $this->_math_obj->bin2int($this->_modulus); + $exp_num = $this->_math_obj->bin2int($this->_exp); + + if ($this->_math_obj->cmpAbs($mod_num, $exp_num) <= 0) { + $this->pushError('modulus must be greater than exponent', CRYPT_RSA_ERROR_EXP_GE_MOD); + return; + } + + // determine key length + $this->_key_len = $this->_math_obj->bitLen($mod_num); + } + + /** + * Crypt_RSA_Key factory. + * + * @param string $modulus key modulus + * @param string $exp key exponent + * @param string $key_type type of the key (public or private) + * @param string $wrapper_name wrapper to use + * @param string $error_handler name of error handler function + * + * @return object new Crypt_RSA_Key object on success or PEAR_Error object on failure + * @access public + */ + function factory($modulus, $exp, $key_type, $wrapper_name = 'default', $error_handler = '') + { + $obj = new Crypt_RSA_Key($modulus, $exp, $key_type, $wrapper_name, $error_handler); + if ($obj->isError()) { + // error during creating a new object. Retrurn PEAR_Error object + return $obj->getLastError(); + } + // object created successfully. Return it + return $obj; + } + + /** + * Calculates bit length of the key + * + * @return int bit length of key + * @access public + */ + function getKeyLength() + { + return $this->_key_len; + } + + /** + * Returns modulus part of the key as binary string, + * which can be used to construct new Crypt_RSA_Key object. + * + * @return string modulus as binary string + * @access public + */ + function getModulus() + { + return $this->_modulus; + } + + /** + * Returns exponent part of the key as binary string, + * which can be used to construct new Crypt_RSA_Key object. + * + * @return string exponent as binary string + * @access public + */ + function getExponent() + { + return $this->_exp; + } + + /** + * Returns key type (public, private) + * + * @return string key type (public, private) + * @access public + */ + function getKeyType() + { + return $this->_key_type; + } + + /** + * Returns string representation of key + * + * @return string key, serialized to string + * @access public + */ + function toString() + { + return base64_encode( + serialize( + array($this->_modulus, $this->_exp, $this->_key_type) + ) + ); + } + + /** + * Returns Crypt_RSA_Key object, unserialized from + * string representation of key. + * + * optional parameter $wrapper_name - is the name of math wrapper, + * which will be used during unserialization of this object. + * + * This function can be called statically: + * $key = Crypt_RSA_Key::fromString($key_in_string, 'BigInt'); + * + * @param string $key_str RSA key, serialized into string + * @param string $wrapper_name optional math wrapper name + * + * @return object key as Crypt_RSA_Key object + * @access public + * @static + */ + function fromString($key_str, $wrapper_name = 'default') + { + list($modulus, $exponent, $key_type) = unserialize(base64_decode($key_str)); + $obj = new Crypt_RSA_Key($modulus, $exponent, $key_type, $wrapper_name); + return $obj; + } + + /** + * Validates key + * This function can be called statically: + * $is_valid = Crypt_RSA_Key::isValid($key) + * + * Returns true, if $key is valid Crypt_RSA key, else returns false + * + * @param object $key Crypt_RSA_Key object for validating + * + * @return bool true if $key is valid, else false + * @access public + */ + function isValid($key) + { + return (is_object($key) && strtolower(get_class($key)) === strtolower(__CLASS__)); + } +} + +?> diff --git a/plugins/OStatus/extlib/Crypt/RSA/KeyPair.php b/plugins/OStatus/extlib/Crypt/RSA/KeyPair.php new file mode 100644 index 0000000000..ecc0b7dc7e --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA/KeyPair.php @@ -0,0 +1,804 @@ + + * @copyright 2005 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: KeyPair.php,v 1.7 2009/01/05 08:30:29 clockwerx Exp $ + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * loader for RSA math wrappers + */ +require_once 'Crypt/RSA/MathLoader.php'; + +/** + * helper class for single key managing + */ +require_once 'Crypt/RSA/Key.php'; + +/** + * Crypt_RSA_KeyPair class, derived from Crypt_RSA_ErrorHandler + * + * Provides the following functions: + * - generate($key) - generates new key pair + * - getPublicKey() - returns public key + * - getPrivateKey() - returns private key + * - getKeyLength() - returns bit key length + * - setRandomGenerator($func_name) - sets random generator to $func_name + * - fromPEMString($str) - retrieves keypair from PEM-encoded string + * - toPEMString() - stores keypair to PEM-encoded string + * - isEqual($keypair2) - compares current keypair to $keypair2 + * + * Example usage: + * // create new 1024-bit key pair + * $key_pair = new Crypt_RSA_KeyPair(1024); + * + * // error check + * if ($key_pair->isError()) { + * echo "error while initializing Crypt_RSA_KeyPair object:\n"; + * $erorr = $key_pair->getLastError(); + * echo $error->getMessage(), "\n"; + * } + * + * // get public key + * $public_key = $key_pair->getPublicKey(); + * + * // get private key + * $private_key = $key_pair->getPrivateKey(); + * + * // generate new 512-bit key pair + * $key_pair->generate(512); + * + * // error check + * if ($key_pair->isError()) { + * echo "error while generating key pair:\n"; + * $erorr = $key_pair->getLastError(); + * echo $error->getMessage(), "\n"; + * } + * + * // get key pair length + * $length = $key_pair->getKeyLength(); + * + * // set random generator to $func_name, where $func_name + * // consists name of random generator function. See comments + * // before setRandomGenerator() method for details + * $key_pair->setRandomGenerator($func_name); + * + * // error check + * if ($key_pair->isError()) { + * echo "error while changing random generator:\n"; + * $erorr = $key_pair->getLastError(); + * echo $error->getMessage(), "\n"; + * } + * + * // using factory() method instead of constructor (it returns PEAR_Error object on failure) + * $rsa_obj = &Crypt_RSA_KeyPair::factory($key_len); + * if (PEAR::isError($rsa_obj)) { + * echo "error: ", $rsa_obj->getMessage(), "\n"; + * } + * + * // read key pair from PEM-encoded string: + * $str = "-----BEGIN RSA PRIVATE KEY-----" + * . "MCsCAQACBHr5LDkCAwEAAQIEBc6jbQIDAOCfAgMAjCcCAk3pAgJMawIDAL41" + * . "-----END RSA PRIVATE KEY-----"; + * $keypair = Crypt_RSA_KeyPair::fromPEMString($str); + * + * // read key pair from .pem file 'private.pem': + * $str = file_get_contents('private.pem'); + * $keypair = Crypt_RSA_KeyPair::fromPEMString($str); + * + * // generate and write 1024-bit key pair to .pem file 'private_new.pem' + * $keypair = new Crypt_RSA_KeyPair(1024); + * $str = $keypair->toPEMString(); + * file_put_contents('private_new.pem', $str); + * + * // compare $keypair1 to $keypair2 + * if ($keypair1->isEqual($keypair2)) { + * echo "keypair1 = keypair2\n"; + * } + * else { + * echo "keypair1 != keypair2\n"; + * } + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright 2005 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/Crypt_RSA + * @access public + */ +class Crypt_RSA_KeyPair extends Crypt_RSA_ErrorHandler +{ + /** + * Reference to math wrapper object, which is used to + * manipulate large integers in RSA algorithm. + * + * @var object of Crypt_RSA_Math_* class + * @access private + */ + var $_math_obj; + + /** + * length of each key in the key pair + * + * @var int + * @access private + */ + var $_key_len; + + /** + * public key + * + * @var object of Crypt_RSA_KEY class + * @access private + */ + var $_public_key; + + /** + * private key + * + * @var object of Crypt_RSA_KEY class + * @access private + */ + var $_private_key; + + /** + * name of function, which is used as random generator + * + * @var string + * @access private + */ + var $_random_generator; + + /** + * RSA keypair attributes [version, n, e, d, p, q, dmp1, dmq1, iqmp] as associative array + * + * @var array + * @access private + */ + var $_attrs; + + /** + * Returns names of keypair attributes from $this->_attrs array + * + * @return array Array of keypair attributes names + * @access private + */ + function _get_attr_names() + { + return array('version', 'n', 'e', 'd', 'p', 'q', 'dmp1', 'dmq1', 'iqmp'); + } + + /** + * Parses ASN.1 string [$str] starting form position [$pos]. + * Returns tag and string value of parsed object. + * + * @param string $str + * @param int &$pos + * @param Crypt_RSA_ErrorHandler &$err_handler + * + * @return mixed Array('tag' => ..., 'str' => ...) on success, false on error + * @access private + */ + function _ASN1Parse($str, &$pos, &$err_handler) + { + $max_pos = strlen($str); + if ($max_pos < 2) { + $err_handler->pushError("ASN.1 string too short"); + return false; + } + + // get ASN.1 tag value + $tag = ord($str[$pos++]) & 0x1f; + if ($tag == 0x1f) { + $tag = 0; + do { + $n = ord($str[$pos++]); + $tag <<= 7; + $tag |= $n & 0x7f; + } while (($n & 0x80) && $pos < $max_pos); + } + if ($pos >= $max_pos) { + $err_handler->pushError("ASN.1 string too short"); + return false; + } + + // get ASN.1 object length + $len = ord($str[$pos++]); + if ($len & 0x80) { + $n = $len & 0x1f; + $len = 0; + while ($n-- && $pos < $max_pos) { + $len <<= 8; + $len |= ord($str[$pos++]); + } + } + if ($pos >= $max_pos || $len > $max_pos - $pos) { + $err_handler->pushError("ASN.1 string too short"); + return false; + } + + // get string value of ASN.1 object + $str = substr($str, $pos, $len); + + return array( + 'tag' => $tag, + 'str' => $str, + ); + } + + /** + * Parses ASN.1 sting [$str] starting from position [$pos]. + * Returns string representation of number, which can be passed + * in bin2int() function of math wrapper. + * + * @param string $str + * @param int &$pos + * @param Crypt_RSA_ErrorHandler &$err_handler + * + * @return mixed string representation of parsed number on success, false on error + * @access private + */ + function _ASN1ParseInt($str, &$pos, &$err_handler) + { + $tmp = Crypt_RSA_KeyPair::_ASN1Parse($str, $pos, $err_handler); + if ($err_handler->isError()) { + return false; + } + if ($tmp['tag'] != 0x02) { + $errstr = sprintf("wrong ASN tag value: 0x%02x. Expected 0x02 (INTEGER)", $tmp['tag']); + $err_handler->pushError($errstr); + return false; + } + $pos += strlen($tmp['str']); + + return strrev($tmp['str']); + } + + /** + * Constructs ASN.1 string from tag $tag and object $str + * + * @param string $str ASN.1 object string + * @param int $tag ASN.1 tag value + * @param bool $is_constructed + * @param bool $is_private + * + * @return ASN.1-encoded string + * @access private + */ + function _ASN1Store($str, $tag, $is_constructed = false, $is_private = false) + { + $out = ''; + + // encode ASN.1 tag value + $tag_ext = ($is_constructed ? 0x20 : 0) | ($is_private ? 0xc0 : 0); + if ($tag < 0x1f) { + $out .= chr($tag | $tag_ext); + } else { + $out .= chr($tag_ext | 0x1f); + $tmp = chr($tag & 0x7f); + $tag >>= 7; + while ($tag) { + $tmp .= chr(($tag & 0x7f) | 0x80); + $tag >>= 7; + } + $out .= strrev($tmp); + } + + // encode ASN.1 object length + $len = strlen($str); + if ($len < 0x7f) { + $out .= chr($len); + } else { + $tmp = ''; + $n = 0; + while ($len) { + $tmp .= chr($len & 0xff); + $len >>= 8; + $n++; + } + $out .= chr($n | 0x80); + $out .= strrev($tmp); + } + + return $out . $str; + } + + /** + * Constructs ASN.1 string from binary representation of big integer + * + * @param string $str binary representation of big integer + * + * @return ASN.1-encoded string + * @access private + */ + function _ASN1StoreInt($str) + { + $str = strrev($str); + return Crypt_RSA_KeyPair::_ASN1Store($str, 0x02); + } + + /** + * Crypt_RSA_KeyPair constructor. + * + * Wrapper: name of math wrapper, which will be used to + * perform different operations with big integers. + * See contents of Crypt/RSA/Math folder for examples of wrappers. + * Read docs/Crypt_RSA/docs/math_wrappers.txt for details. + * + * @param int $key_len bit length of key pair, which will be generated in constructor + * @param string $wrapper_name wrapper name + * @param string $error_handler name of error handler function + * @param callback $random_generator function which will be used as random generator + * + * @access public + */ + function Crypt_RSA_KeyPair($key_len, $wrapper_name = 'default', $error_handler = '', $random_generator = null) + { + // set error handler + $this->setErrorHandler($error_handler); + // try to load math wrapper + $obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper_name); + if ($this->isError($obj)) { + // error during loading of math wrapper + $this->pushError($obj); + return; + } + $this->_math_obj = &$obj; + + // set random generator + if (!$this->setRandomGenerator($random_generator)) { + // error in setRandomGenerator() function + return; + } + + if (is_array($key_len)) { + // ugly BC hack - it is possible to pass RSA private key attributes [version, n, e, d, p, q, dmp1, dmq1, iqmp] + // as associative array instead of key length to Crypt_RSA_KeyPair constructor + $rsa_attrs = $key_len; + + // convert attributes to big integers + $attr_names = $this->_get_attr_names(); + foreach ($attr_names as $attr) { + if (!isset($rsa_attrs[$attr])) { + $this->pushError("missing required RSA attribute [$attr]"); + return; + } + ${$attr} = $this->_math_obj->bin2int($rsa_attrs[$attr]); + } + + // check primality of p and q + if (!$this->_math_obj->isPrime($p)) { + $this->pushError("[p] must be prime"); + return; + } + if (!$this->_math_obj->isPrime($q)) { + $this->pushError("[q] must be prime"); + return; + } + + // check n = p * q + $n1 = $this->_math_obj->mul($p, $q); + if ($this->_math_obj->cmpAbs($n, $n1)) { + $this->pushError("n != p * q"); + return; + } + + // check e * d = 1 mod (p-1) * (q-1) + $p1 = $this->_math_obj->dec($p); + $q1 = $this->_math_obj->dec($q); + $p1q1 = $this->_math_obj->mul($p1, $q1); + $ed = $this->_math_obj->mul($e, $d); + $one = $this->_math_obj->mod($ed, $p1q1); + if (!$this->_math_obj->isOne($one)) { + $this->pushError("e * d != 1 mod (p-1)*(q-1)"); + return; + } + + // check dmp1 = d mod (p-1) + $dmp = $this->_math_obj->mod($d, $p1); + if ($this->_math_obj->cmpAbs($dmp, $dmp1)) { + $this->pushError("dmp1 != d mod (p-1)"); + return; + } + + // check dmq1 = d mod (q-1) + $dmq = $this->_math_obj->mod($d, $q1); + if ($this->_math_obj->cmpAbs($dmq, $dmq1)) { + $this->pushError("dmq1 != d mod (q-1)"); + return; + } + + // check iqmp = 1/q mod p + $q1 = $this->_math_obj->invmod($iqmp, $p); + if ($this->_math_obj->cmpAbs($q, $q1)) { + $this->pushError("iqmp != 1/q mod p"); + return; + } + + // try to create public key object + $public_key = &new Crypt_RSA_Key($rsa_attrs['n'], $rsa_attrs['e'], 'public', $wrapper_name, $error_handler); + if ($public_key->isError()) { + // error during creating public object + $this->pushError($public_key->getLastError()); + return; + } + + // try to create private key object + $private_key = &new Crypt_RSA_Key($rsa_attrs['n'], $rsa_attrs['d'], 'private', $wrapper_name, $error_handler); + if ($private_key->isError()) { + // error during creating private key object + $this->pushError($private_key->getLastError()); + return; + } + + $this->_public_key = $public_key; + $this->_private_key = $private_key; + $this->_key_len = $public_key->getKeyLength(); + $this->_attrs = $rsa_attrs; + } else { + // generate key pair + if (!$this->generate($key_len)) { + // error during generating key pair + return; + } + } + } + + /** + * Crypt_RSA_KeyPair factory. + * + * Wrapper - Name of math wrapper, which will be used to + * perform different operations with big integers. + * See contents of Crypt/RSA/Math folder for examples of wrappers. + * Read docs/Crypt_RSA/docs/math_wrappers.txt for details. + * + * @param int $key_len bit length of key pair, which will be generated in constructor + * @param string $wrapper_name wrapper name + * @param string $error_handler name of error handler function + * @param callback $random_generator function which will be used as random generator + * + * @return object new Crypt_RSA_KeyPair object on success or PEAR_Error object on failure + * @access public + */ + function &factory($key_len, $wrapper_name = 'default', $error_handler = '', $random_generator = null) + { + $obj = &new Crypt_RSA_KeyPair($key_len, $wrapper_name, $error_handler, $random_generator); + if ($obj->isError()) { + // error during creating a new object. Return PEAR_Error object + return $obj->getLastError(); + } + // object created successfully. Return it + return $obj; + } + + /** + * Generates new Crypt_RSA key pair with length $key_len. + * If $key_len is missed, use an old key length from $this->_key_len + * + * @param int $key_len bit length of key pair, which will be generated + * + * @return bool true on success or false on error + * @access public + */ + function generate($key_len = null) + { + if (is_null($key_len)) { + // use an old key length + $key_len = $this->_key_len; + if (is_null($key_len)) { + $this->pushError('missing key_len parameter', CRYPT_RSA_ERROR_MISSING_KEY_LEN); + return false; + } + } + + // minimal key length is 8 bit ;) + if ($key_len < 8) { + $key_len = 8; + } + // store key length in the _key_len property + $this->_key_len = $key_len; + + // set [e] to 0x10001 (65537) + $e = $this->_math_obj->bin2int("\x01\x00\x01"); + + // generate [p], [q] and [n] + $p_len = intval(($key_len + 1) / 2); + $q_len = $key_len - $p_len; + $p1 = $q1 = 0; + do { + // generate prime number [$p] with length [$p_len] with the following condition: + // GCD($e, $p - 1) = 1 + do { + $p = $this->_math_obj->getPrime($p_len, $this->_random_generator); + $p1 = $this->_math_obj->dec($p); + $tmp = $this->_math_obj->GCD($e, $p1); + } while (!$this->_math_obj->isOne($tmp)); + // generate prime number [$q] with length [$q_len] with the following conditions: + // GCD($e, $q - 1) = 1 + // $q != $p + do { + $q = $this->_math_obj->getPrime($q_len, $this->_random_generator); + $q1 = $this->_math_obj->dec($q); + $tmp = $this->_math_obj->GCD($e, $q1); + } while (!$this->_math_obj->isOne($tmp) && !$this->_math_obj->cmpAbs($q, $p)); + // if (p < q), then exchange them + if ($this->_math_obj->cmpAbs($p, $q) < 0) { + $tmp = $p; + $p = $q; + $q = $tmp; + $tmp = $p1; + $p1 = $q1; + $q1 = $tmp; + } + // calculate n = p * q + $n = $this->_math_obj->mul($p, $q); + } while ($this->_math_obj->bitLen($n) != $key_len); + + // calculate d = 1/e mod (p - 1) * (q - 1) + $pq = $this->_math_obj->mul($p1, $q1); + $d = $this->_math_obj->invmod($e, $pq); + + // calculate dmp1 = d mod (p - 1) + $dmp1 = $this->_math_obj->mod($d, $p1); + + // calculate dmq1 = d mod (q - 1) + $dmq1 = $this->_math_obj->mod($d, $q1); + + // calculate iqmp = 1/q mod p + $iqmp = $this->_math_obj->invmod($q, $p); + + // store RSA keypair attributes + $this->_attrs = array( + 'version' => "\x00", + 'n' => $this->_math_obj->int2bin($n), + 'e' => $this->_math_obj->int2bin($e), + 'd' => $this->_math_obj->int2bin($d), + 'p' => $this->_math_obj->int2bin($p), + 'q' => $this->_math_obj->int2bin($q), + 'dmp1' => $this->_math_obj->int2bin($dmp1), + 'dmq1' => $this->_math_obj->int2bin($dmq1), + 'iqmp' => $this->_math_obj->int2bin($iqmp), + ); + + $n = $this->_attrs['n']; + $e = $this->_attrs['e']; + $d = $this->_attrs['d']; + + // try to create public key object + $obj = &new Crypt_RSA_Key($n, $e, 'public', $this->_math_obj->getWrapperName(), $this->_error_handler); + if ($obj->isError()) { + // error during creating public object + $this->pushError($obj->getLastError()); + return false; + } + $this->_public_key = &$obj; + + // try to create private key object + $obj = &new Crypt_RSA_Key($n, $d, 'private', $this->_math_obj->getWrapperName(), $this->_error_handler); + if ($obj->isError()) { + // error during creating private key object + $this->pushError($obj->getLastError()); + return false; + } + $this->_private_key = &$obj; + + return true; // key pair successfully generated + } + + /** + * Returns public key from the pair + * + * @return object public key object of class Crypt_RSA_Key + * @access public + */ + function getPublicKey() + { + return $this->_public_key; + } + + /** + * Returns private key from the pair + * + * @return object private key object of class Crypt_RSA_Key + * @access public + */ + function getPrivateKey() + { + return $this->_private_key; + } + + /** + * Sets name of random generator function for key generation. + * If parameter is skipped, then sets to default random generator. + * + * Random generator function must return integer with at least 8 lower + * significant bits, which will be used as random values. + * + * @param string $random_generator name of random generator function + * + * @return bool true on success or false on error + * @access public + */ + function setRandomGenerator($random_generator = null) + { + static $default_random_generator = null; + + if (is_string($random_generator)) { + // set user's random generator + if (!function_exists($random_generator)) { + $this->pushError("can't find random generator function with name [{$random_generator}]"); + return false; + } + $this->_random_generator = $random_generator; + } else { + // set default random generator + $this->_random_generator = is_null($default_random_generator) ? + ($default_random_generator = create_function('', '$a=explode(" ",microtime());return(int)($a[0]*1000000);')) : + $default_random_generator; + } + return true; + } + + /** + * Returns length of each key in the key pair + * + * @return int bit length of each key in key pair + * @access public + */ + function getKeyLength() + { + return $this->_key_len; + } + + /** + * Retrieves RSA keypair from PEM-encoded string, containing RSA private key. + * Example of such string: + * -----BEGIN RSA PRIVATE KEY----- + * MCsCAQACBHtvbSECAwEAAQIEeYrk3QIDAOF3AgMAjCcCAmdnAgJMawIDALEk + * -----END RSA PRIVATE KEY----- + * + * Wrapper: Name of math wrapper, which will be used to + * perform different operations with big integers. + * See contents of Crypt/RSA/Math folder for examples of wrappers. + * Read docs/Crypt_RSA/docs/math_wrappers.txt for details. + * + * @param string $str PEM-encoded string + * @param string $wrapper_name Wrapper name + * @param string $error_handler name of error handler function + * + * @return Crypt_RSA_KeyPair object on success, PEAR_Error object on error + * @access public + * @static + */ + function &fromPEMString($str, $wrapper_name = 'default', $error_handler = '') + { + if (isset($this)) { + if ($wrapper_name == 'default') { + $wrapper_name = $this->_math_obj->getWrapperName(); + } + if ($error_handler == '') { + $error_handler = $this->_error_handler; + } + } + $err_handler = &new Crypt_RSA_ErrorHandler; + $err_handler->setErrorHandler($error_handler); + + // search for base64-encoded private key + if (!preg_match('/-----BEGIN RSA PRIVATE KEY-----([^-]+)-----END RSA PRIVATE KEY-----/', $str, $matches)) { + $err_handler->pushError("can't find RSA private key in the string [{$str}]"); + return $err_handler->getLastError(); + } + + // parse private key. It is ASN.1-encoded + $str = base64_decode($matches[1]); + $pos = 0; + $tmp = Crypt_RSA_KeyPair::_ASN1Parse($str, $pos, $err_handler); + if ($err_handler->isError()) { + return $err_handler->getLastError(); + } + if ($tmp['tag'] != 0x10) { + $errstr = sprintf("wrong ASN tag value: 0x%02x. Expected 0x10 (SEQUENCE)", $tmp['tag']); + $err_handler->pushError($errstr); + return $err_handler->getLastError(); + } + + // parse ASN.1 SEQUENCE for RSA private key + $attr_names = Crypt_RSA_KeyPair::_get_attr_names(); + $n = sizeof($attr_names); + $rsa_attrs = array(); + for ($i = 0; $i < $n; $i++) { + $tmp = Crypt_RSA_KeyPair::_ASN1ParseInt($str, $pos, $err_handler); + if ($err_handler->isError()) { + return $err_handler->getLastError(); + } + $attr = $attr_names[$i]; + $rsa_attrs[$attr] = $tmp; + } + + // create Crypt_RSA_KeyPair object. + $keypair = &new Crypt_RSA_KeyPair($rsa_attrs, $wrapper_name, $error_handler); + if ($keypair->isError()) { + return $keypair->getLastError(); + } + + return $keypair; + } + + /** + * converts keypair to PEM-encoded string, which can be stroed in + * .pem compatible files, contianing RSA private key. + * + * @return string PEM-encoded keypair on success, false on error + * @access public + */ + function toPEMString() + { + // store RSA private key attributes into ASN.1 string + $str = ''; + $attr_names = $this->_get_attr_names(); + $n = sizeof($attr_names); + $rsa_attrs = $this->_attrs; + for ($i = 0; $i < $n; $i++) { + $attr = $attr_names[$i]; + if (!isset($rsa_attrs[$attr])) { + $this->pushError("Cannot find value for ASN.1 attribute [$attr]"); + return false; + } + $tmp = $rsa_attrs[$attr]; + $str .= Crypt_RSA_KeyPair::_ASN1StoreInt($tmp); + } + + // prepend $str by ASN.1 SEQUENCE (0x10) header + $str = Crypt_RSA_KeyPair::_ASN1Store($str, 0x10, true); + + // encode and format PEM string + $str = base64_encode($str); + $str = chunk_split($str, 64, "\n"); + return "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n"; + } + + /** + * Compares keypairs in Crypt_RSA_KeyPair objects $this and $key_pair + * + * @param Crypt_RSA_KeyPair $key_pair keypair to compare + * + * @return bool true, if keypair stored in $this equal to keypair stored in $key_pair + * @access public + */ + function isEqual($key_pair) + { + $attr_names = $this->_get_attr_names(); + foreach ($attr_names as $attr) { + if ($this->_attrs[$attr] != $key_pair->_attrs[$attr]) { + return false; + } + } + return true; + } +} + +?> diff --git a/plugins/OStatus/extlib/Crypt/RSA/Math/BCMath.php b/plugins/OStatus/extlib/Crypt/RSA/Math/BCMath.php new file mode 100644 index 0000000000..646ff67103 --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA/Math/BCMath.php @@ -0,0 +1,482 @@ + + * @copyright 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version 1.2.0b + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * Crypt_RSA_Math_BCMath class. + * + * Provides set of math functions, which are used by Crypt_RSA package + * This class is a wrapper for PHP BCMath extension. + * See http://php.net/manual/en/ref.bc.php for details. + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright 2005, 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @link http://pear.php.net/package/Crypt_RSA + * @version @package_version@ + * @access public + */ +class Crypt_RSA_Math_BCMath +{ + /** + * error description + * + * @var string + * @access public + */ + var $errstr = ''; + + /** + * Performs Miller-Rabin primality test for number $num + * with base $base. Returns true, if $num is strong pseudoprime + * by base $base. Else returns false. + * + * @param string $num + * @param string $base + * @return bool + * @access private + */ + function _millerTest($num, $base) + { + if (!bccomp($num, '1')) { + // 1 is not prime ;) + return false; + } + $tmp = bcsub($num, '1'); + + $zero_bits = 0; + while (!bccomp(bcmod($tmp, '2'), '0')) { + $zero_bits++; + $tmp = bcdiv($tmp, '2'); + } + + $tmp = $this->powmod($base, $tmp, $num); + if (!bccomp($tmp, '1')) { + // $num is probably prime + return true; + } + + while ($zero_bits--) { + if (!bccomp(bcadd($tmp, '1'), $num)) { + // $num is probably prime + return true; + } + $tmp = $this->powmod($tmp, '2', $num); + } + // $num is composite + return false; + } + + /** + * Crypt_RSA_Math_BCMath constructor. + * Checks an existance of PHP BCMath extension. + * On failure saves error description in $this->errstr + * + * @access public + */ + function Crypt_RSA_Math_BCMath() + { + if (!extension_loaded('bcmath')) { + if (!@dl('bcmath.' . PHP_SHLIB_SUFFIX) && !@dl('php_bcmath.' . PHP_SHLIB_SUFFIX)) { + // cannot load BCMath extension. Set error string + $this->errstr = 'Crypt_RSA package requires the BCMath extension. See http://php.net/manual/en/ref.bc.php for details'; + return; + } + } + } + + /** + * Transforms binary representation of large integer into its native form. + * + * Example of transformation: + * $str = "\x12\x34\x56\x78\x90"; + * $num = 0x9078563412; + * + * @param string $str + * @return string + * @access public + */ + function bin2int($str) + { + $result = '0'; + $n = strlen($str); + do { + $result = bcadd(bcmul($result, '256'), ord($str{--$n})); + } while ($n > 0); + return $result; + } + + /** + * Transforms large integer into binary representation. + * + * Example of transformation: + * $num = 0x9078563412; + * $str = "\x12\x34\x56\x78\x90"; + * + * @param string $num + * @return string + * @access public + */ + function int2bin($num) + { + $result = ''; + do { + $result .= chr(bcmod($num, '256')); + $num = bcdiv($num, '256'); + } while (bccomp($num, '0')); + return $result; + } + + /** + * Calculates pow($num, $pow) (mod $mod) + * + * @param string $num + * @param string $pow + * @param string $mod + * @return string + * @access public + */ + function powmod($num, $pow, $mod) + { + if (function_exists('bcpowmod')) { + // bcpowmod is only available under PHP5 + return bcpowmod($num, $pow, $mod); + } + + // emulate bcpowmod + $result = '1'; + do { + if (!bccomp(bcmod($pow, '2'), '1')) { + $result = bcmod(bcmul($result, $num), $mod); + } + $num = bcmod(bcpow($num, '2'), $mod); + $pow = bcdiv($pow, '2'); + } while (bccomp($pow, '0')); + return $result; + } + + /** + * Calculates $num1 * $num2 + * + * @param string $num1 + * @param string $num2 + * @return string + * @access public + */ + function mul($num1, $num2) + { + return bcmul($num1, $num2); + } + + /** + * Calculates $num1 % $num2 + * + * @param string $num1 + * @param string $num2 + * @return string + * @access public + */ + function mod($num1, $num2) + { + return bcmod($num1, $num2); + } + + /** + * Compares abs($num1) to abs($num2). + * Returns: + * -1, if abs($num1) < abs($num2) + * 0, if abs($num1) == abs($num2) + * 1, if abs($num1) > abs($num2) + * + * @param string $num1 + * @param string $num2 + * @return int + * @access public + */ + function cmpAbs($num1, $num2) + { + return bccomp($num1, $num2); + } + + /** + * Tests $num on primality. Returns true, if $num is strong pseudoprime. + * Else returns false. + * + * @param string $num + * @return bool + * @access private + */ + function isPrime($num) + { + static $primes = null; + static $primes_cnt = 0; + if (is_null($primes)) { + // generate all primes up to 10000 + $primes = array(); + for ($i = 0; $i < 10000; $i++) { + $primes[] = $i; + } + $primes[0] = $primes[1] = 0; + for ($i = 2; $i < 100; $i++) { + while (!$primes[$i]) { + $i++; + } + $j = $i; + for ($j += $i; $j < 10000; $j += $i) { + $primes[$j] = 0; + } + } + $j = 0; + for ($i = 0; $i < 10000; $i++) { + if ($primes[$i]) { + $primes[$j++] = $primes[$i]; + } + } + $primes_cnt = $j; + } + + // try to divide number by small primes + for ($i = 0; $i < $primes_cnt; $i++) { + if (bccomp($num, $primes[$i]) <= 0) { + // number is prime + return true; + } + if (!bccomp(bcmod($num, $primes[$i]), '0')) { + // number divides by $primes[$i] + return false; + } + } + + /* + try Miller-Rabin's probable-primality test for first + 7 primes as bases + */ + for ($i = 0; $i < 7; $i++) { + if (!$this->_millerTest($num, $primes[$i])) { + // $num is composite + return false; + } + } + // $num is strong pseudoprime + return true; + } + + /** + * Generates prime number with length $bits_cnt + * using $random_generator as random generator function. + * + * @param int $bits_cnt + * @param string $rnd_generator + * @access public + */ + function getPrime($bits_cnt, $random_generator) + { + $bytes_n = intval($bits_cnt / 8); + $bits_n = $bits_cnt % 8; + do { + $str = ''; + for ($i = 0; $i < $bytes_n; $i++) { + $str .= chr(call_user_func($random_generator) & 0xff); + } + $n = call_user_func($random_generator) & 0xff; + $n |= 0x80; + $n >>= 8 - $bits_n; + $str .= chr($n); + $num = $this->bin2int($str); + + // search for the next closest prime number after [$num] + if (!bccomp(bcmod($num, '2'), '0')) { + $num = bcadd($num, '1'); + } + while (!$this->isPrime($num)) { + $num = bcadd($num, '2'); + } + } while ($this->bitLen($num) != $bits_cnt); + return $num; + } + + /** + * Calculates $num - 1 + * + * @param string $num + * @return string + * @access public + */ + function dec($num) + { + return bcsub($num, '1'); + } + + /** + * Returns true, if $num is equal to one. Else returns false + * + * @param string $num + * @return bool + * @access public + */ + function isOne($num) + { + return !bccomp($num, '1'); + } + + /** + * Finds greatest common divider (GCD) of $num1 and $num2 + * + * @param string $num1 + * @param string $num2 + * @return string + * @access public + */ + function GCD($num1, $num2) + { + do { + $tmp = bcmod($num1, $num2); + $num1 = $num2; + $num2 = $tmp; + } while (bccomp($num2, '0')); + return $num1; + } + + /** + * Finds inverse number $inv for $num by modulus $mod, such as: + * $inv * $num = 1 (mod $mod) + * + * @param string $num + * @param string $mod + * @return string + * @access public + */ + function invmod($num, $mod) + { + $x = '1'; + $y = '0'; + $num1 = $mod; + do { + $tmp = bcmod($num, $num1); + $q = bcdiv($num, $num1); + $num = $num1; + $num1 = $tmp; + + $tmp = bcsub($x, bcmul($y, $q)); + $x = $y; + $y = $tmp; + } while (bccomp($num1, '0')); + if (bccomp($x, '0') < 0) { + $x = bcadd($x, $mod); + } + return $x; + } + + /** + * Returns bit length of number $num + * + * @param string $num + * @return int + * @access public + */ + function bitLen($num) + { + $tmp = $this->int2bin($num); + $bit_len = strlen($tmp) * 8; + $tmp = ord($tmp{strlen($tmp) - 1}); + if (!$tmp) { + $bit_len -= 8; + } + else { + while (!($tmp & 0x80)) { + $bit_len--; + $tmp <<= 1; + } + } + return $bit_len; + } + + /** + * Calculates bitwise or of $num1 and $num2, + * starting from bit $start_pos for number $num1 + * + * @param string $num1 + * @param string $num2 + * @param int $start_pos + * @return string + * @access public + */ + function bitOr($num1, $num2, $start_pos) + { + $start_byte = intval($start_pos / 8); + $start_bit = $start_pos % 8; + $tmp1 = $this->int2bin($num1); + + $num2 = bcmul($num2, 1 << $start_bit); + $tmp2 = $this->int2bin($num2); + if ($start_byte < strlen($tmp1)) { + $tmp2 |= substr($tmp1, $start_byte); + $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2; + } + else { + $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2; + } + return $this->bin2int($tmp1); + } + + /** + * Returns part of number $num, starting at bit + * position $start with length $length + * + * @param string $num + * @param int start + * @param int length + * @return string + * @access public + */ + function subint($num, $start, $length) + { + $start_byte = intval($start / 8); + $start_bit = $start % 8; + $byte_length = intval($length / 8); + $bit_length = $length % 8; + if ($bit_length) { + $byte_length++; + } + $num = bcdiv($num, 1 << $start_bit); + $tmp = substr($this->int2bin($num), $start_byte, $byte_length); + $tmp = str_pad($tmp, $byte_length, "\0"); + $tmp = substr_replace($tmp, $tmp{$byte_length - 1} & chr(0xff >> (8 - $bit_length)), $byte_length - 1, 1); + return $this->bin2int($tmp); + } + + /** + * Returns name of current wrapper + * + * @return string name of current wrapper + * @access public + */ + function getWrapperName() + { + return 'BCMath'; + } +} + +?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/Crypt/RSA/Math/BigInt.php b/plugins/OStatus/extlib/Crypt/RSA/Math/BigInt.php new file mode 100644 index 0000000000..b7ac24cb66 --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA/Math/BigInt.php @@ -0,0 +1,313 @@ + + * @copyright 2005, 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version 1.2.0b + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * Crypt_RSA_Math_BigInt class. + * + * Provides set of math functions, which are used by Crypt_RSA package + * This class is a wrapper for big_int PECL extension, + * which could be loaded from http://pecl.php.net/packages/big_int + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright 2005, 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @link http://pear.php.net/package/Crypt_RSA + * @version @package_version@ + * @access public + */ +class Crypt_RSA_Math_BigInt +{ + /** + * error description + * + * @var string + * @access public + */ + var $errstr = ''; + + /** + * Crypt_RSA_Math_BigInt constructor. + * Checks an existance of big_int PECL math package. + * This package is available at http://pecl.php.net/packages/big_int + * On failure saves error description in $this->errstr + * + * @access public + */ + function Crypt_RSA_Math_BigInt() + { + if (!extension_loaded('big_int')) { + if (!@dl('big_int.' . PHP_SHLIB_SUFFIX) && !@dl('php_big_int.' . PHP_SHLIB_SUFFIX)) { + // cannot load big_int extension + $this->errstr = 'Crypt_RSA package requires big_int PECL package. ' . + 'It is available at http://pecl.php.net/packages/big_int'; + return; + } + } + + // check version of big_int extension ( Crypt_RSA requires version 1.0.2 and higher ) + if (!in_array('bi_info', get_extension_funcs('big_int'))) { + // there is no bi_info() function in versions, older than 1.0.2 + $this->errstr = 'Crypt_RSA package requires big_int package version 1.0.2 and higher'; + } + } + + /** + * Transforms binary representation of large integer into its native form. + * + * Example of transformation: + * $str = "\x12\x34\x56\x78\x90"; + * $num = 0x9078563412; + * + * @param string $str + * @return big_int resource + * @access public + */ + function bin2int($str) + { + return bi_unserialize($str); + } + + /** + * Transforms large integer into binary representation. + * + * Example of transformation: + * $num = 0x9078563412; + * $str = "\x12\x34\x56\x78\x90"; + * + * @param big_int resource $num + * @return string + * @access public + */ + function int2bin($num) + { + return bi_serialize($num); + } + + /** + * Calculates pow($num, $pow) (mod $mod) + * + * @param big_int resource $num + * @param big_int resource $pow + * @param big_int resource $mod + * @return big_int resource + * @access public + */ + function powmod($num, $pow, $mod) + { + return bi_powmod($num, $pow, $mod); + } + + /** + * Calculates $num1 * $num2 + * + * @param big_int resource $num1 + * @param big_int resource $num2 + * @return big_int resource + * @access public + */ + function mul($num1, $num2) + { + return bi_mul($num1, $num2); + } + + /** + * Calculates $num1 % $num2 + * + * @param string $num1 + * @param string $num2 + * @return string + * @access public + */ + function mod($num1, $num2) + { + return bi_mod($num1, $num2); + } + + /** + * Compares abs($num1) to abs($num2). + * Returns: + * -1, if abs($num1) < abs($num2) + * 0, if abs($num1) == abs($num2) + * 1, if abs($num1) > abs($num2) + * + * @param big_int resource $num1 + * @param big_int resource $num2 + * @return int + * @access public + */ + function cmpAbs($num1, $num2) + { + return bi_cmp_abs($num1, $num2); + } + + /** + * Tests $num on primality. Returns true, if $num is strong pseudoprime. + * Else returns false. + * + * @param string $num + * @return bool + * @access private + */ + function isPrime($num) + { + return bi_is_prime($num) ? true : false; + } + + /** + * Generates prime number with length $bits_cnt + * using $random_generator as random generator function. + * + * @param int $bits_cnt + * @param string $rnd_generator + * @access public + */ + function getPrime($bits_cnt, $random_generator) + { + $bytes_n = intval($bits_cnt / 8); + $bits_n = $bits_cnt % 8; + do { + $str = ''; + for ($i = 0; $i < $bytes_n; $i++) { + $str .= chr(call_user_func($random_generator) & 0xff); + } + $n = call_user_func($random_generator) & 0xff; + $n |= 0x80; + $n >>= 8 - $bits_n; + $str .= chr($n); + $num = $this->bin2int($str); + + // search for the next closest prime number after [$num] + $num = bi_next_prime($num); + } while ($this->bitLen($num) != $bits_cnt); + return $num; + } + + /** + * Calculates $num - 1 + * + * @param big_int resource $num + * @return big_int resource + * @access public + */ + function dec($num) + { + return bi_dec($num); + } + + /** + * Returns true, if $num is equal to 1. Else returns false + * + * @param big_int resource $num + * @return bool + * @access public + */ + function isOne($num) + { + return bi_is_one($num); + } + + /** + * Finds greatest common divider (GCD) of $num1 and $num2 + * + * @param big_int resource $num1 + * @param big_int resource $num2 + * @return big_int resource + * @access public + */ + function GCD($num1, $num2) + { + return bi_gcd($num1, $num2); + } + + /** + * Finds inverse number $inv for $num by modulus $mod, such as: + * $inv * $num = 1 (mod $mod) + * + * @param big_int resource $num + * @param big_int resource $mod + * @return big_int resource + * @access public + */ + function invmod($num, $mod) + { + return bi_invmod($num, $mod); + } + + /** + * Returns bit length of number $num + * + * @param big_int resource $num + * @return int + * @access public + */ + function bitLen($num) + { + return bi_bit_len($num); + } + + /** + * Calculates bitwise or of $num1 and $num2, + * starting from bit $start_pos for number $num1 + * + * @param big_int resource $num1 + * @param big_int resource $num2 + * @param int $start_pos + * @return big_int resource + * @access public + */ + function bitOr($num1, $num2, $start_pos) + { + return bi_or($num1, $num2, $start_pos); + } + + /** + * Returns part of number $num, starting at bit + * position $start with length $length + * + * @param big_int resource $num + * @param int start + * @param int length + * @return big_int resource + * @access public + */ + function subint($num, $start, $length) + { + return bi_subint($num, $start, $length); + } + + /** + * Returns name of current wrapper + * + * @return string name of current wrapper + * @access public + */ + function getWrapperName() + { + return 'BigInt'; + } +} + +?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/Crypt/RSA/Math/GMP.php b/plugins/OStatus/extlib/Crypt/RSA/Math/GMP.php new file mode 100644 index 0000000000..54e4c34fce --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA/Math/GMP.php @@ -0,0 +1,361 @@ + + * @copyright 2005, 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version 1.2.0b + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * Crypt_RSA_Math_GMP class. + * + * Provides set of math functions, which are used by Crypt_RSA package + * This class is a wrapper for PHP GMP extension. + * See http://php.net/gmp for details. + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright 2005, 2006 Alexander Valyalkin + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @link http://pear.php.net/package/Crypt_RSA + * @version @package_version@ + * @access public + */ +class Crypt_RSA_Math_GMP +{ + /** + * error description + * + * @var string + * @access public + */ + var $errstr = ''; + + /** + * Crypt_RSA_Math_GMP constructor. + * Checks an existance of PHP GMP package. + * See http://php.net/gmp for details. + * + * On failure saves error description in $this->errstr + * + * @access public + */ + function Crypt_RSA_Math_GMP() + { + if (!extension_loaded('gmp')) { + if (!@dl('gmp.' . PHP_SHLIB_SUFFIX) && !@dl('php_gmp.' . PHP_SHLIB_SUFFIX)) { + // cannot load GMP extension + $this->errstr = 'Crypt_RSA package requires PHP GMP package. ' . + 'See http://php.net/gmp for details'; + return; + } + } + } + + /** + * Transforms binary representation of large integer into its native form. + * + * Example of transformation: + * $str = "\x12\x34\x56\x78\x90"; + * $num = 0x9078563412; + * + * @param string $str + * @return gmp resource + * @access public + */ + function bin2int($str) + { + $result = 0; + $n = strlen($str); + do { + // dirty hack: GMP returns FALSE, when second argument equals to int(0). + // so, it must be converted to string '0' + $result = gmp_add(gmp_mul($result, 256), strval(ord($str{--$n}))); + } while ($n > 0); + return $result; + } + + /** + * Transforms large integer into binary representation. + * + * Example of transformation: + * $num = 0x9078563412; + * $str = "\x12\x34\x56\x78\x90"; + * + * @param gmp resource $num + * @return string + * @access public + */ + function int2bin($num) + { + $result = ''; + do { + $result .= chr(gmp_intval(gmp_mod($num, 256))); + $num = gmp_div($num, 256); + } while (gmp_cmp($num, 0)); + return $result; + } + + /** + * Calculates pow($num, $pow) (mod $mod) + * + * @param gmp resource $num + * @param gmp resource $pow + * @param gmp resource $mod + * @return gmp resource + * @access public + */ + function powmod($num, $pow, $mod) + { + return gmp_powm($num, $pow, $mod); + } + + /** + * Calculates $num1 * $num2 + * + * @param gmp resource $num1 + * @param gmp resource $num2 + * @return gmp resource + * @access public + */ + function mul($num1, $num2) + { + return gmp_mul($num1, $num2); + } + + /** + * Calculates $num1 % $num2 + * + * @param string $num1 + * @param string $num2 + * @return string + * @access public + */ + function mod($num1, $num2) + { + return gmp_mod($num1, $num2); + } + + /** + * Compares abs($num1) to abs($num2). + * Returns: + * -1, if abs($num1) < abs($num2) + * 0, if abs($num1) == abs($num2) + * 1, if abs($num1) > abs($num2) + * + * @param gmp resource $num1 + * @param gmp resource $num2 + * @return int + * @access public + */ + function cmpAbs($num1, $num2) + { + return gmp_cmp($num1, $num2); + } + + /** + * Tests $num on primality. Returns true, if $num is strong pseudoprime. + * Else returns false. + * + * @param string $num + * @return bool + * @access private + */ + function isPrime($num) + { + return gmp_prob_prime($num) ? true : false; + } + + /** + * Generates prime number with length $bits_cnt + * using $random_generator as random generator function. + * + * @param int $bits_cnt + * @param string $rnd_generator + * @access public + */ + function getPrime($bits_cnt, $random_generator) + { + $bytes_n = intval($bits_cnt / 8); + $bits_n = $bits_cnt % 8; + do { + $str = ''; + for ($i = 0; $i < $bytes_n; $i++) { + $str .= chr(call_user_func($random_generator) & 0xff); + } + $n = call_user_func($random_generator) & 0xff; + $n |= 0x80; + $n >>= 8 - $bits_n; + $str .= chr($n); + $num = $this->bin2int($str); + + // search for the next closest prime number after [$num] + if (!gmp_cmp(gmp_mod($num, '2'), '0')) { + $num = gmp_add($num, '1'); + } + while (!gmp_prob_prime($num)) { + $num = gmp_add($num, '2'); + } + } while ($this->bitLen($num) != $bits_cnt); + return $num; + } + + /** + * Calculates $num - 1 + * + * @param gmp resource $num + * @return gmp resource + * @access public + */ + function dec($num) + { + return gmp_sub($num, 1); + } + + /** + * Returns true, if $num is equal to one. Else returns false + * + * @param gmp resource $num + * @return bool + * @access public + */ + function isOne($num) + { + return !gmp_cmp($num, 1); + } + + /** + * Finds greatest common divider (GCD) of $num1 and $num2 + * + * @param gmp resource $num1 + * @param gmp resource $num2 + * @return gmp resource + * @access public + */ + function GCD($num1, $num2) + { + return gmp_gcd($num1, $num2); + } + + /** + * Finds inverse number $inv for $num by modulus $mod, such as: + * $inv * $num = 1 (mod $mod) + * + * @param gmp resource $num + * @param gmp resource $mod + * @return gmp resource + * @access public + */ + function invmod($num, $mod) + { + return gmp_invert($num, $mod); + } + + /** + * Returns bit length of number $num + * + * @param gmp resource $num + * @return int + * @access public + */ + function bitLen($num) + { + $tmp = $this->int2bin($num); + $bit_len = strlen($tmp) * 8; + $tmp = ord($tmp{strlen($tmp) - 1}); + if (!$tmp) { + $bit_len -= 8; + } + else { + while (!($tmp & 0x80)) { + $bit_len--; + $tmp <<= 1; + } + } + return $bit_len; + } + + /** + * Calculates bitwise or of $num1 and $num2, + * starting from bit $start_pos for number $num1 + * + * @param gmp resource $num1 + * @param gmp resource $num2 + * @param int $start_pos + * @return gmp resource + * @access public + */ + function bitOr($num1, $num2, $start_pos) + { + $start_byte = intval($start_pos / 8); + $start_bit = $start_pos % 8; + $tmp1 = $this->int2bin($num1); + + $num2 = gmp_mul($num2, 1 << $start_bit); + $tmp2 = $this->int2bin($num2); + if ($start_byte < strlen($tmp1)) { + $tmp2 |= substr($tmp1, $start_byte); + $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2; + } + else { + $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2; + } + return $this->bin2int($tmp1); + } + + /** + * Returns part of number $num, starting at bit + * position $start with length $length + * + * @param gmp resource $num + * @param int start + * @param int length + * @return gmp resource + * @access public + */ + function subint($num, $start, $length) + { + $start_byte = intval($start / 8); + $start_bit = $start % 8; + $byte_length = intval($length / 8); + $bit_length = $length % 8; + if ($bit_length) { + $byte_length++; + } + $num = gmp_div($num, 1 << $start_bit); + $tmp = substr($this->int2bin($num), $start_byte, $byte_length); + $tmp = str_pad($tmp, $byte_length, "\0"); + $tmp = substr_replace($tmp, $tmp{$byte_length - 1} & chr(0xff >> (8 - $bit_length)), $byte_length - 1, 1); + return $this->bin2int($tmp); + } + + /** + * Returns name of current wrapper + * + * @return string name of current wrapper + * @access public + */ + function getWrapperName() + { + return 'GMP'; + } +} + +?> \ No newline at end of file diff --git a/plugins/OStatus/extlib/Crypt/RSA/MathLoader.php b/plugins/OStatus/extlib/Crypt/RSA/MathLoader.php new file mode 100644 index 0000000000..de6c94642f --- /dev/null +++ b/plugins/OStatus/extlib/Crypt/RSA/MathLoader.php @@ -0,0 +1,135 @@ + + * @copyright Alexander Valyalkin 2005 + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: MathLoader.php,v 1.5 2009/01/05 08:30:29 clockwerx Exp $ + * @link http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * Crypt_RSA_MathLoader class. + * + * Provides static function: + * - loadWrapper($wrapper_name) - loads RSA math wrapper with name $wrapper_name + * or most suitable wrapper if $wrapper_name == 'default' + * + * Example usage: + * // load BigInt wrapper + * $big_int_wrapper = Crypt_RSA_MathLoader::loadWrapper('BigInt'); + * + * // load BCMath wrapper + * $bcmath_wrapper = Crypt_RSA_MathLoader::loadWrapper('BCMath'); + * + * // load the most suitable wrapper + * $bcmath_wrapper = Crypt_RSA_MathLoader::loadWrapper(); + * + * @category Encryption + * @package Crypt_RSA + * @author Alexander Valyalkin + * @copyright Alexander Valyalkin 2005 + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/Crypt_RSA + * @access public + */ +class Crypt_RSA_MathLoader +{ + /** + * Loads RSA math wrapper with name $wrapper_name. + * Implemented wrappers can be found at Crypt/RSA/Math folder. + * Read docs/Crypt_RSA/docs/math_wrappers.txt for details + * + * This is a static function: + * // load BigInt wrapper + * $big_int_wrapper = &Crypt_RSA_MathLoader::loadWrapper('BigInt'); + * + * // load BCMath wrapper + * $bcmath_wrapper = &Crypt_RSA_MathLoader::loadWrapper('BCMath'); + * + * @param string $wrapper_name Name of wrapper + * + * @return object + * Reference to object of wrapper with name $wrapper_name on success + * or PEAR_Error object on error + * + * @access public + */ + function loadWrapper($wrapper_name = 'default') + { + static $math_objects = array(); + // ordered by performance. GMP is the fastest math library, BCMath - the slowest. + static $math_wrappers = array('GMP', 'BigInt', 'BCMath',); + + if (isset($math_objects[$wrapper_name])) { + /* + wrapper with name $wrapper_name is already loaded and created. + Return reference to existing copy of wrapper + */ + return $math_objects[$wrapper_name]; + } + + $err_handler = new Crypt_RSA_ErrorHandler(); + + if ($wrapper_name === 'default') { + // try to load the most suitable wrapper + $n = sizeof($math_wrappers); + for ($i = 0; $i < $n; $i++) { + $obj = Crypt_RSA_MathLoader::loadWrapper($math_wrappers[$i]); + if (!$err_handler->isError($obj)) { + // wrapper for $math_wrappers[$i] successfully loaded + // register it as default wrapper and return reference to it + return $math_objects['default'] = $obj; + } + } + // can't load any wrapper + $err_handler->pushError("can't load any wrapper for existing math libraries", CRYPT_RSA_ERROR_NO_WRAPPERS); + return $err_handler->getLastError(); + } + + $class_name = 'Crypt_RSA_Math_' . $wrapper_name; + $class_filename = dirname(__FILE__) . '/Math/' . $wrapper_name . '.php'; + + if (!is_file($class_filename)) { + $err_handler->pushError("can't find file [{$class_filename}] for RSA math wrapper [{$wrapper_name}]", CRYPT_RSA_ERROR_NO_FILE); + return $err_handler->getLastError(); + } + + include_once $class_filename; + if (!class_exists($class_name)) { + $err_handler->pushError("can't find class [{$class_name}] in file [{$class_filename}]", CRYPT_RSA_ERROR_NO_CLASS); + return $err_handler->getLastError(); + } + + // create and return wrapper object on success or PEAR_Error object on error + $obj = new $class_name; + if ($obj->errstr) { + // cannot load required extension for math wrapper + $err_handler->pushError($obj->errstr, CRYPT_RSA_ERROR_NO_EXT); + return $err_handler->getLastError(); + } + return $math_objects[$wrapper_name] = $obj; + } +} + +?> diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php new file mode 100644 index 0000000000..1ae80d70c1 --- /dev/null +++ b/plugins/OStatus/lib/magicenvelope.php @@ -0,0 +1,174 @@ +. + * + * @package StatusNet + * @author James Walker + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +require_once 'magicsig.php'; + +class MagicEnvelope +{ + const ENCODING = 'base64url'; + + const NS = 'http://salmon-protocol.org/ns/magic-env'; + + private function normalizeUser($user_id) + { + if (substr($user_id, 0, 5) == 'http:' || + substr($user_id, 0, 6) == 'https:' || + substr($user_id, 0, 5) == 'acct:') { + return $user_id; + } + + if (strpos($user_id, '@') !== FALSE) { + return 'acct:' . $user_id; + } + + return 'http://' . $user_id; + } + + public function getKeyPair($signer_uri) + { + return 'RSA.79_L2gq-TD72Nsb5yGS0r9stLLpJZF5AHXyxzWmQmlqKl276LEJEs8CppcerLcR90MbYQUwt-SX9slx40Yq3vA==.AQAB.AR-jo5KMfSISmDAT2iMs2_vNFgWRjl5rbJVvA0SpGIEWyPdCGxlPtCbTexp8-0ZEIe8a4SyjatBECH5hxgMTpw=='; + } + + + public function signMessage($text, $mimetype, $signer_uri) + { + $signer_uri = $this->normalizeUser($signer_uri); + + if (!$this->checkAuthor($text, $signer_uri)) { + return false; + } + + $signature_alg = new MagicsigRsaSha256($this->getKeyPair($signer_uri)); + $armored_text = base64_encode($text); + + return array( + 'data' => $armored_text, + 'encoding' => MagicEnvelope::ENCODING, + 'data_type' => $mimetype, + 'sig' => $signature_alg->sign($armored_text), + 'alg' => $signature_alg->getName() + ); + + + } + + public function unfold($env) + { + $dom = new DOMDocument(); + $dom->loadXML(base64_decode($env['data'])); + + if ($dom->documentElement->tagName != 'entry') { + return false; + } + + $prov = $dom->createElementNS(MagicEnvelope::NS, 'me:provenance'); + $prov->setAttribute('xmlns:me', MagicEnvelope::NS); + $data = $dom->createElementNS(MagicEnvelope::NS, 'me:data', $env['data']); + $data->setAttribute('type', $env['data_type']); + $prov->appendChild($data); + $enc = $dom->createElementNS(MagicEnvelope::NS, 'me:encoding', $env['encoding']); + $prov->appendChild($enc); + $alg = $dom->createElementNS(MagicEnvelope::NS, 'me:alg', $env['alg']); + $prov->appendChild($alg); + $sig = $dom->createElementNS(MagicEnvelope::NS, 'me:sig', $env['sig']); + $prov->appendChild($sig); + + $dom->documentElement->appendChild($prov); + + return $dom->saveXML(); + } + + public function getAuthor($text) { + $doc = new DOMDocument(); + if (!$doc->loadXML($text)) { + return FALSE; + } + + if ($doc->documentElement->tagName == 'entry') { + $authors = $doc->documentElement->getElementsByTagName('author'); + foreach ($authors as $author) { + $uris = $author->getElementsByTagName('uri'); + foreach ($uris as $uri) { + return $this->normalizeUser($uri->nodeValue); + } + } + } + } + + public function checkAuthor($text, $signer_uri) + { + return ($this->getAuthor($text) == $signer_uri); + } + + public function verify($env) + { + if ($env['alg'] != 'RSA-SHA256') { + return false; + } + + if ($env['encoding'] != MagicEnvelope::ENCODING) { + return false; + } + + $text = base64_decode($env['data']); + $signer_uri = $this->getAuthor($text); + + $verifier = new MagicsigRsaSha256($this->getKeyPair($signer_uri)); + + return $verifier->verify($env['data'], $env['sig']); + } + + public function parse($text) + { + $dom = DOMDocument::loadXML($text); + return $this->fromDom($dom); + } + + public function fromDom($dom) + { + if ($dom->documentElement->tagName == 'entry') { + $env_element = $dom->getElementsByTagNameNS(MagicEnvelope::NS, 'provenance')->item(0); + } else if ($dom->documentElement->tagName == 'me:env') { + $env_element = $dom->documentElement; + } else { + return false; + } + + $data_element = $env_element->getElementsByTagNameNS(MagicEnvelope::NS, 'data')->item(0); + + return array( + 'data' => trim($data_element->nodeValue), + 'data_type' => $data_element->getAttribute('type'), + 'encoding' => $env_element->getElementsByTagNameNS(MagicEnvelope::NS, 'encoding')->item(0)->nodeValue, + 'alg' => $env_element->getElementsByTagNameNS(MagicEnvelope::NS, 'alg')->item(0)->nodeValue, + 'sig' => $env_element->getElementsByTagNameNS(MagicEnvelope::NS, 'sig')->item(0)->nodeValue, + ); + } + +} diff --git a/plugins/OStatus/lib/magicsig.php b/plugins/OStatus/lib/magicsig.php new file mode 100644 index 0000000000..af65bad046 --- /dev/null +++ b/plugins/OStatus/lib/magicsig.php @@ -0,0 +1,159 @@ +. + * + * @package StatusNet + * @author James Walker + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +require_once 'Crypt/RSA.php'; + +interface Magicsig +{ + + public function sign($bytes); + + public function verify($signed, $signature_b64); +} + +class MagicsigRsaSha256 +{ + + public $keypair; + + public function __construct($init = null) + { + if (is_null($init)) { + $this->generate(); + } else { + $this->fromString($init); + } + } + + + public function generate($key_length = 512) + { + $keypair = new Crypt_RSA_KeyPair($key_length); + $params['public_key'] = $keypair->getPublicKey(); + $params['private_key'] = $keypair->getPrivateKey(); + + $this->keypair = new Crypt_RSA($params); + } + + + public function toString($full_pair = true) + { + $public_key = $this->keypair->_public_key; + $private_key = $this->keypair->_private_key; + + $mod = base64_url_encode($public_key->getModulus()); + $exp = base64_url_encode($public_key->getExponent()); + $private_exp = ''; + if ($full_pair && $private_key->getExponent()) { + $private_exp = '.' . base64_url_encode($private_key->getExponent()); + } + + return 'RSA.' . $mod . '.' . $exp . $private_exp; + } + + public function fromString($text) + { + // remove whitespace + $text = preg_replace('/\s+/', '', $text); + + // parse components + if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(.([^\.]+))?/', $text, $matches)) { + return false; + } + + + $mod = base64_url_decode($matches[1]); + $exp = base64_url_decode($matches[2]); + if ($matches[4]) { + $private_exp = base64_url_decode($matches[4]); + } + + $params['public_key'] = new Crypt_RSA_KEY($mod, $exp, 'public'); + if ($params['public_key']->isError()) { + $error = $params['public_key']->getLastError(); + print $error->getMessage(); + exit; + } + if ($private_exp) { + $params['private_key'] = new Crypt_RSA_KEY($mod, $private_exp, 'private'); + if ($params['private_key']->isError()) { + $error = $params['private_key']->getLastError(); + print $error->getMessage(); + exit; + } + } + + $this->keypair = new Crypt_RSA($params); + } + + public function getName() + { + return 'RSA-SHA256'; + } + + public function sign($bytes) + { + $sig = $this->keypair->createSign($bytes, null, 'sha256'); + if ($this->keypair->isError()) { + $error = $this->keypair->getLastError(); + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + } + + return $sig; + } + + public function verify($signed_bytes, $signature) + { + $result = $this->keypair->validateSign($signed_bytes, $signature, null, 'sha256'); + if ($this->keypair->isError()) { + $error = $this->keypair->getLastError(); + //common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + print $error->getMessage(); + } + return $result; + } + +} + +// Define a sha256 function for hashing +// (Crypt_RSA should really be updated to use hash() ) +function sha256($bytes) +{ + return hash('sha256', $bytes); +} + +function base64_url_encode($input) +{ + return strtr(base64_encode($input), '+/', '-_'); +} + +function base64_url_decode($input) +{ + return base64_decode(strtr($input, '-_', '+/')); +} \ No newline at end of file From 2f65fa646acc9a0739e779de9e472b9957c2e7eb Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 09:05:52 -0500 Subject: [PATCH 130/190] wiring in magicsig --- plugins/OStatus/lib/salmon.php | 17 ++++++++++++++--- plugins/OStatus/lib/salmonaction.php | 8 +++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/plugins/OStatus/lib/salmon.php b/plugins/OStatus/lib/salmon.php index df17a70068..53925dc3f4 100644 --- a/plugins/OStatus/lib/salmon.php +++ b/plugins/OStatus/lib/salmon.php @@ -34,6 +34,8 @@ class Salmon return FALSE; } + $xml = $this->createMagicEnv($xml); + $headers = array('Content-type: application/atom+xml'); try { @@ -52,16 +54,25 @@ class Salmon } - public function createMagicEnv($text, $userid) + public function createMagicEnv($text) { + $magic_env = new MagicEnvelope(); + // TODO: Should probably be getting the signer uri as an argument? + $signer_uri = $magic_env->getAuthor($text); + $env = $magic_env->signMessage($text, 'application/atom+xml', $signer_uri); + + return $magic_env->unfold($env); } - public function verifyMagicEnv($env) + public function verifyMagicEnv($dom) { + $magic_env = new MagicEnvelope(); + + $env = $magic_env->fromDom($dom); - + return $magic_env->verify($env); } } diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 4aba20cc40..09a042975d 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -54,8 +54,14 @@ class SalmonAction extends Action common_log(LOG_DEBUG, "Got invalid Salmon post: $xml"); $this->clientError(_m('Salmon post must be an Atom entry.')); } - // XXX: check the signature + // Check the signature + $salmon = new Salmon; + if (!$salmon->verifyMagicEnv($dom)) { + common_log(LOG_DEBUG, "Salmon signature verification failed."); + $this->clientError(_m('Salmon signature verification failed.')); + } + $this->act = new Activity($dom->documentElement); return true; } From 8ccc9e2c386824c71aca2da7ae311d2787338483 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 17:03:28 +0100 Subject: [PATCH 131/190] Added before and after event hooks for subscriptions content --- EVENTS.txt | 6 +++++ actions/subscriptions.php | 47 ++++++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index d3c2fb7bf6..c387274c03 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -763,3 +763,9 @@ EndFindMentions: end finding mentions in a block of text has 'mentioned' (array of mentioned profiles), 'url' (url to link as), 'title' (title of the link), 'position' (position of the text to replace), 'text' (text to replace) + +StartShowSubscriptionsContent: before showing the subscriptions content +- $action: the current action + +EndShowSubscriptionsContent: after showing the subscriptions content +- $action: the current action diff --git a/actions/subscriptions.php b/actions/subscriptions.php index 0ef31aa9f1..ba6171ef4c 100644 --- a/actions/subscriptions.php +++ b/actions/subscriptions.php @@ -79,32 +79,37 @@ class SubscriptionsAction extends GalleryAction function showContent() { - parent::showContent(); + if (Event::handle('StartShowSubscriptionsContent', array($this))) { + parent::showContent(); - $offset = ($this->page-1) * PROFILES_PER_PAGE; - $limit = PROFILES_PER_PAGE + 1; + $offset = ($this->page-1) * PROFILES_PER_PAGE; + $limit = PROFILES_PER_PAGE + 1; - $cnt = 0; + $cnt = 0; - if ($this->tag) { - $subscriptions = $this->user->getTaggedSubscriptions($this->tag, $offset, $limit); - } else { - $subscriptions = $this->user->getSubscriptions($offset, $limit); - } - - if ($subscriptions) { - $subscriptions_list = new SubscriptionsList($subscriptions, $this->user, $this); - $cnt = $subscriptions_list->show(); - if (0 == $cnt) { - $this->showEmptyListMessage(); + if ($this->tag) { + $subscriptions = $this->user->getTaggedSubscriptions($this->tag, $offset, $limit); + } else { + $subscriptions = $this->user->getSubscriptions($offset, $limit); } + + if ($subscriptions) { + $subscriptions_list = new SubscriptionsList($subscriptions, $this->user, $this); + $cnt = $subscriptions_list->show(); + if (0 == $cnt) { + $this->showEmptyListMessage(); + } + } + + $subscriptions->free(); + + $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, + $this->page, 'subscriptions', + array('nickname' => $this->user->nickname)); + + + Event::handle('EndShowSubscriptionsContent', array($this)); } - - $subscriptions->free(); - - $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, - $this->page, 'subscriptions', - array('nickname' => $this->user->nickname)); } function showScripts() From 5a6967db6cbe0e864c8d542700008bba99a7b095 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Feb 2010 11:03:56 -0500 Subject: [PATCH 132/190] clear the site owner when profile changes --- actions/profilesettings.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/actions/profilesettings.php b/actions/profilesettings.php index 0d67778791..161e35b111 100644 --- a/actions/profilesettings.php +++ b/actions/profilesettings.php @@ -285,6 +285,10 @@ class ProfilesettingsAction extends AccountSettingsAction } else { // Re-initialize language environment if it changed common_init_language(); + // Clear the site owner, in case nickname changed + if ($user->hasRole(Profile_role::OWNER)) { + User::blow('user:site_owner'); + } } } From e6ce04cbce08b9f7d0d74f6fbf86e199af8b865d Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 17:05:43 +0100 Subject: [PATCH 133/190] Generalised Subscription XHR dialogbox --- plugins/OStatus/js/ostatus.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 6717955582..4b4c329102 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -1,14 +1,15 @@ SN.U.DialogBox = { Subscribe: function(a) { - var f = a.parent().find('#form_ostatus_connect'); + var f = a.parent().find('.form_settings'); if (f.length > 0) { f.show(); } else { + a[0].href = (a[0].href.match(/[\\?]/) == null) ? a[0].href+'?' : a[0].href+'&'; $.ajax({ type: 'GET', dataType: 'xml', - url: a[0].href+'&ajax=1', + url: a[0].href+'ajax=1', beforeSend: function(formData) { a.addClass('processing'); }, @@ -19,7 +20,7 @@ SN.U.DialogBox = { if (typeof($('form', data)[0]) != 'undefined') { a.after(document._importNode($('form', data)[0], true)); - var form = a.parent().find('#form_ostatus_connect'); + var form = a.parent().find('.form_settings'); form .addClass('dialogbox') @@ -40,6 +41,7 @@ SN.U.DialogBox = { }); form.find('#acct').focus(); + form.find('#profile').focus(); } a.removeClass('processing'); @@ -50,11 +52,9 @@ SN.U.DialogBox = { }; SN.Init.Subscribe = function() { - $('.entity_subscribe a').live('click', function() { SN.U.DialogBox.Subscribe($(this)); return false; }); + $('.entity_subscribe .entity_remote_subscribe').live('click', function() { SN.U.DialogBox.Subscribe($(this)); return false; }); }; $(document).ready(function() { - if ($('.entity_subscribe .entity_remote_subscribe').length > 0) { - SN.Init.Subscribe(); - } + SN.Init.Subscribe(); }); From 3569493ba7e77a1a9f19bdbbf3f2d5f262ea8484 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 17:07:48 +0100 Subject: [PATCH 134/190] Added link to Subscriptions page to XHR get the ostatus sub form --- plugins/OStatus/OStatusPlugin.php | 17 ++++++++++++ plugins/OStatus/actions/ostatussub.php | 19 +++++++++++--- plugins/OStatus/theme/base/css/ostatus.css | 30 +++++++++++++++++----- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 3ac2bb87d7..0b0317316c 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -497,4 +497,21 @@ class OStatusPlugin extends Plugin } return true; } + + function onStartShowSubscriptionsContent($action) + { + $user = common_current_user(); + if ($user && ($user->id == $action->profile->id)) { + $action->elementStart('div', 'entity_actions'); + $action->elementStart('p', array('id' => 'entity_remote_subscribe', + 'class' => 'entity_subscribe')); + $action->element('a', array('href' => common_local_url('ostatussub'), + 'class' => 'entity_remote_subscribe') + , _m('Subscribe to remote user')); + $action->elementEnd('p'); + $action->elementEnd('div'); + } + + return true; + } } diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 8cb8e2ae7c..95dec19afc 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -55,7 +55,20 @@ class OStatusSubAction extends Action function showForm($error=null) { $this->error = $error; - $this->showPage(); + if ($this->boolean('ajax')) { + header('Content-Type: text/xml;charset=utf-8'); + $this->xw->startDocument('1.0', 'UTF-8'); + $this->elementStart('html'); + $this->elementStart('head'); + $this->element('title', null, _m('Subscribe to user')); + $this->elementEnd('head'); + $this->elementStart('body'); + $this->showContent(); + $this->elementEnd('body'); + $this->elementEnd('html'); + } else { + $this->showPage(); + } } function showPageNotice() @@ -81,7 +94,7 @@ class OStatusSubAction extends Action $profile = $user->getProfile(); $this->elementStart('form', array('method' => 'post', - 'id' => 'ostatus_sub', + 'id' => 'form_ostatus_sub', 'class' => 'form_settings', 'action' => common_local_url('ostatussub'))); @@ -141,7 +154,7 @@ class OStatusSubAction extends Action if ($this->profile_uri) { $this->validateAndPreview(); } else { - $this->showPage(); + $this->showForm(); } } } diff --git a/plugins/OStatus/theme/base/css/ostatus.css b/plugins/OStatus/theme/base/css/ostatus.css index 9bc90a7315..feeeb47d38 100644 --- a/plugins/OStatus/theme/base/css/ostatus.css +++ b/plugins/OStatus/theme/base/css/ostatus.css @@ -7,24 +7,42 @@ * @link http://status.net/ */ -#form_ostatus_connect.dialogbox { +#form_ostatus_connect.dialogbox, +#form_ostatus_sub.dialogbox { width:70%; background-image:none; } -#form_ostatus_connect.dialogbox .form_data label { +#form_ostatus_sub.dialogbox { +width:65%; +} +#form_ostatus_connect.dialogbox .form_data label, +#form_ostatus_sub.dialogbox .form_data label { width:34%; } -#form_ostatus_connect.dialogbox .form_data input { +#form_ostatus_connect.dialogbox .form_data input, +#form_ostatus_sub.dialogbox .form_data input { width:57%; } -#form_ostatus_connect.dialogbox .form_data .form_guide { +#form_ostatus_connect.dialogbox .form_data .form_guide, +#form_ostatus_sub.dialogbox .form_data .form_guide { margin-left:36%; } -#form_ostatus_connect.dialogbox #ostatus_nickname { +#form_ostatus_connect.dialogbox #ostatus_nickname, +#form_ostatus_sub.dialogbox #ostatus_nickname { display:none; } -#form_ostatus_connect.dialogbox .submit_dialogbox { +#form_ostatus_connect.dialogbox .submit_dialogbox, +#form_ostatus_sub.dialogbox .submit_dialogbox { min-width:96px; } + +#subscriptions #entity_remote_subscribe { +padding:0; +float:right; +} + +#subscriptions .entity_remote_subscribe { +float:right; +} From 2b16532ffb77d683d32ca6a399b80949d7e6b1e4 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 22 Feb 2010 10:03:34 -0800 Subject: [PATCH 135/190] OStatus: use 'profile' consistently as param on ostatussub and ostatusinit to help us stay sane. --- plugins/OStatus/actions/ostatusinit.php | 28 +++++++++++++++---------- plugins/OStatus/js/ostatus.js | 1 - 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/plugins/OStatus/actions/ostatusinit.php b/plugins/OStatus/actions/ostatusinit.php index abd8cb5419..3f2f6368f6 100644 --- a/plugins/OStatus/actions/ostatusinit.php +++ b/plugins/OStatus/actions/ostatusinit.php @@ -29,7 +29,7 @@ class OStatusInitAction extends Action { var $nickname; - var $acct; + var $profile; var $err; function prepare($args) @@ -41,8 +41,11 @@ class OStatusInitAction extends Action return false; } - $this->nickname = $this->trimmed('nickname'); - $this->acct = $this->trimmed('acct'); + // Local user the remote wants to subscribe to + $this->nickname = $this->trimmed('nickname'); + + // Webfinger or profile URL of the remote user + $this->profile = $this->trimmed('profile'); return true; } @@ -100,7 +103,7 @@ class OStatusInitAction extends Action _m('Nickname of the user you want to follow')); $this->elementEnd('li'); $this->elementStart('li', array('id' => 'ostatus_profile')); - $this->input('acct', _m('Profile Account'), $this->acct, + $this->input('profile', _m('Profile Account'), $this->profile, _m('Your account id (i.e. user@identi.ca)')); $this->elementEnd('li'); $this->elementEnd('ul'); @@ -112,15 +115,17 @@ class OStatusInitAction extends Action function ostatusConnect() { $opts = array('allowed_schemes' => array('http', 'https', 'acct')); - if (Validate::uri($this->acct, $opts)) { - $bits = parse_url($this->acct); + if (Validate::uri($this->profile, $opts)) { + $bits = parse_url($this->profile); if ($bits['scheme'] == 'acct') { $this->connectWebfinger($bits['path']); } else { - $this->connectProfile($this->acct); + $this->connectProfile($this->profile); } - } elseif (strpos($this->acct, '@') !== false) { - $this->connectWebfinger($this->acct); + } elseif (strpos($this->profile, '@') !== false) { + $this->connectWebfinger($this->profile); + } else { + $this->clientError(_m("Must provide a remote profile.")); } } @@ -140,12 +145,12 @@ class OStatusInitAction extends Action $target_profile = common_local_url('userbyid', array('id' => $user->id)); $url = $w->applyTemplate($link['template'], $target_profile); - + common_log(LOG_INFO, "Sending remote subscriber $acct to $url"); common_redirect($url, 303); } } - + $this->clientError(_m("Couldn't confirm remote profile address.")); } function connectProfile($subscriber_profile) @@ -157,6 +162,7 @@ class OStatusInitAction extends Action $suburl = preg_replace('!^(.*)/(.*?)$!', '$1/main/ostatussub', $subscriber_profile); $suburl .= '?profile=' . urlencode($target_profile); + common_log(LOG_INFO, "Sending remote subscriber $subscriber_profile to $suburl"); common_redirect($suburl, 303); } diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 4b4c329102..0daeb1a8b0 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -40,7 +40,6 @@ SN.U.DialogBox = { return false; }); - form.find('#acct').focus(); form.find('#profile').focus(); } From 85cb850cd5fe4b2edd61a86c6020f246f71e8306 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 19:13:30 +0100 Subject: [PATCH 136/190] Set and reuse a cookie with own profile value at a StatusNet instance --- plugins/OStatus/js/ostatus.js | 45 ++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 0daeb1a8b0..dc1925cb93 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -1,3 +1,36 @@ +SN.C.S.StatusNetInstance = 'StatusNetInstance'; + +SN.U.StatusNetInstance = { + Set: function(value) { + $.cookie( + SN.C.S.StatusNetInstance, + JSON.stringify(value), + { + path: '/', + expires: SN.U.GetFullYear(2029, 0, 1) + }); + }, + + Get: function() { + var cookieValue = $.cookie(SN.C.S.StatusNetInstance); + if (cookieValue !== null) { + return JSON.parse(cookieValue); + } + return null; + }, + + Delete: function() { + $.cookie(SN.C.S.StatusNetInstance, null); + } +}; + +SN.Init.OStatusCookie = function() { + if (SN.U.StatusNetInstance.Get() === null) { + SN.C.I.OStatusProfile = SN.C.I.OStatusProfile || null; + SN.U.StatusNetInstance.Set({profile: SN.C.I.OStatusProfile}); + } +}; + SN.U.DialogBox = { Subscribe: function(a) { var f = a.parent().find('.form_settings'); @@ -41,13 +74,23 @@ SN.U.DialogBox = { }); form.find('#profile').focus(); + + if (form.attr('id') == 'form_ostatus_connect') { + SN.Init.OStatusCookie(); + form.find('#profile').val(SN.U.StatusNetInstance.Get().profile) + + form.find("[type=submit]").bind('click', function() { + SN.U.StatusNetInstance.Set({profile: form.find('#profile').val()}); + return true; + }); + } } a.removeClass('processing'); } }); } - } + }, }; SN.Init.Subscribe = function() { From 3ed379613598645f75a402baa2c4abcf78984639 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 19:18:32 +0100 Subject: [PATCH 137/190] Added licensing info and a note about migrating --- plugins/OStatus/js/ostatus.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index dc1925cb93..5521583de2 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -1,3 +1,29 @@ +/* + * StatusNet - a distributed open-source microblogging tool + * Copyright (C) 2010, StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * @category OStatus UI interaction + * @package StatusNet + * @author Sarven Capadisli + * @copyright 2010 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/ + * @note Everything in here should eventually migrate over to /js/util.js's SN. + */ + SN.C.S.StatusNetInstance = 'StatusNetInstance'; SN.U.StatusNetInstance = { From a1549ebf87b7c1629c23704b1ec733c1e7c2a57d Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 19:36:03 +0100 Subject: [PATCH 138/190] Minor JSLinting --- plugins/OStatus/js/ostatus.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 5521583de2..473f1540a4 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -64,7 +64,7 @@ SN.U.DialogBox = { f.show(); } else { - a[0].href = (a[0].href.match(/[\\?]/) == null) ? a[0].href+'?' : a[0].href+'&'; + a[0].href = (a[0].href.match(/[\\?]/) === null) ? a[0].href+'?' : a[0].href+'&'; $.ajax({ type: 'GET', dataType: 'xml', @@ -103,7 +103,7 @@ SN.U.DialogBox = { if (form.attr('id') == 'form_ostatus_connect') { SN.Init.OStatusCookie(); - form.find('#profile').val(SN.U.StatusNetInstance.Get().profile) + form.find('#profile').val(SN.U.StatusNetInstance.Get().profile); form.find("[type=submit]").bind('click', function() { SN.U.StatusNetInstance.Set({profile: form.find('#profile').val()}); From 7e8c3ea418796152151a5780e52dd095ca4e114b Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 19:37:42 +0100 Subject: [PATCH 139/190] Removed extra comma --- plugins/OStatus/js/ostatus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 473f1540a4..8ba424a530 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -116,7 +116,7 @@ SN.U.DialogBox = { } }); } - }, + } }; SN.Init.Subscribe = function() { From 06f155c02df91ae81eb4401c738815ee46b802a6 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 22 Feb 2010 09:43:27 -0800 Subject: [PATCH 140/190] OStatus: initial hookup of remote group membership (notice delivery not yet working quite right) - added a temp config var to disable salmon magic signatures until they're working consistently --- plugins/OStatus/OStatusPlugin.php | 93 ++++++++++- plugins/OStatus/actions/groupsalmon.php | 77 ++++++++- plugins/OStatus/actions/ostatussub.php | 2 +- plugins/OStatus/classes/Ostatus_profile.php | 169 +++++++++++++++----- plugins/OStatus/lib/activity.php | 6 + plugins/OStatus/lib/salmon.php | 21 ++- plugins/OStatus/lib/salmonaction.php | 23 ++- 7 files changed, 336 insertions(+), 55 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 7c6c0c69f3..061ed4bd1b 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -211,7 +211,7 @@ class OStatusPlugin extends Plugin // FIXME: this needs to go out in a queue handler - $xml = ''; + $xml = ''; $xml .= $notice->asAtomEntry(true, true); $salmon = new Salmon(); @@ -402,6 +402,97 @@ class OStatusPlugin extends Plugin return true; } + /** + * When one of our local users tries to join a remote group, + * notify the remote server. If the notification is rejected, + * deny the join. + * + * @param User_group $group + * @param User $user + * + * @return mixed hook return value + */ + + function onStartJoinGroup($group, $user) + { + $oprofile = Ostatus_profile::staticGet('group_id', $group->id); + if ($oprofile) { + $member = Profile::staticGet($user->id); + + $act = new Activity(); + $act->id = TagURI::mint('join:%d:%d:%s', + $member->id, + $group->id, + common_date_iso8601(time())); + + $act->actor = ActivityObject::fromProfile($member); + $act->verb = ActivityVerb::JOIN; + $act->object = $oprofile->asActivityObject(); + + $act->time = time(); + $act->title = _m("Join"); + $act->content = sprintf(_m("%s has joined group %s."), + $member->getBestName(), + $oprofile->getBestName()); + + if ($oprofile->notifyActivity($act)) { + return true; + } else { + throw new ServerException(_m("Failed joining remote group.")); + } + } + } + + /** + * When one of our local users leaves a remote group, notify the remote + * server. + * + * @fixme Might be good to schedule a resend of the leave notification + * if it failed due to a transitory error. We've canceled the local + * membership already anyway, but if the remote server comes back up + * it'll be left with a stray membership record. + * + * @param User_group $group + * @param User $user + * + * @return mixed hook return value + */ + + function onEndLeaveGroup($group, $user) + { + $oprofile = Ostatus_profile::staticGet('group_id', $group->id); + if ($oprofile) { + // Drop the PuSH subscription if there are no other subscribers. + + $members = $group->getMembers(0, 1); + if ($members->N == 0) { + common_log(LOG_INFO, "Unsubscribing from now-unused group feed $oprofile->feeduri"); + $oprofile->unsubscribe(); + } + + + $member = Profile::staticGet($user->id); + + $act = new Activity(); + $act->id = TagURI::mint('leave:%d:%d:%s', + $member->id, + $group->id, + common_date_iso8601(time())); + + $act->actor = ActivityObject::fromProfile($member); + $act->verb = ActivityVerb::LEAVE; + $act->object = $oprofile->asActivityObject(); + + $act->time = time(); + $act->title = _m("Leave"); + $act->content = sprintf(_m("%s has left group %s."), + $member->getBestName(), + $oprofile->getBestName()); + + $oprofile->notifyActivity($act); + } + } + /** * Notify remote users when their notices get favorited. * diff --git a/plugins/OStatus/actions/groupsalmon.php b/plugins/OStatus/actions/groupsalmon.php index 64ae9f3cc0..2e4fe94436 100644 --- a/plugins/OStatus/actions/groupsalmon.php +++ b/plugins/OStatus/actions/groupsalmon.php @@ -88,21 +88,96 @@ class GroupsalmonAction extends SalmonAction * Save a subscription relationship for them. */ + /** + * Postel's law: consider a "follow" notification as a "join". + */ function handleFollow() { - $this->handleJoin(); // ??? + $this->handleJoin(); } + /** + * Postel's law: consider an "unfollow" notification as a "leave". + */ function handleUnfollow() { + $this->handleLeave(); } /** * A remote user joined our group. + * @fixme move permission checks and event call into common code, + * currently we're doing the main logic in joingroup action + * and so have to repeat it here. */ function handleJoin() { + $oprofile = $this->ensureProfile(); + if (!$oprofile) { + $this->clientError(_m("Can't read profile to set up group membership.")); + } + if ($oprofile->isGroup()) { + $this->clientError(_m("Groups can't join groups.")); + } + + common_log(LOG_INFO, "Remote profile {$oprofile->uri} joining local group {$this->group->nickname}"); + $profile = $oprofile->localProfile(); + + if ($profile->isMember($this->group)) { + // Already a member; we'll take it silently to aid in resolving + // inconsistencies on the other side. + return true; + } + + if (Group_block::isBlocked($this->group, $profile)) { + $this->clientError(_('You have been blocked from that group by the admin.'), 403); + return false; + } + + try { + // @fixme that event currently passes a user from main UI + // Event should probably move into Group_member::join + // and take a Profile object. + // + //if (Event::handle('StartJoinGroup', array($this->group, $profile))) { + Group_member::join($this->group->id, $profile->id); + //Event::handle('EndJoinGroup', array($this->group, $profile)); + //} + } catch (Exception $e) { + $this->serverError(sprintf(_m('Could not join remote user %1$s to group %2$s.'), + $oprofile->uri, $this->group->nickname)); + } + } + + /** + * A remote user left our group. + */ + + function handleLeave() + { + $oprofile = $this->ensureProfile(); + if (!$oprofile) { + $this->clientError(_m("Can't read profile to cancel group membership.")); + } + if ($oprofile->isGroup()) { + $this->clientError(_m("Groups can't join groups.")); + } + + common_log(LOG_INFO, "Remote profile {$oprofile->uri} leaving local group {$this->group->nickname}"); + $profile = $oprofile->localProfile(); + + try { + // @fixme event needs to be refactored as above + //if (Event::handle('StartLeaveGroup', array($this->group, $profile))) { + Group_member::leave($this->group->id, $profile->id); + //Event::handle('EndLeaveGroup', array($this->group, $profile)); + //} + } catch (Exception $e) { + $this->serverError(sprintf(_m('Could not remove remote user %1$s from group %2$s.'), + $oprofile->uri, $this->group->nickname)); + return; + } } } diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 95dec19afc..592ae387ea 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -248,7 +248,7 @@ class OStatusSubAction extends Action $group = $this->oprofile->localGroup(); if ($user->isMember($group)) { $this->showForm(_m('Already a member!')); - } elseif (Group_member::join($this->profile->group_id, $user->id)) { + } elseif (Group_member::join($this->oprofile->group_id, $user->id)) { $this->showForm(_m('Joined remote group!')); } else { $this->showForm(_m('Remote group join failed!')); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 0e12f8fc6e..c0e39add8f 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -137,12 +137,49 @@ class Ostatus_profile extends Memcached_DataObject return null; } + /** + * Returns an ActivityObject describing this remote user or group profile. + * Can then be used to generate Atom chunks. + * + * @return ActivityObject + */ + function asActivityObject() + { + if ($this->isGroup()) { + $object = new ActivityObject(); + $object->type = 'http://activitystrea.ms/schema/1.0/group'; + $object->id = $this->uri; + $self = $this->localGroup(); + + // @fixme put a standard getAvatar() interface on groups too + if ($self->homepage_logo) { + $object->avatar = $self->homepage_logo; + $map = array('png' => 'image/png', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'gif' => 'image/gif'); + $extension = pathinfo(parse_url($avatarHref, PHP_URL_PATH), PATHINFO_EXTENSION); + if (isset($map[$extension])) { + // @fixme this ain't used/saved yet + $object->avatarType = $map[$extension]; + } + } + + $object->link = $this->uri; // @fixme accurate? + return $object; + } else { + return ActivityObject::fromProfile($this->localProfile()); + } + } + /** * Returns an XML string fragment with profile information as an * Activity Streams noun object with the given element type. * * Assumes that 'activity' namespace has been previously defined. * + * @fixme replace with wrappers on asActivityObject when it's got everything. + * * @param string $element one of 'actor', 'subject', 'object', 'target' * @return string */ @@ -202,11 +239,19 @@ class Ostatus_profile extends Memcached_DataObject } /** - * Damn dirty hack! + * @return boolean true if this is a remote group */ function isGroup() { - return (strpos($this->feeduri, '/groups/') !== false); + if ($this->profile_id && !$this->group_id) { + return false; + } else if ($this->group_id && !$this->profile_id) { + return true; + } else if ($this->group_id && $this->profile_id) { + throw new ServerException("Invalid ostatus_profile state: both group and profile IDs set for $this->uri"); + } else { + throw new ServerException("Invalid ostatus_profile state: both group and profile IDs empty for $this->uri"); + } } /** @@ -353,22 +398,24 @@ class Ostatus_profile extends Memcached_DataObject common_log(LOG_INFO, "Posting to Salmon endpoint $this->salmonuri: $xml"); $salmon = new Salmon(); // ? - $salmon->post($this->salmonuri, $xml); + return $salmon->post($this->salmonuri, $xml); } + return false; } public function notifyActivity($activity) { if ($this->salmonuri) { - $xml = $activity->asString(true); + $xml = '' . + $activity->asString(true); $salmon = new Salmon(); // ? - $salmon->post($this->salmonuri, $xml); + return $salmon->post($this->salmonuri, $xml); } - return; + return false; } function getBestName() @@ -597,10 +644,23 @@ class Ostatus_profile extends Memcached_DataObject */ protected function updateAvatar($url) { + if ($this->isGroup()) { + $self = $this->localGroup(); + } else { + $self = $this->localProfile(); + } + if (!$self) { + throw new ServerException(sprintf( + _m("Tried to update avatar for unsaved remote profile %s"), + $this->uri)); + } + // @fixme this should be better encapsulated // ripped from oauthstore.php (for old OMB client) $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); - copy($url, $temp_filename); + if (!copy($url, $temp_filename)) { + throw new ServerException(sprintf(_m("Unable to fetch avatar from %s"), $url)); + } if ($this->isGroup()) { $id = $this->group_id; @@ -614,13 +674,7 @@ class Ostatus_profile extends Memcached_DataObject null, common_timestamp()); rename($temp_filename, Avatar::path($filename)); - if ($this->isGroup()) { - $group = $this->localGroup(); - $group->setOriginal($filename); - } else { - $profile = $this->localProfile(); - $profile->setOriginal($filename); - } + $self->setOriginal($filename); } protected static function getActivityObjectAvatar($object) @@ -747,6 +801,18 @@ class Ostatus_profile extends Memcached_DataObject self::createActivityObjectProfile($actor, $feeduri, $salmonuri); } + /** + * Create local ostatus_profile and profile/user_group entries for + * the provided remote user or group. + * + * @param ActivityObject $object + * @param string $feeduri + * @param string $salmonuri + * @param array $hints + * + * @fixme fold $feeduri/$salmonuri into $hints + * @return Ostatus_profile + */ protected static function createActivityObjectProfile($object, $feeduri=null, $salmonuri=null, $hints=array()) { $homeuri = $object->id; @@ -784,46 +850,65 @@ class Ostatus_profile extends Memcached_DataObject } } - $profile = new Profile(); - $profile->nickname = $nickname; - $profile->fullname = $object->title; - if (!empty($object->link)) { - $profile->profileurl = $object->link; - } else if (array_key_exists('profileurl', $hints)) { - $profile->profileurl = $hints['profileurl']; - } - $profile->created = common_sql_now(); - - // @fixme bio - // @fixme tags/categories - // @fixme location? - // @todo tags from categories - // @todo lat/lon/location? - - $profile_id = $profile->insert(); - - if (!$profile_id) { - throw new ServerException("Can't save local profile"); - } - - // @fixme either need to do feed discovery here - // or need to split out some of the feed stuff - // so we can leave it empty until later. - $oprofile = new Ostatus_profile(); $oprofile->uri = $homeuri; $oprofile->feeduri = $feeduri; $oprofile->salmonuri = $salmonuri; - $oprofile->profile_id = $profile_id; $oprofile->created = common_sql_now(); $oprofile->modified = common_sql_now(); + if ($object->type == ActivityObject::PERSON) { + $profile = new Profile(); + $profile->nickname = $nickname; + $profile->fullname = $object->title; + if (!empty($object->link)) { + $profile->profileurl = $object->link; + } else if (array_key_exists('profileurl', $hints)) { + $profile->profileurl = $hints['profileurl']; + } + $profile->created = common_sql_now(); + + // @fixme bio + // @fixme tags/categories + // @fixme location? + // @todo tags from categories + // @todo lat/lon/location? + + $oprofile->profile_id = $profile->insert(); + + if (!$oprofile->profile_id) { + throw new ServerException("Can't save local profile"); + } + } else { + $group = new User_group(); + $group->nickname = $nickname; + $group->fullname = $object->title; + // @fixme no canonical profileurl; using homepage instead for now + $group->homepage = $homeuri; + $group->created = common_sql_now(); + + // @fixme homepage + // @fixme bio + // @fixme tags/categories + // @fixme location? + // @todo tags from categories + // @todo lat/lon/location? + + $oprofile->group_id = $group->insert(); + + if (!$oprofile->group_id) { + throw new ServerException("Can't save local profile"); + } + } + $ok = $oprofile->insert(); if ($ok) { - $oprofile->updateAvatar($avatar); + if ($avatar) { + $oprofile->updateAvatar($avatar); + } return $oprofile; } else { throw new ServerException("Can't save OStatus profile"); diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index a26248f199..6cb9881bf6 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -367,6 +367,9 @@ class ActivityObject return $object; } + /** + * @fixme missing avatar, bio info, etc + */ static function fromProfile($profile) { $object = new ActivityObject(); @@ -379,6 +382,9 @@ class ActivityObject return $object; } + /** + * @fixme missing avatar, bio info, etc + */ function asString($tag='activity:object') { $xs = new XMLStringer(true); diff --git a/plugins/OStatus/lib/salmon.php b/plugins/OStatus/lib/salmon.php index 53925dc3f4..b5f178cc6a 100644 --- a/plugins/OStatus/lib/salmon.php +++ b/plugins/OStatus/lib/salmon.php @@ -28,15 +28,26 @@ */ class Salmon { + /** + * Sign and post the given Atom entry as a Salmon message. + * + * @fixme pass through the actor for signing? + * + * @param string $endpoint_uri + * @param string $xml + * @return boolean success + */ public function post($endpoint_uri, $xml) { if (empty($endpoint_uri)) { - return FALSE; + return false; } - $xml = $this->createMagicEnv($xml); - - $headers = array('Content-type: application/atom+xml'); + if (!common_config('ostatus', 'skip_signatures')) { + $xml = $this->createMagicEnv($xml); + } + + $headers = array('Content-Type: application/atom+xml'); try { $client = new HTTPClient(); @@ -51,7 +62,7 @@ class Salmon $response->getStatus() . ': ' . $response->getBody()); return false; } - + return true; } public function createMagicEnv($text) diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 09a042975d..83cf0b8f8a 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -41,7 +41,7 @@ class SalmonAction extends Action $this->clientError(_('This method requires a POST.')); } - if ($_SERVER['CONTENT_TYPE'] != 'application/atom+xml') { + if (empty($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/atom+xml') { $this->clientError(_('Salmon requires application/atom+xml')); } @@ -57,11 +57,13 @@ class SalmonAction extends Action // Check the signature $salmon = new Salmon; - if (!$salmon->verifyMagicEnv($dom)) { - common_log(LOG_DEBUG, "Salmon signature verification failed."); - $this->clientError(_m('Salmon signature verification failed.')); + if (!common_config('ostatus', 'skip_signatures')) { + if (!$salmon->verifyMagicEnv($dom)) { + common_log(LOG_DEBUG, "Salmon signature verification failed."); + $this->clientError(_m('Salmon signature verification failed.')); + } } - + $this->act = new Activity($dom->documentElement); return true; } @@ -101,6 +103,9 @@ class SalmonAction extends Action case ActivityVerb::JOIN: $this->handleJoin(); break; + case ActivityVerb::LEAVE: + $this->handleLeave(); + break; default: throw new ClientException(_("Unimplemented.")); } @@ -154,6 +159,14 @@ class SalmonAction extends Action throw new ClientException(_("Unimplemented!")); } + /** + * Hmmmm + */ + function handleLeave() + { + throw new ClientException(_("Unimplemented!")); + } + /** * @return Ostatus_profile */ From 3c004729999f3f1a25ecb723a07af07c4b4c2bc8 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Feb 2010 22:23:37 +0100 Subject: [PATCH 141/190] Removed unnecessary assignment to SN.C.I.OStatusProfile. It can be brought back in the future if the value is to be set directly from the HTML script output. --- plugins/OStatus/js/ostatus.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 8ba424a530..148a05f6f6 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -52,8 +52,7 @@ SN.U.StatusNetInstance = { SN.Init.OStatusCookie = function() { if (SN.U.StatusNetInstance.Get() === null) { - SN.C.I.OStatusProfile = SN.C.I.OStatusProfile || null; - SN.U.StatusNetInstance.Set({profile: SN.C.I.OStatusProfile}); + SN.U.StatusNetInstance.Set({profile: null}); } }; From 3b823f8fbde531b00f9770fb214543b965851036 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 23 Feb 2010 00:27:41 +0100 Subject: [PATCH 142/190] Leaves the original URL alone and adds ? or & when it does the XHR. --- plugins/OStatus/js/ostatus.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 148a05f6f6..1fc44b21b6 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -63,11 +63,10 @@ SN.U.DialogBox = { f.show(); } else { - a[0].href = (a[0].href.match(/[\\?]/) === null) ? a[0].href+'?' : a[0].href+'&'; $.ajax({ type: 'GET', dataType: 'xml', - url: a[0].href+'ajax=1', + url: a[0].href + ((a[0].href.match(/[\\?]/) === null)?'?':'&') + 'ajax=1', beforeSend: function(formData) { a.addClass('processing'); }, From caad5859b51e8d9be87f234ebc91fdf2802816f1 Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 19:00:27 -0500 Subject: [PATCH 143/190] swapping pear error handling so Crypt_RSA can properly detect available math libraries --- plugins/OStatus/lib/magicsig.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/lib/magicsig.php b/plugins/OStatus/lib/magicsig.php index af65bad046..50eb301ab3 100644 --- a/plugins/OStatus/lib/magicsig.php +++ b/plugins/OStatus/lib/magicsig.php @@ -57,8 +57,10 @@ class MagicsigRsaSha256 $keypair = new Crypt_RSA_KeyPair($key_length); $params['public_key'] = $keypair->getPublicKey(); $params['private_key'] = $keypair->getPrivateKey(); - + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); $this->keypair = new Crypt_RSA($params); + PEAR::popErrorHandling(); } @@ -79,6 +81,8 @@ class MagicsigRsaSha256 public function fromString($text) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + // remove whitespace $text = preg_replace('/\s+/', '', $text); @@ -86,7 +90,6 @@ class MagicsigRsaSha256 if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(.([^\.]+))?/', $text, $matches)) { return false; } - $mod = base64_url_decode($matches[1]); $exp = base64_url_decode($matches[2]); @@ -110,6 +113,7 @@ class MagicsigRsaSha256 } $this->keypair = new Crypt_RSA($params); + PEAR::popErrorHandling(); } public function getName() From d410df040684f443d14bd921c450ca464d52c9d4 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Feb 2010 00:44:45 +0000 Subject: [PATCH 144/190] OStatus group delivery initial implementation. - added rel="ostatus:attention" links for group delivery - added events for plugins to override group profile/permalink pages - pulled Notice::saveGroups up to save-time so we can override; it's relatively cheap and gives us a clean list of target groups for distrib time even with customized delivery. - fixed notice::getGroups to return group objects as expected - added some doc on new parameters to Notice::saveNew - 'groups' list of group IDs to push to in place of parsing - messages that come in via PuSH and contain local group targets are delivered to local group members - messages that come in via PuSH and contain remote group targets are delivered to local members of the remote group Todo: - handle group posts that only come through Salmon - handle conflicts in case something comes in both through Salmon and PuSH - better source verification - need a cleaner interface to look up groups by URI - need a way to handle remote groups with conflicting names --- actions/apitimelinegroup.php | 3 +- classes/Notice.php | 111 +++++++++++++++++- classes/User_group.php | 18 ++- lib/distribqueuehandler.php | 14 +-- plugins/OStatus/OStatusPlugin.php | 16 +++ plugins/OStatus/classes/Ostatus_profile.php | 75 ++++++++++-- .../OStatus/lib/hubdistribqueuehandler.php | 2 +- 7 files changed, 207 insertions(+), 32 deletions(-) diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index 1d0c4afdd0..0bb4860ea7 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -176,7 +176,8 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction $atom->addEntryFromNotices($this->notices); - $this->raw($atom->getString()); + //$this->raw($atom->getString()); + print $atom->getString(); // temp hack until PuSH feeds are redone cleanly } catch (Atom10FeedException $e) { $this->serverError( diff --git a/classes/Notice.php b/classes/Notice.php index a12839d729..754c126ed1 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -187,7 +187,14 @@ class Notice extends Memcached_DataObject * int 'location_ns' geoname namespace to interpret location_id * int 'reply_to'; notice ID this is a reply to * int 'repeat_of'; notice ID this is a repeat of - * string 'uri' permalink to notice; defaults to local notice URL + * string 'uri' unique ID for notice; defaults to local notice URL + * string 'url' permalink to notice; defaults to local notice URL + * string 'rendered' rendered HTML version of content + * array 'replies' list of profile URIs for reply delivery in + * place of extracting @-replies from content. + * array 'groups' list of group IDs to deliver to, in place of + * extracting ! tags from content + * @fixme tag override * * @return Notice * @throws ClientException @@ -342,6 +349,12 @@ class Notice extends Memcached_DataObject $notice->saveReplies(); } + if (isset($groups)) { + $notice->saveKnownGroups($groups); + } else { + $notice->saveGroups(); + } + $notice->distribute(); return $notice; @@ -692,7 +705,22 @@ class Notice extends Memcached_DataObject return $ni; } - function addToInboxes($groups, $recipients) + /** + * Adds this notice to the inboxes of each local user who should receive + * it, based on author subscriptions, group memberships, and @-replies. + * + * Warning: running a second time currently will make items appear + * multiple times in users' inboxes. + * + * @fixme make more robust against errors + * @fixme break up massive deliveries to smaller background tasks + * + * @param array $groups optional list of Group objects; + * if left empty, will be loaded from group_inbox records + * @param array $recipient optional list of reply profile ids + * if left empty, will be loaded from reply records + */ + function addToInboxes($groups=null, $recipients=null) { $ni = $this->whoGets($groups, $recipients); @@ -742,6 +770,42 @@ class Notice extends Memcached_DataObject } /** + * Record this notice to the given group inboxes for delivery. + * Overrides the regular parsing of !group markup. + * + * @param string $group_ids + * @fixme might prefer URIs as identifiers, as for replies? + * best with generalizations on user_group to support + * remote groups better. + */ + function saveKnownGroups($group_ids) + { + if (!is_array($group_ids)) { + throw new ServerException("Bad type provided to saveKnownGroups"); + } + + $groups = array(); + foreach ($group_ids as $id) { + $group = User_group::staticGet('id', $id); + if ($group) { + common_log(LOG_ERR, "Local delivery to group id $id, $group->nickname"); + $result = $this->addToGroupInbox($group); + if (!$result) { + common_log_db_error($gi, 'INSERT', __FILE__); + } + + // @fixme should we save the tags here or not? + $groups[] = clone($group); + } else { + common_log(LOG_ERR, "Local delivery to group id $id skipped, doesn't exist"); + } + } + + return $groups; + } + + /** + * Parse !group delivery and record targets into group_inbox. * @return array of Group objects */ function saveGroups() @@ -824,6 +888,19 @@ class Notice extends Memcached_DataObject return true; } + /** + * Save reply records indicating that this notice needs to be + * delivered to the local users with the given URIs. + * + * Since this is expected to be used when saving foreign-sourced + * messages, we won't deliver to any remote targets as that's the + * source service's responsibility. + * + * @fixme Unlike saveReplies() there's no mail notification here. + * Move that to distrib queue handler? + * + * @param array of unique identifier URIs for recipients + */ function saveKnownReplies($uris) { foreach ($uris as $uri) { @@ -845,6 +922,13 @@ class Notice extends Memcached_DataObject } /** + * Pull @-replies from this message's content in StatusNet markup format + * and save reply records indicating that this message needs to be + * delivered to those users. + * + * Side effect: local recipients get e-mail notifications here. + * @fixme move mail notifications to distrib? + * * @return array of integer profile IDs */ @@ -934,9 +1018,10 @@ class Notice extends Memcached_DataObject } /** - * Same calculation as saveGroups but without the saving - * @fixme merge the functions - * @return array of Group_inbox objects + * Pull list of groups this notice needs to be delivered to, + * as previously recorded by saveGroups() or saveKnownGroups(). + * + * @return array of Group objects */ function getGroups() { @@ -959,7 +1044,10 @@ class Notice extends Memcached_DataObject if ($gi->find()) { while ($gi->fetch()) { - $groups[] = clone($gi); + $group = User_group::staticGet('id', $gi->group_id); + if ($group) { + $groups[] = $group; + } } } @@ -1063,6 +1151,17 @@ class Notice extends Memcached_DataObject } } + $groups = $this->getGroups(); + + foreach ($groups as $group) { + $xs->element( + 'link', array( + 'rel' => 'ostatus:attention', + 'href' => $group->permalink() + ) + ); + } + if (!empty($this->repeat_of)) { $repeat = Notice::staticGet('id', $this->repeat_of); if (!empty($repeat)) { diff --git a/classes/User_group.php b/classes/User_group.php index 379e6b7219..1382aa407c 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -39,14 +39,24 @@ class User_group extends Memcached_DataObject function homeUrl() { - return common_local_url('showgroup', - array('nickname' => $this->nickname)); + $url = null; + if (Event::handle('StartUserGroupHomeUrl', array($this, &$url))) { + $url = common_local_url('showgroup', + array('nickname' => $this->nickname)); + } + Event::handle('EndUserGroupHomeUrl', array($this, &$url)); + return $url; } function permalink() { - return common_local_url('groupbyid', - array('id' => $this->id)); + $url = null; + if (Event::handle('StartUserGroupPermalink', array($this, &$url))) { + $url = common_local_url('groupbyid', + array('id' => $this->id)); + } + Event::handle('EndUserGroupPermalink', array($this, &$url)); + return $url; } function getNotices($offset, $limit, $since_id=null, $max_id=null) diff --git a/lib/distribqueuehandler.php b/lib/distribqueuehandler.php index c31b675c1a..dc183fb36a 100644 --- a/lib/distribqueuehandler.php +++ b/lib/distribqueuehandler.php @@ -69,19 +69,7 @@ class DistribQueueHandler } try { - $groups = $notice->saveGroups(); - } catch (Exception $e) { - $this->logit($notice, $e); - } - - try { - $recipients = $notice->getReplies(); - } catch (Exception $e) { - $this->logit($notice, $e); - } - - try { - $notice->addToInboxes($groups, $recipients); + $notice->addToInboxes(); } catch (Exception $e) { $this->logit($notice, $e); } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 061ed4bd1b..472008419a 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -591,6 +591,22 @@ class OStatusPlugin extends Plugin return true; } + function onStartUserGroupHomeUrl($group, &$url) + { + return $this->onStartUserGroupPermalink($group, &$url); + } + + function onStartUserGroupPermalink($group, &$url) + { + $oprofile = Ostatus_profile::staticGet('group_id', $group->id); + if ($oprofile) { + // @fixme this should probably be in the user_group table + // @fixme this uri not guaranteed to be a profile page + $url = $oprofile->uri; + return false; + } + } + function onStartShowSubscriptionsContent($action) { $user = common_current_user(); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index c0e39add8f..e8cc13c6c1 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -501,6 +501,7 @@ class Ostatus_profile extends Memcached_DataObject /** * Process an incoming post activity from this remote feed. * @param Activity $activity + * @fixme break up this function, it's getting nasty long */ protected function processPost($activity) { @@ -518,7 +519,6 @@ class Ostatus_profile extends Memcached_DataObject } $oprofile = $this; } - $sourceUri = $activity->object->id; $dupe = Notice::staticGet('uri', $sourceUri); @@ -555,15 +555,76 @@ class Ostatus_profile extends Memcached_DataObject } } - // @fixme ensure that groups get handled correctly + $profile = $oprofile->localProfile(); + $params['groups'] = array(); + $params['replies'] = array(); + if ($activity->context) { + foreach ($activity->context->attention as $recipient) { + $roprofile = Ostatus_profile::staticGet('uri', $recipient); + if ($roprofile) { + if ($roprofile->isGroup()) { + // Deliver to local recipients of this remote group. + // @fixme sender verification? + $params['groups'][] = $roprofile->group_id; + continue; + } else { + // Delivery to remote users is the source service's job. + continue; + } + } + + $user = User::staticGet('uri', $recipient); + if ($user) { + // An @-reply directed to a local user. + // @fixme sender verification, spam etc? + $params['replies'][] = $recipient; + continue; + } + + // @fixme we need a uri on user_group + // $group = User_group::staticGet('uri', $recipient); + $template = common_local_url('groupbyid', array('id' => '31337')); + $template = preg_quote($template, '/'); + $template = str_replace('31337', '(\d+)', $template); + common_log(LOG_DEBUG, $template); + if (preg_match("/$template/", $recipient, $matches)) { + $id = $matches[1]; + $group = User_group::staticGet('id', $id); + if ($group) { + // Deliver to all members of this local group. + // @fixme sender verification? + if ($profile->isMember($group)) { + common_log(LOG_DEBUG, "delivering to group $id $group->nickname"); + $params['groups'][] = $group->id; + } else { + common_log(LOG_DEBUG, "not delivering to group $id $group->nickname because sender $profile->nickname is not a member"); + } + continue; + } else { + common_log(LOG_DEBUG, "not delivering to missing group $id"); + } + } else { + common_log(LOG_DEBUG, "not delivering to groups for $recipient"); + } + } + } - $saved = Notice::saveNew($oprofile->localProfile()->id, - $content, - 'ostatus', - $params); + try { + $saved = Notice::saveNew($profile->id, + $content, + 'ostatus', + $params); + } catch (Exception $e) { + common_log(LOG_ERR, "Failed saving notice entry for $sourceUri: " . $e->getMessage()); + return; + } // Record which feed this came through... - Ostatus_source::saveNew($saved, $this, 'push'); + try { + Ostatus_source::saveNew($saved, $this, 'push'); + } catch (Exception $e) { + common_log(LOG_ERR, "Failed saving ostatus_source entry for $saved->notice_id: " . $e->getMessage()); + } } /** diff --git a/plugins/OStatus/lib/hubdistribqueuehandler.php b/plugins/OStatus/lib/hubdistribqueuehandler.php index 30a427e3fc..c2bd630f9c 100644 --- a/plugins/OStatus/lib/hubdistribqueuehandler.php +++ b/plugins/OStatus/lib/hubdistribqueuehandler.php @@ -36,7 +36,7 @@ class HubDistribQueueHandler extends QueueHandler $this->pushUser($notice); foreach ($notice->getGroups() as $group) { - $this->pushGroup($notice, $group->group_id); + $this->pushGroup($notice, $group->id); } return true; } From a3e800e67c8ced785a1ca6c2628cc5116ef44730 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Feb 2010 16:46:54 -0800 Subject: [PATCH 145/190] Add PoCo bits, avatar link, geo point, etc. to person activity obj output --- plugins/OStatus/lib/activity.php | 152 +++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 6 deletions(-) diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php index a26248f199..585028318d 100644 --- a/plugins/OStatus/lib/activity.php +++ b/plugins/OStatus/lib/activity.php @@ -31,10 +31,117 @@ if (!defined('STATUSNET')) { exit(1); } +class PoCoURL +{ + const TYPE = 'type'; + const VALUE = 'value'; + const PRIMARY = 'primary'; + + public $type; + public $value; + public $primary; + + function __construct($type, $value, $primary = false) + { + $this->type = $type; + $this->value = $value; + $this->primary = $primary; + } + + function asString() + { + $xs = new XMLStringer(true); + $xs->elementStart('poco:urls'); + $xs->element('poco:type', null, $this->type); + $xs->element('poco:value', null, $this->value); + if ($this->primary) { + $xs->element('poco:primary', null, 'true'); + } + $xs->elementEnd('poco:urls'); + return $xs->getString(); + } +} + +class PoCoAddress +{ + const ADDRESS = 'address'; + const FORMATTED = 'formatted'; + + public $formatted; + + function __construct($formatted) + { + if (empty($formatted)) { + return null; + } + $this->formatted = $formatted; + } + + function asString() + { + $xs = new XMLStringer(true); + $xs->elementStart('poco:address'); + $xs->element('poco:formatted', null, $this->formatted); + $xs->elementEnd('poco:address'); + return $xs->getString(); + } +} + class PoCo { const NS = 'http://portablecontacts.net/spec/1.0'; - const USERNAME = 'preferredUsername'; + + const USERNAME = 'preferredUsername'; + const NOTE = 'note'; + const URLS = 'urls'; + + public $preferredUsername; + public $note; + public $address; + public $urls = array(); + + function __construct($profile) + { + $this->preferredUsername = $profile->nickname; + + $this->note = $profile->bio; + $this->address = new PoCoAddress($profile->location); + + if (!empty($profile->homepage)) { + array_push( + $this->urls, + new PoCoURL( + 'homepage', + $profile->homepage, + true + ) + ); + } + } + + function asString() + { + $xs = new XMLStringer(true); + $xs->element( + 'poco:preferredUsername', + null, + $this->preferredUsername + ); + + if (!empty($this->note)) { + $xs->element('poco:note', null, $this->note); + } + + if (!empty($this->address)) { + $xs->raw($this->address->asString()); + } + + foreach ($this->urls as $url) { + $xs->raw($url->asString()); + } + + return $xs->getString(); + } } /** @@ -265,6 +372,7 @@ class ActivityObject public $link; public $source; public $avatar; + public $geopoint; /** * Constructor @@ -371,10 +479,17 @@ class ActivityObject { $object = new ActivityObject(); - $object->type = ActivityObject::PERSON; - $object->id = $profile->getUri(); - $object->title = $profile->getBestName(); - $object->link = $profile->profileurl; + $object->type = ActivityObject::PERSON; + $object->id = $profile->getUri(); + $object->title = $profile->getBestName(); + $object->link = $profile->profileurl; + $object->avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); + + if (isset($profile->lat) && isset($profile->lon)) { + $object->geopoint = (float)$profile->lat . ' ' . (float)$profile->lon; + } + + $object->poco = new PoCo($profile); return $object; } @@ -404,7 +519,32 @@ class ActivityObject if (!empty($this->link)) { $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html'), - $this->content); + $this->link); + } + + if ($this->type == ActivityObject::PERSON) { + $xs->element( + 'link', array( + 'type' => empty($this->avatar) ? 'image/png' : $this->avatar->mediatype, + 'rel' => 'avatar', + 'href' => empty($this->avatar) + ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) + : $this->avatar->displayUrl() + ), + '' + ); + } + + if (!empty($this->geopoint)) { + $xs->element( + 'georss:point', + null, + $this->geopoint + ); + } + + if (!empty($this->poco)) { + $xs->raw($this->poco->asString()); } $xs->elementEnd($tag); From 6a711c6cdc5d1e1b1a64e5858b12e6964a0abe9c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Feb 2010 17:10:50 -0800 Subject: [PATCH 146/190] Move ActivityObject and related stuff to core --- classes/Notice.php | 21 +----- classes/Profile.php | 78 +---------------------- {plugins/OStatus/lib => lib}/activity.php | 3 +- 3 files changed, 6 insertions(+), 96 deletions(-) rename {plugins/OStatus/lib => lib}/activity.php (99%) diff --git a/classes/Notice.php b/classes/Notice.php index a12839d729..ba8646f68e 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1119,25 +1119,8 @@ class Notice extends Memcached_DataObject */ function asActivityNoun($element) { - $xs = new XMLStringer(true); - - $xs->elementStart('activity:' . $element); - $xs->element('activity:object-type', - null, - 'http://activitystrea.ms/schema/1.0/note'); - $xs->element('id', - null, - $this->uri); - $xs->element('content', - array('type' => 'text/html'), - $this->rendered); - $xs->element('link', - array('type' => 'text/html', - 'rel' => 'alternate', - 'href' => $this->bestUrl())); - $xs->elementEnd('activity:' . $element); - - return $xs->getString(); + $noun = ActivityObject::fromNotice($this); + return $noun->asString('activity:' . $element); } function bestUrl() diff --git a/classes/Profile.php b/classes/Profile.php index 7fb2b87bc3..78223b34a1 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -801,82 +801,8 @@ class Profile extends Memcached_DataObject */ function asActivityNoun($element) { - $xs = new XMLStringer(true); - - $xs->elementStart('activity:' . $element); - $xs->element( - 'activity:object-type', - null, - 'http://activitystrea.ms/schema/1.0/person' - ); - $xs->element( - 'id', - null, - $this->getUri() - ); - - // title should contain fullname - $xs->element('title', null, $this->getBestName()); - - $xs->element('link', array('rel' => 'alternate', - 'type' => 'text/html'), - $this->profileurl); - - $xs->element('poco:preferredUsername', null, $this->nickname); - - // Portable Contacts stuff - - if (isset($this->bio)) { - - // XXX: Possible to use OpenSocial's aboutMe? - - $xs->element('poco:note', null, $this->bio); - } - - if (isset($this->homepage)) { - - $xs->elementStart('poco:urls'); - $xs->element('poco:value', null, $this->homepage); - $xs->element('poco:type', null, 'homepage'); - $xs->element('poco:primary', null, 'true'); - $xs->elementEnd('poco:urls'); - } - - if (isset($this->location)) { - $xs->elementStart('poco:address'); - $xs->element('poco:formatted', null, $this->location); - $xs->elementEnd('poco:address'); - } - - if (isset($this->lat) && isset($this->lon)) { - $this->element( - 'georss:point', - null, - (float)$this->lat . ' ' . (float)$this->lon - ); - } - - // XXX: Should we send all avatar sizes we have? I think - // cliqset does -Z - - $avatar = $this->getAvatar(AVATAR_PROFILE_SIZE); - - $xs->element( - 'link', array( - 'type' => empty($avatar) ? 'image/png' : $avatar->mediatype, - 'rel' => 'avatar', - 'href' => empty($avatar) - ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) - : $avatar->displayUrl() - ), - '' - ); - - $xs->elementEnd('activity:' . $element); - - // XXX: Add people tags with plural? - - return $xs->getString(); + $noun = ActivityObject::fromProfile($this); + return $noun->asString('activity:' . $element); } /** diff --git a/plugins/OStatus/lib/activity.php b/lib/activity.php similarity index 99% rename from plugins/OStatus/lib/activity.php rename to lib/activity.php index 585028318d..3689dac385 100644 --- a/plugins/OStatus/lib/activity.php +++ b/lib/activity.php @@ -19,9 +19,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @category OStatus + * @category Feed * @package StatusNet * @author Evan Prodromou + * @author Zach Copley * @copyright 2010 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ From 1f859e72a205807ca15cc8e22e82e8e112979de9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Feb 2010 17:47:40 -0800 Subject: [PATCH 147/190] Add activity.php to common includes --- lib/activity.php | 6 ------ lib/common.php | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/activity.php b/lib/activity.php index d91e04260c..3689dac385 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -476,9 +476,6 @@ class ActivityObject return $object; } - /** - * @fixme missing avatar, bio info, etc - */ static function fromProfile($profile) { $object = new ActivityObject(); @@ -498,9 +495,6 @@ class ActivityObject return $object; } - /** - * @fixme missing avatar, bio info, etc - */ function asString($tag='activity:object') { $xs = new XMLStringer(true); diff --git a/lib/common.php b/lib/common.php index b95cd11752..68723955ec 100644 --- a/lib/common.php +++ b/lib/common.php @@ -123,6 +123,7 @@ require_once INSTALLDIR.'/lib/util.php'; require_once INSTALLDIR.'/lib/action.php'; require_once INSTALLDIR.'/lib/mail.php'; require_once INSTALLDIR.'/lib/subs.php'; +require_once INSTALLDIR.'/lib/activity.php'; require_once INSTALLDIR.'/lib/clientexception.php'; require_once INSTALLDIR.'/lib/serverexception.php'; From 89dc6dee01b08a2dc529449e6006fe772d46b72d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Feb 2010 17:56:43 -0800 Subject: [PATCH 148/190] Add PoCo namespace to optional ns output in Notice::asAtomEntry() --- classes/Notice.php | 1 + 1 file changed, 1 insertion(+) diff --git a/classes/Notice.php b/classes/Notice.php index 92d959dc56..e8d5c45cb2 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1067,6 +1067,7 @@ class Notice extends Memcached_DataObject 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', + 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); } else { $attrs = array(); From 193448d1be53e27232477bed4d3fa7c2c6f39fbf Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Feb 2010 01:58:05 +0000 Subject: [PATCH 149/190] OStatus: cleanup on ostatussub preparing for final UI work on the remote sub/join forms. --- plugins/OStatus/actions/ostatussub.php | 397 +++++++++++++++---------- 1 file changed, 242 insertions(+), 155 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 592ae387ea..ffa88cb088 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -24,70 +24,29 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +/** + * Key UI methods: + * + * showInputForm() - form asking for a remote profile account or URL + * We end up back here on errors + * + * showPreviewForm() - surrounding form for preview-and-confirm + * previewUser() - display profile for a remote user + * previewGroup() - display profile for a remote group + * + * successUser() - redirects to subscriptions page on subscribe + * successGroup() - redirects to groups page on join + */ class OStatusSubAction extends Action { - protected $profile_uri; - protected $preview; - protected $munger; + protected $profile_uri; // provided acct: or URI of remote entity + protected $oprofile; // Ostatus_profile of remote entity, if valid /** - * Title of the page - * - * @return string Title of the page + * Show the initial form, when we haven't yet been given a valid + * remote profile. */ - - function title() - { - return _m('Authorize subscription'); - } - - /** - * Instructions for use - * - * @return instructions for use - */ - - function getInstructions() - { - return _m('You can subscribe to users from other supported sites. Paste their address or profile URI below:'); - } - - function showForm($error=null) - { - $this->error = $error; - if ($this->boolean('ajax')) { - header('Content-Type: text/xml;charset=utf-8'); - $this->xw->startDocument('1.0', 'UTF-8'); - $this->elementStart('html'); - $this->elementStart('head'); - $this->element('title', null, _m('Subscribe to user')); - $this->elementEnd('head'); - $this->elementStart('body'); - $this->showContent(); - $this->elementEnd('body'); - $this->elementEnd('html'); - } else { - $this->showPage(); - } - } - - function showPageNotice() - { - if ($this->error) { - $this->element('p', 'error', $this->error); - } - } - - /** - * Content area of the page - * - * Shows a form for associating a remote OStatus account with this - * StatusNet account. - * - * @return void - */ - - function showContent() + function showInputForm() { $user = common_current_user(); @@ -112,18 +71,167 @@ class OStatusSubAction extends Action $this->elementEnd('li'); $this->elementEnd('ul'); - if ($this->preview) { - $this->submit('subscribe', _m('Subscribe')); - } else { - $this->submit('validate', _m('Continue')); - } + $this->submit('validate', _m('Continue')); $this->elementEnd('fieldset'); $this->elementEnd('form'); + } - if ($this->preview) { - $this->previewFeed(); + /** + * Show the preview-and-confirm form. We've got a valid remote + * profile and are ready to poke it! + * + * This controls the wrapper form; actual profile display will + * be in previewUser() or previewGroup() depending on the type. + */ + function showPreviewForm() + { + $this->elementStart('form', array('method' => 'post', + 'id' => 'form_ostatus_sub', + 'class' => 'form_settings', + 'action' => + common_local_url('ostatussub'))); + + $this->hidden('token', common_session_token()); + $this->hidden('profile', $this->profile_uri); + + $this->elementStart('fieldset', array('id' => 'settings_feeds')); + + if ($this->oprofile->isGroup()) { + $this->previewGroup(); + $this->submit('subscribe', _m('Join')); + } else { + $this->previewUser(); + $this->submit('subscribe', _m('Subscribe')); + } + + + $this->elementEnd('fieldset'); + + $this->elementEnd('form'); + } + + /** + * Show a preview for a remote user's profile + */ + function previewUser() + { + $oprofile = $this->oprofile; + $profile = $oprofile->localProfile(); + + $this->text(sprintf(_m("Remote user %s"), $profile->nickname)); + // ... + } + + /** + * Show a preview for a remote group's profile + */ + function previewGroup() + { + $oprofile = $this->oprofile; + $group = $oprofile->localGroup(); + + $this->text(sprintf(_m("Remote group %s"), $group->nickname)); + // .. + } + + /** + * Redirect on successful remote user subscription + */ + function successUser() + { + $cur = common_current_user(); + $url = common_local_url('subscriptions', array('nickname' => $cur->nickname)); + common_redirect($url, 303); + } + + /** + * Redirect on successful remote group join + */ + function successGroup() + { + $cur = common_current_user(); + $url = common_local_url('usergroups', array('nickname' => $cur->nickname)); + common_redirect($url, 303); + } + + /** + * Pull data for a remote profile and check if it's valid. + * Fills out error UI string in $this->error + * Fills out $this->oprofile on success. + * + * @return boolean + */ + function validateFeed() + { + $profile_uri = trim($this->arg('profile')); + + if ($profile_uri == '') { + $this->showForm(_m('Empty remote profile URL!')); + return; + } + $this->profile_uri = $profile_uri; + + // @fixme validate, normalize bla bla + try { + $oprofile = Ostatus_profile::ensureProfile($this->profile_uri); + $this->oprofile = $oprofile; + return true; + } catch (FeedSubBadURLException $e) { + $this->error = _m('Invalid URL or could not reach server.'); + } catch (FeedSubBadResponseException $e) { + $this->error = _m('Cannot read feed; server returned error.'); + } catch (FeedSubEmptyException $e) { + $this->error = _m('Cannot read feed; server returned an empty page.'); + } catch (FeedSubBadHTMLException $e) { + $this->error = _m('Bad HTML, could not find feed link.'); + } catch (FeedSubNoFeedException $e) { + $this->error = _m('Could not find a feed linked from this URL.'); + } catch (FeedSubUnrecognizedTypeException $e) { + $this->error = _m('Not a recognized feed type.'); + } catch (FeedSubException $e) { + // Any new ones we forgot about + $this->error = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage()); + } + + return false; + } + + /** + * Attempt to finalize subscription. + * validateFeed must have been run first. + * + * Calls showForm on failure or successUser/successGroup on success. + */ + function saveFeed() + { + // And subscribe the current user to the local profile + $user = common_current_user(); + + if (!$this->oprofile->subscribe()) { + $this->showForm(_m("Failed to set up server-to-server subscription.")); + return; + } + + if ($this->oprofile->isGroup()) { + $group = $this->oprofile->localGroup(); + if ($user->isMember($group)) { + $this->showForm(_m('Already a member!')); + } elseif (Group_member::join($this->oprofile->group_id, $user->id)) { + $this->successGroup(); + } else { + $this->showForm(_m('Remote group join failed!')); + } + } else { + $local = $this->oprofile->localProfile(); + if ($user->isSubscribed($local)) { + $this->showForm(_m('Already subscribed!')); + } elseif ($this->oprofile->subscribeLocalToRemote($user)) { + $this->successUser(); + } else { + $this->showForm(_m('Remote subscription failed!')); + } } } @@ -145,28 +253,26 @@ class OStatusSubAction extends Action return true; } + /** + * Handle the submission. + */ function handle($args) { parent::handle($args); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->handlePost(); } else { - if ($this->profile_uri) { - $this->validateAndPreview(); - } else { - $this->showForm(); + if ($this->arg('profile')) { + $this->validateFeed(); } + $this->showForm(); } } + /** * Handle posts to this form * - * Based on the button that was pressed, muxes out to other functions - * to do the actual task requested. - * - * All sub-functions reload the form with a message -- success or failure. - * * @return void */ @@ -180,103 +286,84 @@ class OStatusSubAction extends Action return; } - if ($this->arg('validate')) { - $this->validateAndPreview(); - } else if ($this->arg('subscribe')) { - $this->saveFeed(); + if ($this->validateFeed()) { + if ($this->arg('subscribe')) { + $this->saveFeed(); + return; + } + } + $this->showForm(); + } + + /** + * Show the appropriate form based on our input state. + */ + function showForm($err=null) + { + if ($err) { + $this->error = $err; + } + if ($this->boolean('ajax')) { + header('Content-Type: text/xml;charset=utf-8'); + $this->xw->startDocument('1.0', 'UTF-8'); + $this->elementStart('html'); + $this->elementStart('head'); + $this->element('title', null, _m('Subscribe to user')); + $this->elementEnd('head'); + $this->elementStart('body'); + $this->showContent(); + $this->elementEnd('body'); + $this->elementEnd('html'); } else { - $this->showForm(_('Unexpected form submission.')); + $this->showPage(); } } /** - * Set up and add a feed + * Title of the page * - * @return boolean true if feed successfully read - * Sends you back to input form if not. + * @return string Title of the page */ - function validateFeed() + + function title() { - $profile_uri = trim($this->arg('profile')); - - if ($profile_uri == '') { - $this->showForm(_m('Empty remote profile URL!')); - return; - } - $this->profile_uri = $profile_uri; - - // @fixme validate, normalize bla bla - try { - $oprofile = Ostatus_profile::ensureProfile($this->profile_uri); - $this->oprofile = $oprofile; - return true; - } catch (FeedSubBadURLException $e) { - $err = _m('Invalid URL or could not reach server.'); - } catch (FeedSubBadResponseException $e) { - $err = _m('Cannot read feed; server returned error.'); - } catch (FeedSubEmptyException $e) { - $err = _m('Cannot read feed; server returned an empty page.'); - } catch (FeedSubBadHTMLException $e) { - $err = _m('Bad HTML, could not find feed link.'); - } catch (FeedSubNoFeedException $e) { - $err = _m('Could not find a feed linked from this URL.'); - } catch (FeedSubUnrecognizedTypeException $e) { - $err = _m('Not a recognized feed type.'); - } catch (FeedSubException $e) { - // Any new ones we forgot about - $err = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage()); - } - - $this->showForm($err); - return false; + return _m('Authorize subscription'); } - function saveFeed() + /** + * Instructions for use + * + * @return instructions for use + */ + + function getInstructions() { - if ($this->validateFeed()) { - $this->preview = true; + return _m('You can subscribe to users from other supported sites. Paste their address or profile URI below:'); + } - // And subscribe the current user to the local profile - $user = common_current_user(); - - if (!$this->oprofile->subscribe()) { - $this->showForm(_m("Failed to set up server-to-server subscription.")); - return; - } - - if ($this->oprofile->isGroup()) { - $group = $this->oprofile->localGroup(); - if ($user->isMember($group)) { - $this->showForm(_m('Already a member!')); - } elseif (Group_member::join($this->oprofile->group_id, $user->id)) { - $this->showForm(_m('Joined remote group!')); - } else { - $this->showForm(_m('Remote group join failed!')); - } - } else { - $local = $this->oprofile->localProfile(); - if ($user->isSubscribed($local)) { - $this->showForm(_m('Already subscribed!')); - } elseif ($this->oprofile->subscribeLocalToRemote($user)) { - $this->showForm(_m('Remote user subscribed!')); - } else { - $this->showForm(_m('Remote subscription failed!')); - } - } + function showPageNotice() + { + if ($this->error) { + $this->element('p', 'error', $this->error); } } - function validateAndPreview() - { - if ($this->validateFeed()) { - $this->preview = true; - $this->showForm(); - } - } + /** + * Content area of the page + * + * Shows a form for associating a remote OStatus account with this + * StatusNet account. + * + * @return void + */ - function previewFeed() + function showContent() { - $this->text('Profile preview should go here'); + if ($this->oprofile) { + $this->showPreviewForm(); + } else { + $this->showInputForm(); + } } function showScripts() From a306ac39768ff6cbae4f14b565acf2850c979f8b Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 23 Feb 2010 04:58:58 +0100 Subject: [PATCH 150/190] Added a general classname for remote authorization --- theme/default/css/display.css | 3 +++ theme/identica/css/display.css | 3 +++ 2 files changed, 6 insertions(+) diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 71470d55d2..deb985909e 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -184,6 +184,7 @@ button.close, .form_user_unsubscribe input.submit, .form_group_join input.submit, .form_user_subscribe input.submit, +.form_remote_authorize input.submit, .entity_subscribe a, .entity_moderation p, .entity_sandbox input.submit, @@ -291,6 +292,7 @@ background-position:0 1px; .form_group_leave input.submit, .form_user_subscribe input.submit, .form_user_unsubscribe input.submit, +.form_remote_authorize input.submit, .entity_subscribe a { background-color:#AAAAAA; color:#FFFFFF; @@ -301,6 +303,7 @@ background-position:5px -1246px; } .form_group_join input.submit, .form_user_subscribe input.submit, +.form_remote_authorize input.submit, .entity_subscribe a { background-position:5px -1181px; } diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 14a82a8def..0e54d82e2f 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -184,6 +184,7 @@ button.close, .form_user_unsubscribe input.submit, .form_group_join input.submit, .form_user_subscribe input.submit, +.form_remote_authorize input.submit, .entity_subscribe a, .entity_moderation p, .entity_sandbox input.submit, @@ -290,6 +291,7 @@ background-position:0 1px; .form_group_leave input.submit, .form_user_subscribe input.submit, .form_user_unsubscribe input.submit, +.form_remote_authorize input.submit, .entity_subscribe a { background-color:#AAAAAA; color:#FFFFFF; @@ -300,6 +302,7 @@ background-position:5px -1246px; } .form_group_join input.submit, .form_user_subscribe input.submit, +.form_remote_authorize input.submit, .entity_subscribe a { background-position:5px -1181px; } From b67bb182b008b5f7b66d39df7bb8dab449b7002a Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 23 Feb 2010 04:59:34 +0100 Subject: [PATCH 151/190] Refactored preview info and form for authorizing a remote subscription --- plugins/OStatus/actions/ostatussub.php | 119 +++++++++++++++++++++---- 1 file changed, 100 insertions(+), 19 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index ffa88cb088..206fb309d2 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -87,29 +87,35 @@ class OStatusSubAction extends Action */ function showPreviewForm() { - $this->elementStart('form', array('method' => 'post', - 'id' => 'form_ostatus_sub', - 'class' => 'form_settings', - 'action' => - common_local_url('ostatussub'))); - - $this->hidden('token', common_session_token()); - $this->hidden('profile', $this->profile_uri); - - $this->elementStart('fieldset', array('id' => 'settings_feeds')); - if ($this->oprofile->isGroup()) { $this->previewGroup(); - $this->submit('subscribe', _m('Join')); } else { $this->previewUser(); - $this->submit('subscribe', _m('Subscribe')); } - + $this->elementStart('div', 'entity_actions'); + $this->elementStart('ul'); + $this->elementStart('li', 'entity_subscribe'); + $this->elementStart('form', array('method' => 'post', + 'id' => 'form_ostatus_sub', + 'class' => 'form_remote_authorize', + 'action' => + common_local_url('ostatussub'))); + $this->elementStart('fieldset'); + $this->hidden('token', common_session_token()); + $this->hidden('profile', $this->profile_uri); + if ($this->oprofile->isGroup()) { + $this->submit('submit', _m('Join'), 'submit', null, + _m('Join this group')); + } else { + $this->submit('submit', _m('Subscribe'), 'submit', null, + _m('Subscribe to this user')); + } $this->elementEnd('fieldset'); - $this->elementEnd('form'); + $this->elementEnd('li'); + $this->elementEnd('ul'); + $this->elementEnd('div'); } /** @@ -120,8 +126,7 @@ class OStatusSubAction extends Action $oprofile = $this->oprofile; $profile = $oprofile->localProfile(); - $this->text(sprintf(_m("Remote user %s"), $profile->nickname)); - // ... + $this->showEntity($profile); } /** @@ -132,8 +137,84 @@ class OStatusSubAction extends Action $oprofile = $this->oprofile; $group = $oprofile->localGroup(); - $this->text(sprintf(_m("Remote group %s"), $group->nickname)); - // .. + $this->showEntity($group); + } + + + function showEntity($entity) + { + $nickname = $entity->nickname; + $profile = $entity->profileurl; + $fullname = $entity->fullname; + $homepage = $entity->homepage; + $bio = $entity->bio; + $location = $entity->location; + $avatar = $entity->avatarurl; + + $this->elementStart('div', 'entity_profile vcard'); + $this->elementStart('dl', 'entity_depiction'); + $this->element('dt', null, _('Photo')); + $this->elementStart('dd'); + if ($avatar) { + $this->element('img', array('src' => $avatar, + 'class' => 'photo avatar', + 'width' => AVATAR_PROFILE_SIZE, + 'height' => AVATAR_PROFILE_SIZE, + 'alt' => $nickname)); + } + $this->elementEnd('dd'); + $this->elementEnd('dl'); + + $this->elementStart('dl', 'entity_nickname'); + $this->element('dt', null, _('Nickname')); + $this->elementStart('dd'); + $hasFN = ($fullname !== '') ? 'nickname' : 'fn nickname'; + $this->elementStart('a', array('href' => $profile, + 'class' => 'url '.$hasFN)); + $this->raw($nickname); + $this->elementEnd('a'); + $this->elementEnd('dd'); + $this->elementEnd('dl'); + + if (!is_null($fullname)) { + $this->elementStart('dl', 'entity_fn'); + $this->elementStart('dd'); + $this->elementStart('span', 'fn'); + $this->raw($fullname); + $this->elementEnd('span'); + $this->elementEnd('dd'); + $this->elementEnd('dl'); + } + if (!is_null($location)) { + $this->elementStart('dl', 'entity_location'); + $this->element('dt', null, _('Location')); + $this->elementStart('dd', 'label'); + $this->raw($location); + $this->elementEnd('dd'); + $this->elementEnd('dl'); + } + + if (!is_null($homepage)) { + $this->elementStart('dl', 'entity_url'); + $this->element('dt', null, _('URL')); + $this->elementStart('dd'); + $this->elementStart('a', array('href' => $homepage, + 'class' => 'url')); + $this->raw($homepage); + $this->elementEnd('a'); + $this->elementEnd('dd'); + $this->elementEnd('dl'); + } + + if (!is_null($bio)) { + $this->elementStart('dl', 'entity_note'); + $this->element('dt', null, _('Note')); + $this->elementStart('dd', 'note'); + $this->raw($bio); + $this->elementEnd('dd'); + $this->elementEnd('dl'); + } + $this->elementEnd('div'); } /** From f0d1d07b94fbd2fe0ecd1c2f18d831a177d11c5c Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Mon, 22 Feb 2010 22:57:16 -0500 Subject: [PATCH 152/190] Add lose command to the command interpreter --- lib/command.php | 29 ++++++++++++++++++++++++ lib/commandinterpreter.php | 11 ++++++++++ lib/subs.php | 45 +++++++++++++++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/lib/command.php b/lib/command.php index ea7b60372d..db8e800304 100644 --- a/lib/command.php +++ b/lib/command.php @@ -668,6 +668,34 @@ class LoginCommand extends Command } } +class LoseCommand extends Command +{ + + var $other = null; + + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } + + function execute($channel) + { + if(!$this->other) { + $channel->error($this->user, _('Specify the name of the user to unsubscribe from')); + return; + } + + $result=subs_unsubscribe_from($this->user, $this->other); + + if ($result) { + $channel->output($this->user, sprintf(_('Unsubscribed %s'), $this->other)); + } else { + $channel->error($this->user, $result); + } + } +} + class SubscriptionsCommand extends Command { function execute($channel) @@ -750,6 +778,7 @@ class HelpCommand extends Command "d - direct message to user\n". "get - get last notice from user\n". "whois - get profile info on user\n". + "lose - force user to stop following you\n". "fav - add user's last notice as a 'fave'\n". "fav # - add notice with the given id as a 'fave'\n". "repeat # - repeat a notice with a given id\n". diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php index c2add7299e..fbc6174bbf 100644 --- a/lib/commandinterpreter.php +++ b/lib/commandinterpreter.php @@ -47,6 +47,17 @@ class CommandInterpreter } else { return new LoginCommand($user); } + case 'lose': + if ($arg) { + list($other, $extra) = $this->split_arg($arg); + if ($extra) { + return null; + } else { + return new LoseCommand($user, $other); + } + } else { + return null; + } case 'subscribers': if ($arg) { return null; diff --git a/lib/subs.php b/lib/subs.php index 1c240c475d..e2ce0667eb 100644 --- a/lib/subs.php +++ b/lib/subs.php @@ -42,4 +42,47 @@ function subs_unsubscribe_to($user, $other) } catch (Exception $e) { return $e->getMessage(); } -} \ No newline at end of file +} + +function subs_unsubscribe_from($user, $other){ + $local = User::staticGet("nickname",$other); + if($local){ + return subs_unsubscribe_to($local,$user); + } else { + try { + $remote = Profile::staticGet("nickname",$other); + if(is_string($remote)){ + return $remote; + } + if (Event::handle('StartUnsubscribe', array($remote,$user))) { + + $sub = DB_DataObject::factory('subscription'); + + $sub->subscriber = $remote->id; + $sub->subscribed = $user->id; + + $sub->find(true); + + // note we checked for existence above + + if (!$sub->delete()) + return _('Couldn\'t delete subscription.'); + + $cache = common_memcache(); + + if ($cache) { + $cache->delete(common_cache_key('user:notices_with_friends:' . $remote->id)); + } + + + $user->blowSubscribersCount(); + $remote->blowSubscribersCount(); + + Event::handle('EndUnsubscribe', array($remote, $user)); + } + } catch (Exception $e) { + return $e->getMessage(); + } + } +} + From cb32b676fa4d7e95ec32c3e8968d0ccddbfa42fa Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 20:56:11 -0500 Subject: [PATCH 153/190] moving magicsig.php to classes - to add storage --- .../OStatus/{lib/magicsig.php => classes/Magicsig.php} | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) rename plugins/OStatus/{lib/magicsig.php => classes/Magicsig.php} (97%) diff --git a/plugins/OStatus/lib/magicsig.php b/plugins/OStatus/classes/Magicsig.php similarity index 97% rename from plugins/OStatus/lib/magicsig.php rename to plugins/OStatus/classes/Magicsig.php index 50eb301ab3..9d9d327447 100644 --- a/plugins/OStatus/lib/magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -29,15 +29,7 @@ require_once 'Crypt/RSA.php'; -interface Magicsig -{ - - public function sign($bytes); - - public function verify($signed, $signature_b64); -} - -class MagicsigRsaSha256 +class Magicsig { public $keypair; From 74f5c1e16968110caefeeb8431869897f2f8ddfb Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 22:55:26 -0500 Subject: [PATCH 154/190] db_objectified magic sig - for persistence of local keypairs --- plugins/OStatus/classes/Magicsig.php | 46 +++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 9d9d327447..6d09c54ecb 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -29,21 +29,53 @@ require_once 'Crypt/RSA.php'; -class Magicsig +class Magicsig extends Memcached_DataObject { + public $__table = 'magicsig'; + + public $user_id; public $keypair; + public $alg; - public function __construct($init = null) + private $_rsa; + + public /*static*/ function staticGet($k, $v=null) { - if (is_null($init)) { - $this->generate(); - } else { - $this->fromString($init); - } + return parent::staticGet(__CLASS__, $k, $v); } + function table() + { + return array( + 'user_id' => DB_DATAOBJECT_INT, + 'keypair' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'alg' => DB_DATAOBJECT_STR + ); + } + + static function schemaDef() + { + return array(new ColumnDef('user_id', 'integer', + null, true, 'PRI'), + new ColumnDef('keypair', 'varchar', + 255, false), + new ColumnDef('alg', 'varchar', + 64, false)); + } + + + function keys() + { + return array_keys($this->keyTypes()); + } + + function keyTypes() + { + return array('user_id' => 'K'); + } + public function generate($key_length = 512) { $keypair = new Crypt_RSA_KeyPair($key_length); From f4b34d67c54022b70185e83fe628c17e3656d91f Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 23:11:40 -0500 Subject: [PATCH 155/190] generate keypairs for users, and put them in the XRD for discovery --- plugins/OStatus/OStatusPlugin.php | 1 + plugins/OStatus/actions/webfinger.php | 11 ++++++ plugins/OStatus/classes/Magicsig.php | 55 +++++++++++++++++++++------ 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 472008419a..db4a0af358 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -312,6 +312,7 @@ class OStatusPlugin extends Plugin $schema->ensureTable('ostatus_source', Ostatus_source::schemaDef()); $schema->ensureTable('feedsub', FeedSub::schemaDef()); $schema->ensureTable('hubsub', HubSub::schemaDef()); + $schema->ensureTable('magicsig', Magicsig::schemaDef()); return true; } diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php index cf60b8069d..fbbd8d0397 100644 --- a/plugins/OStatus/actions/webfinger.php +++ b/plugins/OStatus/actions/webfinger.php @@ -71,6 +71,17 @@ class WebfingerAction extends Action $xrd->links[] = array('rel' => 'salmon', 'href' => $salmon_url); + // Get this user's keypair + $magickey = Magicsig::staticGet('user_id', $this->user->id); + if (!$magickey) { + // No keypair yet, let's generate one. + $magickey = new Magicsig(); + $magickey->generate(); + } + + $xrd->links[] = array('rel' => Magicsig::PUBLICKEYREL, + 'href' => 'data:application/magic-public-key;'. $magickey->keypair); + // TODO - finalize where the redirect should go on the publisher $url = common_local_url('ostatussub') . '?profile={uri}'; $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe', diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 6d09c54ecb..85664bbf9d 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -32,6 +32,8 @@ require_once 'Crypt/RSA.php'; class Magicsig extends Memcached_DataObject { + const PUBLICKEYREL = 'magic-public-key'; + public $__table = 'magicsig'; public $user_id; @@ -40,6 +42,11 @@ class Magicsig extends Memcached_DataObject private $_rsa; + public function __construct($alg = 'RSA-SHA256') + { + $this->alg = $alg; + } + public /*static*/ function staticGet($k, $v=null) { return parent::staticGet(__CLASS__, $k, $v); @@ -75,23 +82,33 @@ class Magicsig extends Memcached_DataObject { return array('user_id' => 'K'); } + + function insert() + { + $this->keypair = $this->toString(); + + return parent::insert(); + } public function generate($key_length = 512) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $keypair = new Crypt_RSA_KeyPair($key_length); $params['public_key'] = $keypair->getPublicKey(); $params['private_key'] = $keypair->getPrivateKey(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $this->keypair = new Crypt_RSA($params); + $this->_rsa = new Crypt_RSA($params); PEAR::popErrorHandling(); + + $this->insert(); } public function toString($full_pair = true) { - $public_key = $this->keypair->_public_key; - $private_key = $this->keypair->_private_key; + $public_key = $this->_rsa->_public_key; + $private_key = $this->_rsa->_private_key; $mod = base64_url_encode($public_key->getModulus()); $exp = base64_url_encode($public_key->getExponent()); @@ -103,10 +120,12 @@ class Magicsig extends Memcached_DataObject return 'RSA.' . $mod . '.' . $exp . $private_exp; } - public function fromString($text) + public static function fromString($text) { PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $magic_sig = new Magicsig(); + // remove whitespace $text = preg_replace('/\s+/', '', $text); @@ -136,20 +155,32 @@ class Magicsig extends Memcached_DataObject } } - $this->keypair = new Crypt_RSA($params); + $magic_sig->_rsa = new Crypt_RSA($params); PEAR::popErrorHandling(); + + return $magic_sig; } public function getName() { - return 'RSA-SHA256'; + $this->alg; } + public function getHash() + { + switch ($this->alg) { + + case 'RSA-SHA256': + return 'sha256'; + } + + } + public function sign($bytes) { - $sig = $this->keypair->createSign($bytes, null, 'sha256'); - if ($this->keypair->isError()) { - $error = $this->keypair->getLastError(); + $sig = $this->_rsa->createSign($bytes, null, 'sha256'); + if ($this->_rsa->isError()) { + $error = $this->_rsa->getLastError(); common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); } @@ -158,8 +189,8 @@ class Magicsig extends Memcached_DataObject public function verify($signed_bytes, $signature) { - $result = $this->keypair->validateSign($signed_bytes, $signature, null, 'sha256'); - if ($this->keypair->isError()) { + $result = $this->_rsa->validateSign($signed_bytes, $signature, null, 'sha256'); + if ($this->_rsa->isError()) { $error = $this->keypair->getLastError(); //common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); print $error->getMessage(); From cd561657c2bea873f6916cec0e957a9973fa990e Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 23:28:15 -0500 Subject: [PATCH 156/190] missing return value check --- plugins/OStatus/lib/webfinger.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/OStatus/lib/webfinger.php b/plugins/OStatus/lib/webfinger.php index 0386881d14..8a50376294 100644 --- a/plugins/OStatus/lib/webfinger.php +++ b/plugins/OStatus/lib/webfinger.php @@ -108,6 +108,10 @@ class Webfinger $content = $this->fetchURL($url); + if (!$content) { + return false; + } + return XRD::parse($content); } From 17b8020d2585ce248d12ad1a2b8f57a4ab250f82 Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 23:30:05 -0500 Subject: [PATCH 157/190] clean up error logging --- plugins/OStatus/classes/Magicsig.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 85664bbf9d..c9f6182b5b 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -89,7 +89,7 @@ class Magicsig extends Memcached_DataObject return parent::insert(); } - + public function generate($key_length = 512) { PEAR::pushErrorHandling(PEAR_ERROR_RETURN); @@ -143,15 +143,15 @@ class Magicsig extends Memcached_DataObject $params['public_key'] = new Crypt_RSA_KEY($mod, $exp, 'public'); if ($params['public_key']->isError()) { $error = $params['public_key']->getLastError(); - print $error->getMessage(); - exit; + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; } if ($private_exp) { $params['private_key'] = new Crypt_RSA_KEY($mod, $private_exp, 'private'); if ($params['private_key']->isError()) { $error = $params['private_key']->getLastError(); - print $error->getMessage(); - exit; + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; } } @@ -182,6 +182,7 @@ class Magicsig extends Memcached_DataObject if ($this->_rsa->isError()) { $error = $this->_rsa->getLastError(); common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; } return $sig; @@ -192,8 +193,8 @@ class Magicsig extends Memcached_DataObject $result = $this->_rsa->validateSign($signed_bytes, $signature, null, 'sha256'); if ($this->_rsa->isError()) { $error = $this->keypair->getLastError(); - //common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); - print $error->getMessage(); + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; } return $result; } From 9494b0e5d79601b339bf28967a65ffdfe9458532 Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 23:30:21 -0500 Subject: [PATCH 158/190] magicsig shuffling --- plugins/OStatus/lib/magicenvelope.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 1ae80d70c1..81f4609c5c 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -27,8 +27,6 @@ * @link http://status.net/ */ -require_once 'magicsig.php'; - class MagicEnvelope { const ENCODING = 'base64url'; @@ -64,7 +62,7 @@ class MagicEnvelope return false; } - $signature_alg = new MagicsigRsaSha256($this->getKeyPair($signer_uri)); + $signature_alg = Magicsig::fromString($this->getKeyPair($signer_uri)); $armored_text = base64_encode($text); return array( @@ -139,7 +137,7 @@ class MagicEnvelope $text = base64_decode($env['data']); $signer_uri = $this->getAuthor($text); - $verifier = new MagicsigRsaSha256($this->getKeyPair($signer_uri)); + $verifier = Magicsig::fromString($this->getKeyPair($signer_uri)); return $verifier->verify($env['data'], $env['sig']); } From 1fe031844c136d503074e23e0d0a50056dc224dc Mon Sep 17 00:00:00 2001 From: James Walker Date: Mon, 22 Feb 2010 23:44:33 -0500 Subject: [PATCH 159/190] er typo --- plugins/OStatus/classes/Magicsig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index c9f6182b5b..681aec184d 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -163,7 +163,7 @@ class Magicsig extends Memcached_DataObject public function getName() { - $this->alg; + return $this->alg; } public function getHash() From 1bffe424131dfa2c7a85fd9cf782e8c806326bbe Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Feb 2010 08:38:23 -0500 Subject: [PATCH 160/190] Drop user-only requirement for subscribe action I removed the check for local users in the subscribe button. I replaced it with a more specific check for OMB 0.1 remote profiles, which you can't use with this action. I also took the opportunity to split the handle() method into prepare() and handle(), and added PHPCS clean documentation. --- actions/subscribe.php | 132 +++++++++++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 28 deletions(-) diff --git a/actions/subscribe.php b/actions/subscribe.php index a90d7facdf..3745311b66 100644 --- a/actions/subscribe.php +++ b/actions/subscribe.php @@ -1,7 +1,9 @@ . + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Subscription action + * + * Subscribing to a profile. Does not work for OMB 0.1 remote subscriptions, + * but may work for other remote subscription protocols, like OStatus. + * + * Takes parameters: + * + * - subscribeto: a profile ID + * - token: session token to prevent CSRF attacks + * - ajax: boolean; whether to return Ajax or full-browser results + * + * Only works if the current user is logged in. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ class SubscribeAction extends Action { + var $user; + var $other; - function handle($args) + /** + * Check pre-requisites and instantiate attributes + * + * @param Array $args array of arguments (URL, GET, POST) + * + * @return boolean success flag + */ + + function prepare($args) { - parent::handle($args); + parent::prepare($args); - if (!common_logged_in()) { - $this->clientError(_('Not logged in.')); - return; - } - - $user = common_current_user(); + // Only allow POST requests if ($_SERVER['REQUEST_METHOD'] != 'POST') { - common_redirect(common_local_url('subscriptions', array('nickname' => $user->nickname))); - return; + $this->clientError(_('This action only accepts POST requests.')); + return false; } - # CSRF protection + // CSRF protection $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { - $this->clientError(_('There was a problem with your session token. Try again, please.')); - return; + $this->clientError(_('There was a problem with your session token.'. + ' Try again, please.')); + return false; } + // Only for logged-in users + + $this->user = common_current_user(); + + if (empty($this->user)) { + $this->clientError(_('Not logged in.')); + return false; + } + + // Profile to subscribe to + $other_id = $this->arg('subscribeto'); - $other = User::staticGet('id', $other_id); + $this->other = Profile::staticGet('id', $other_id); - if (!$other) { - $this->clientError(_('Not a local user.')); - return; + if (empty($this->other)) { + $this->clientError(_('No such profile.')); + return false; } - $result = subs_subscribe_to($user, $other); + // OMB 0.1 doesn't have a mechanism for local-server- + // originated subscription. - if (is_string($result)) { - $this->clientError($result); - return; + $omb01 = Remote_profile::staticGet('id', $other_id); + + if (!empty($omb01)) { + $this->clientError(_('You cannot subscribe to an OMB 0.1'. + ' remote profile with this action.')); + return false; } + return true; + } + + /** + * Handle request + * + * Does the subscription and returns results. + * + * @param Array $args unused. + * + * @return void + */ + + function handle($args) + { + // Throws exception on error + + Subscription::start($this->user->getProfile(), + $this->other); + if ($this->boolean('ajax')) { $this->startHTML('text/xml;charset=utf-8'); $this->elementStart('head'); $this->element('title', null, _('Subscribed')); $this->elementEnd('head'); $this->elementStart('body'); - $unsubscribe = new UnsubscribeForm($this, $other->getProfile()); + $unsubscribe = new UnsubscribeForm($this, $this->other->getProfile()); $unsubscribe->show(); $this->elementEnd('body'); $this->elementEnd('html'); } else { - common_redirect(common_local_url('subscriptions', array('nickname' => - $user->nickname)), - 303); + $url = common_local_url('subscriptions', + array('nickname' => $this->user->nickname)); + common_redirect($url, 303); } } } From e070fcaaae3e6ac1fef1f9b066c5335fddb9376b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Feb 2010 11:37:49 -0800 Subject: [PATCH 161/190] OStatus: fix for avatars, submit button in updated remote profile preview --- plugins/OStatus/actions/ostatussub.php | 42 +++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 206fb309d2..0d786fac90 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -126,7 +126,13 @@ class OStatusSubAction extends Action $oprofile = $this->oprofile; $profile = $oprofile->localProfile(); - $this->showEntity($profile); + $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); + $avatarUrl = $avatar ? $avatar->displayUrl() : false; + + $this->showEntity($profile, + $profile->profileurl, + $avatarUrl, + $profile->bio); } /** @@ -137,31 +143,33 @@ class OStatusSubAction extends Action $oprofile = $this->oprofile; $group = $oprofile->localGroup(); - $this->showEntity($group); + $this->showEntity($group, + $group->getProfileUrl(), + $group->homepage_logo, + $group->description); } - function showEntity($entity) + function showEntity($entity, $profile, $avatar, $note) { $nickname = $entity->nickname; - $profile = $entity->profileurl; $fullname = $entity->fullname; $homepage = $entity->homepage; - $bio = $entity->bio; $location = $entity->location; - $avatar = $entity->avatarurl; + + if (!$avatar) { + $avatar = Avatar::defaultImage(AVATAR_PROFILE_SIZE); + } $this->elementStart('div', 'entity_profile vcard'); $this->elementStart('dl', 'entity_depiction'); $this->element('dt', null, _('Photo')); $this->elementStart('dd'); - if ($avatar) { - $this->element('img', array('src' => $avatar, - 'class' => 'photo avatar', - 'width' => AVATAR_PROFILE_SIZE, - 'height' => AVATAR_PROFILE_SIZE, - 'alt' => $nickname)); - } + $this->element('img', array('src' => $avatar, + 'class' => 'photo avatar', + 'width' => AVATAR_PROFILE_SIZE, + 'height' => AVATAR_PROFILE_SIZE, + 'alt' => $nickname)); $this->elementEnd('dd'); $this->elementEnd('dl'); @@ -206,11 +214,11 @@ class OStatusSubAction extends Action $this->elementEnd('dl'); } - if (!is_null($bio)) { + if (!is_null($note)) { $this->elementStart('dl', 'entity_note'); $this->element('dt', null, _('Note')); $this->elementStart('dd', 'note'); - $this->raw($bio); + $this->raw($note); $this->elementEnd('dd'); $this->elementEnd('dl'); } @@ -368,7 +376,7 @@ class OStatusSubAction extends Action } if ($this->validateFeed()) { - if ($this->arg('subscribe')) { + if ($this->arg('submit')) { $this->saveFeed(); return; } @@ -424,7 +432,7 @@ class OStatusSubAction extends Action function showPageNotice() { - if ($this->error) { + if (!empty($this->error)) { $this->element('p', 'error', $this->error); } } From c79c70ea2c2dadafa72c65dc4593a66fecb070e3 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Feb 2010 11:56:17 -0800 Subject: [PATCH 162/190] OStatus subscription UI tweak: if we're already subscribed/joined, say so and don't offer a 'subscribe'/'join' button on the profile preview page. --- plugins/OStatus/actions/ostatussub.php | 30 ++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 0d786fac90..df9aa80b01 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -88,9 +88,13 @@ class OStatusSubAction extends Action function showPreviewForm() { if ($this->oprofile->isGroup()) { - $this->previewGroup(); + $ok = $this->previewGroup(); } else { - $this->previewUser(); + $ok = $this->previewUser(); + } + if (!$ok) { + // @fixme maybe provide a cancel button or link back? + return; } $this->elementStart('div', 'entity_actions'); @@ -120,12 +124,22 @@ class OStatusSubAction extends Action /** * Show a preview for a remote user's profile + * @return boolean true if we're ok to try subscribing */ function previewUser() { $oprofile = $this->oprofile; $profile = $oprofile->localProfile(); + $cur = common_current_user(); + if ($cur->isSubscribed($profile)) { + $this->element('div', array('class' => 'error'), + _m("You are already subscribed to this user.")); + $ok = false; + } else { + $ok = true; + } + $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); $avatarUrl = $avatar ? $avatar->displayUrl() : false; @@ -133,20 +147,32 @@ class OStatusSubAction extends Action $profile->profileurl, $avatarUrl, $profile->bio); + return $ok; } /** * Show a preview for a remote group's profile + * @return boolean true if we're ok to try joining */ function previewGroup() { $oprofile = $this->oprofile; $group = $oprofile->localGroup(); + $cur = common_current_user(); + if ($cur->isMember($group)) { + $this->element('div', array('class' => 'error'), + _m("You are already a member of this group.")); + $ok = false; + } else { + $ok = true; + } + $this->showEntity($group, $group->getProfileUrl(), $group->homepage_logo, $group->description); + return $ok; } From 90d34b26c66ceb5d37a9c2782356b46361a523cc Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Feb 2010 20:44:27 +0000 Subject: [PATCH 163/190] OStatus: do PuSH subscription setup from subscribe/join event hooks, so resubscribing directly from a profile/group list works correctly if there aren't active subscriptions at the moment. --- lib/activity.php | 4 +- plugins/OStatus/OStatusPlugin.php | 158 ++++++++++++-------- plugins/OStatus/actions/ostatussub.php | 5 - plugins/OStatus/classes/Ostatus_profile.php | 26 +++- 4 files changed, 127 insertions(+), 66 deletions(-) diff --git a/lib/activity.php b/lib/activity.php index 3689dac385..04c57c561c 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -823,7 +823,9 @@ class Activity if ($namespace) { $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', - 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); + 'xmlns:georss' => 'http://www.georss.org/georss', + 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', + 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0'); } else { $attrs = array(); } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index db4a0af358..629645767f 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -251,58 +251,6 @@ class OStatusPlugin extends Plugin return true; } - /** - * Notify remote server and garbage collect unused feeds on unsubscribe. - * @fixme send these operations to background queues - * - * @param User $user - * @param Profile $other - * @return hook return value - */ - function onEndUnsubscribe($profile, $other) - { - $user = User::staticGet('id', $profile->id); - - if (empty($user)) { - return true; - } - - $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); - - if (empty($oprofile)) { - return true; - } - - // Drop the PuSH subscription if there are no other subscribers. - - if ($other->subscriberCount() == 0) { - common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri"); - $oprofile->unsubscribe(); - } - - $act = new Activity(); - - $act->verb = ActivityVerb::UNFOLLOW; - - $act->id = TagURI::mint('unfollow:%d:%d:%s', - $profile->id, - $other->id, - common_date_iso8601(time())); - - $act->time = time(); - $act->title = _("Unfollow"); - $act->content = sprintf(_("%s stopped following %s."), - $profile->getBestName(), - $other->getBestName()); - - $act->actor = ActivityObject::fromProfile($profile); - $act->object = ActivityObject::fromProfile($other); - - $oprofile->notifyActivity($act); - - return true; - } - /** * Make sure necessary tables are filled out. */ @@ -366,6 +314,50 @@ class OStatusPlugin extends Plugin } } + /** + * When about to subscribe to a remote user, start a server-to-server + * PuSH subscription if needed. If we can't establish that, abort. + * + * @fixme If something else aborts later, we could end up with a stray + * PuSH subscription. This is relatively harmless, though. + * + * @param Profile $subscriber + * @param Profile $other + * + * @return hook return code + * + * @throws Exception + */ + function onStartSubscribe($subscriber, $other) + { + $user = User::staticGet('id', $subscriber->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + + if (empty($oprofile)) { + return true; + } + + if (!$oprofile->subscribe()) { + throw new Exception(_m('Could not set up remote subscription.')); + } + } + + /** + * Having established a remote subscription, send a notification to the + * remote OStatus profile's endpoint. + * + * @param Profile $subscriber + * @param Profile $other + * + * @return hook return code + * + * @throws Exception + */ function onEndSubscribe($subscriber, $other) { $user = User::staticGet('id', $subscriber->id); @@ -403,6 +395,54 @@ class OStatusPlugin extends Plugin return true; } + /** + * Notify remote server and garbage collect unused feeds on unsubscribe. + * @fixme send these operations to background queues + * + * @param User $user + * @param Profile $other + * @return hook return value + */ + function onEndUnsubscribe($profile, $other) + { + $user = User::staticGet('id', $profile->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + + if (empty($oprofile)) { + return true; + } + + // Drop the PuSH subscription if there are no other subscribers. + $oprofile->garbageCollect(); + + $act = new Activity(); + + $act->verb = ActivityVerb::UNFOLLOW; + + $act->id = TagURI::mint('unfollow:%d:%d:%s', + $profile->id, + $other->id, + common_date_iso8601(time())); + + $act->time = time(); + $act->title = _("Unfollow"); + $act->content = sprintf(_("%s stopped following %s."), + $profile->getBestName(), + $other->getBestName()); + + $act->actor = ActivityObject::fromProfile($profile); + $act->object = ActivityObject::fromProfile($other); + + $oprofile->notifyActivity($act); + + return true; + } + /** * When one of our local users tries to join a remote group, * notify the remote server. If the notification is rejected, @@ -418,6 +458,10 @@ class OStatusPlugin extends Plugin { $oprofile = Ostatus_profile::staticGet('group_id', $group->id); if ($oprofile) { + if (!$oprofile->subscribe()) { + throw new Exception(_m('Could not set up remote group membership.')); + } + $member = Profile::staticGet($user->id); $act = new Activity(); @@ -439,7 +483,8 @@ class OStatusPlugin extends Plugin if ($oprofile->notifyActivity($act)) { return true; } else { - throw new ServerException(_m("Failed joining remote group.")); + $oprofile->garbageCollect(); + throw new Exception(_m("Failed joining remote group.")); } } } @@ -464,12 +509,7 @@ class OStatusPlugin extends Plugin $oprofile = Ostatus_profile::staticGet('group_id', $group->id); if ($oprofile) { // Drop the PuSH subscription if there are no other subscribers. - - $members = $group->getMembers(0, 1); - if ($members->N == 0) { - common_log(LOG_INFO, "Unsubscribing from now-unused group feed $oprofile->feeduri"); - $oprofile->unsubscribe(); - } + $oprofile->garbageCollect(); $member = Profile::staticGet($user->id); diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index df9aa80b01..b3569e6951 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -324,11 +324,6 @@ class OStatusSubAction extends Action // And subscribe the current user to the local profile $user = common_current_user(); - if (!$this->oprofile->subscribe()) { - $this->showForm(_m("Failed to set up server-to-server subscription.")); - return; - } - if ($this->oprofile->isGroup()) { $group = $this->oprofile->localGroup(); if ($user->isMember($group)) { diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index e8cc13c6c1..91b957fa23 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -346,6 +346,29 @@ class Ostatus_profile extends Memcached_DataObject } } + /** + * Check if this remote profile has any active local subscriptions, and + * if not drop the PuSH subscription feed. + * + * @return boolean + */ + public function garbageCollect() + { + if ($this->isGroup()) { + $members = $this->localGroup()->getMembers(0, 1); + $count = $members->N; + } else { + $count = $this->localProfile()->subscriberCount(); + } + if ($count == 0) { + common_log(LOG_INFO, "Unsubscribing from now-unused remote feed $oprofile->feeduri"); + $this->unsubscribe(); + return true; + } else { + return false; + } + } + /** * Send an Activity Streams notification to the remote Salmon endpoint, * if so configured. @@ -379,7 +402,8 @@ class Ostatus_profile extends Memcached_DataObject 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', - 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); + 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', + 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0'); $entry = new XMLStringer(); $entry->elementStart('entry', $attributes); From a0c255e231a84cf77554cc3c0a095eae7b0ffd9c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Feb 2010 15:59:10 -0500 Subject: [PATCH 164/190] move mention detection before default in OStatusPlugin --- plugins/OStatus/OStatusPlugin.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index db4a0af358..679857f897 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -224,7 +224,7 @@ class OStatusPlugin extends Plugin * */ - function onEndFindMentions($sender, $text, &$mentions) + function onStartFindMentions($sender, $text, &$mentions) { preg_match_all('/(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)/', $text, @@ -464,14 +464,13 @@ class OStatusPlugin extends Plugin $oprofile = Ostatus_profile::staticGet('group_id', $group->id); if ($oprofile) { // Drop the PuSH subscription if there are no other subscribers. - + $members = $group->getMembers(0, 1); if ($members->N == 0) { common_log(LOG_INFO, "Unsubscribing from now-unused group feed $oprofile->feeduri"); $oprofile->unsubscribe(); } - $member = Profile::staticGet($user->id); $act = new Activity(); From 5f9a8ca64bee5247358238c26b4f54003337d11b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Feb 2010 21:11:44 +0000 Subject: [PATCH 165/190] OStatus: accept webfinger addresses as well as profile URLs in the explicit remote subscribe form. --- plugins/OStatus/actions/ostatussub.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index b3569e6951..12832cdcfb 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -288,10 +288,15 @@ class OStatusSubAction extends Action } $this->profile_uri = $profile_uri; - // @fixme validate, normalize bla bla try { - $oprofile = Ostatus_profile::ensureProfile($this->profile_uri); - $this->oprofile = $oprofile; + if (Validate::email($this->profile_uri)) { + $this->oprofile = Ostatus_profile::ensureWebfinger($this->profile_uri); + } else if (Validate::uri($this->profile_uri)) { + $this->oprofile = Ostatus_profile::ensureProfile($this->profile_uri); + } else { + $this->error = _m("Invalid address format."); + return false; + } return true; } catch (FeedSubBadURLException $e) { $this->error = _m('Invalid URL or could not reach server.'); From f5ec7c27070dac4ac28ba860f4cc9a808b5f7c30 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Feb 2010 16:13:24 -0500 Subject: [PATCH 166/190] some logging for OStatusPlugin::onStartFindMentions() --- plugins/OStatus/OStatusPlugin.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 3a9e77c2a6..934c858ac1 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -235,9 +235,17 @@ class OStatusPlugin extends Plugin $webfinger = $wmatch[0]; + $this->log(LOG_INFO, "Checking Webfinger for address '$webfinger'"); + $oprofile = Ostatus_profile::ensureWebfinger($webfinger); - if (!empty($oprofile)) { + if (empty($oprofile)) { + + $this->log(LOG_INFO, "No Ostatus_profile found for address '$webfinger'"); + + } else { + + $this->log(LOG_INFO, "Ostatus_profile found for address '$webfinger'"); $profile = $oprofile->localProfile(); From d6ad7332475f1cc4ab45d55fc04ef491d5f3999d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 23 Feb 2010 21:47:14 +0000 Subject: [PATCH 167/190] OStatus: fixes for link/id and text extraction gets import of Buzz feeds working. --- plugins/OStatus/OStatusPlugin.php | 24 +++++++++++---------- plugins/OStatus/classes/Ostatus_profile.php | 17 ++++++++++++--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 3a9e77c2a6..724634924d 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -287,13 +287,19 @@ class OStatusPlugin extends Plugin function onStartNoticeSourceLink($notice, &$name, &$url, &$title) { if ($notice->source == 'ostatus') { - $bits = parse_url($notice->uri); - $domain = $bits['host']; + if ($notice->url) { + $bits = parse_url($notice->url); + $domain = $bits['host']; + if (substr($domain, 0, 4) == 'www.') { + $name = substr($domain, 4); + } else { + $name = $domain; + } - $name = $domain; - $url = $notice->uri; - $title = sprintf(_m("Sent from %s via OStatus"), $domain); - return false; + $url = $notice->url; + $title = sprintf(_m("Sent from %s via OStatus"), $domain); + return false; + } } } @@ -509,12 +515,8 @@ class OStatusPlugin extends Plugin $oprofile = Ostatus_profile::staticGet('group_id', $group->id); if ($oprofile) { // Drop the PuSH subscription if there are no other subscribers. + $oprofile->garbageCollect(); - $members = $group->getMembers(0, 1); - if ($members->N == 0) { - common_log(LOG_INFO, "Unsubscribing from now-unused group feed $oprofile->feeduri"); - $oprofile->unsubscribe(); - } $member = Profile::staticGet($user->id); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 91b957fa23..4998809bc8 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -556,17 +556,28 @@ class Ostatus_profile extends Memcached_DataObject if ($activity->object->link) { $sourceUrl = $activity->object->link; + } else if ($activity->link) { + $sourceUrl = $activity->link; } else if (preg_match('!^https?://!', $activity->object->id)) { $sourceUrl = $activity->object->id; } - // @fixme sanitize and save HTML content if available + // Get (safe!) HTML and text versions of the content - $content = $activity->object->title; + require_once(INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php'); + + $html = $activity->object->content; + + $purifier = new HTMLPurifier(); + + $rendered = $purifier->purify($html); + + $content = html_entity_decode(strip_tags($rendered)); $params = array('is_local' => Notice::REMOTE_OMB, 'url' => $sourceUrl, - 'uri' => $sourceUri); + 'uri' => $sourceUri, + 'rendered' => $rendered); $location = $activity->context->location; From fa178a8aa7d6e5ade76eef12ac0ca49aa10f5cdc Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 23 Feb 2010 14:26:34 -0800 Subject: [PATCH 168/190] Add poco:displayName to Atom output for person object --- lib/activity.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/activity.php b/lib/activity.php index 04c57c561c..853741a9a1 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -104,6 +104,7 @@ class PoCo function __construct($profile) { $this->preferredUsername = $profile->nickname; + $this->displayName = $profile->getBestName(); $this->note = $profile->bio; $this->address = new PoCoAddress($profile->location); @@ -129,6 +130,12 @@ class PoCo $this->preferredUsername ); + $xs->element( + 'poco:displayName', + null, + $this->displayName + ); + if (!empty($this->note)) { $xs->element('poco:note', null, $this->note); } From 391b45949f6fabef0427aa99d4123fe6ef5ef49d Mon Sep 17 00:00:00 2001 From: James Walker Date: Tue, 23 Feb 2010 18:25:31 -0500 Subject: [PATCH 169/190] adding xfn, foaf and hcard rel's to our webfinger output --- plugins/OStatus/actions/webfinger.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/OStatus/actions/webfinger.php b/plugins/OStatus/actions/webfinger.php index fbbd8d0397..34336a9039 100644 --- a/plugins/OStatus/actions/webfinger.php +++ b/plugins/OStatus/actions/webfinger.php @@ -65,6 +65,21 @@ class WebfingerAction extends Action 'format' => 'atom')), 'type' => 'application/atom+xml'); + // hCard + $xrd->links[] = array('rel' => 'http://microformats.org/profile/hcard', + 'type' => 'text/html', + 'href' => common_profile_url($nick)); + + // XFN + $xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11', + 'type' => 'text/html', + 'href' => common_profile_url($nick)); + // FOAF + $xrd->links[] = array('rel' => 'describedby', + 'type' => 'application/rdf+xml', + 'href' => common_local_url('foaf', + array('nickname' => $nick))); + $salmon_url = common_local_url('salmon', array('id' => $this->user->id)); From 25864aea9dd81ebcdb8c7386af3662eda800ccc3 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Feb 2010 00:59:00 +0100 Subject: [PATCH 170/190] Using the default abbr class pattern for geo microformats instead of the shorthand that I've proposed at http://microformats.org/wiki/geo-brainstorming#latitude_longitude_shorthand_and_geo_link If anyone wants to pick up on where the discussion was left off or get more implementation support by other sites and software, and be recognized by parsers, I'd be happy to go back to the shorthand. Because you know, it actually makes a lot of sense. --- lib/noticelist.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/noticelist.php b/lib/noticelist.php index 837cb90faa..dcf17be08c 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -438,14 +438,15 @@ class NoticeListItem extends Widget $this->out->text(_('at')); $this->out->text(' '); if (empty($url)) { - $this->out->element('span', array('class' => 'geo', + $this->out->element('abbr', array('class' => 'geo', 'title' => $latlon), $name); } else { - $this->out->element('a', array('class' => 'geo', - 'title' => $latlon, - 'href' => $url), + $this->out->elementStart('a', array('href' => $url)); + $this->out->element('abbr', array('class' => 'geo', + 'title' => $latlon), $name); + $this->out->elementEnd('a'); } $this->out->elementEnd('span'); } From 2aaf8d4e308d49d072a6c43e43cb99c373deca2e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Feb 2010 01:09:12 +0000 Subject: [PATCH 171/190] Add class and (if present) id to DB_DataObject error exceptions; often they're VERRRRRY vague, and it helps to know what type of item is failing! --- classes/Memcached_DataObject.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 40576dc717..bc4c3a000c 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -501,7 +501,11 @@ class Memcached_DataObject extends Safe_DataObject function raiseError($message, $type = null, $behaviour = null) { - throw new ServerException("DB_DataObject error [$type]: $message"); + $id = get_class($this); + if ($this->id) { + $id .= ':' . $this->id; + } + throw new ServerException("[$id] DB_DataObject error [$type]: $message"); } static function cacheGet($keyPart) From 584b87cfe57bd2d683101194040e3563f0706536 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Feb 2010 01:09:52 +0000 Subject: [PATCH 172/190] OStatus: consolidate the low-level notice save code between Salmon and PuSH input paths. Validation etc remains at higher levels. --- plugins/OStatus/OStatusPlugin.php | 2 +- plugins/OStatus/classes/Ostatus_profile.php | 214 +++++++++++--------- plugins/OStatus/lib/salmonaction.php | 50 +---- 3 files changed, 125 insertions(+), 141 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 724634924d..35f9529355 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -314,7 +314,7 @@ class OStatusPlugin extends Plugin { $oprofile = Ostatus_profile::staticGet('feeduri', $feedsub->uri); if ($oprofile) { - $oprofile->processFeed($feed); + $oprofile->processFeed($feed, 'push'); } else { common_log(LOG_DEBUG, "No ostatus profile for incoming feed $feedsub->uri"); } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 4998809bc8..6beaf0f5d0 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -488,7 +488,7 @@ class Ostatus_profile extends Memcached_DataObject * * @param DOMDocument $feed */ - public function processFeed($feed) + public function processFeed($feed, $source) { $entries = $feed->getElementsByTagNameNS(Activity::ATOM, 'entry'); if ($entries->length == 0) { @@ -498,7 +498,7 @@ class Ostatus_profile extends Memcached_DataObject for ($i = 0; $i < $entries->length; $i++) { $entry = $entries->item($i); - $this->processEntry($entry, $feed); + $this->processEntry($entry, $feed, $source); } } @@ -508,15 +508,12 @@ class Ostatus_profile extends Memcached_DataObject * @param DOMElement $entry * @param DOMElement $feed for context */ - protected function processEntry($entry, $feed) + public function processEntry($entry, $feed, $source) { $activity = new Activity($entry, $feed); - $debug = var_export($activity, true); - common_log(LOG_DEBUG, $debug); - if ($activity->verb == ActivityVerb::POST) { - $this->processPost($activity); + $this->processPost($activity, $source); } else { common_log(LOG_INFO, "Ignoring activity with unrecognized verb $activity->verb"); } @@ -525,35 +522,47 @@ class Ostatus_profile extends Memcached_DataObject /** * Process an incoming post activity from this remote feed. * @param Activity $activity + * @param string $method 'push' or 'salmon' + * @return mixed saved Notice or false * @fixme break up this function, it's getting nasty long */ - protected function processPost($activity) + public function processPost($activity, $method) { if ($this->isGroup()) { + // A group feed will contain posts from multiple authors. // @fixme validate these profiles in some way! $oprofile = self::ensureActorProfile($activity); + if ($oprofile->isGroup()) { + // Groups can't post notices in StatusNet. + common_log(LOG_WARNING, "OStatus: skipping post with group listed as author: $oprofile->uri in feed from $this->uri"); + return false; + } } else { + // Individual user feeds may contain only posts from themselves. + // Authorship is validated against the profile URI on upper layers, + // through PuSH setup or Salmon signature checks. $actorUri = self::getActorProfileURI($activity); if ($actorUri == $this->uri) { // @fixme check if profile info has changed and update it } else { - // @fixme drop or reject the messages once we've got the canonical profile URI recorded sanely - common_log(LOG_INFO, "OStatus: Warning: non-group post with unexpected author: $actorUri expected $this->uri"); - //return; + common_log(LOG_WARNING, "OStatus: skipping post with bad author: got $actorUri expected $this->uri"); + return false; } $oprofile = $this; } + + // 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; + // tag: URIs for instance are found in Google Buzz feeds. $sourceUri = $activity->object->id; - $dupe = Notice::staticGet('uri', $sourceUri); - if ($dupe) { common_log(LOG_INFO, "OStatus: ignoring duplicate post: $sourceUri"); - return; + return false; } + // We'll also want to save a web link to the original notice, if provided. $sourceUrl = null; - if ($activity->object->link) { $sourceUrl = $activity->object->link; } else if ($activity->link) { @@ -563,103 +572,126 @@ class Ostatus_profile extends Memcached_DataObject } // Get (safe!) HTML and text versions of the content - - require_once(INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php'); - - $html = $activity->object->content; - - $purifier = new HTMLPurifier(); - - $rendered = $purifier->purify($html); - + $rendered = $this->purify($activity->object->content); $content = html_entity_decode(strip_tags($rendered)); - $params = array('is_local' => Notice::REMOTE_OMB, + $options = array('is_local' => Notice::REMOTE_OMB, 'url' => $sourceUrl, 'uri' => $sourceUri, - 'rendered' => $rendered); + 'rendered' => $rendered, + 'replies' => array(), + 'groups' => array()); - $location = $activity->context->location; + // Check for optional attributes... - if ($location) { - $params['lat'] = $location->lat; - $params['lon'] = $location->lon; - if ($location->location_id) { - $params['location_ns'] = $location->location_ns; - $params['location_id'] = $location->location_id; - } + if (!empty($activity->time)) { + $options['created'] = common_sql_date($activity->time); } - $profile = $oprofile->localProfile(); - $params['groups'] = array(); - $params['replies'] = array(); if ($activity->context) { - foreach ($activity->context->attention as $recipient) { - $roprofile = Ostatus_profile::staticGet('uri', $recipient); - if ($roprofile) { - if ($roprofile->isGroup()) { - // Deliver to local recipients of this remote group. - // @fixme sender verification? - $params['groups'][] = $roprofile->group_id; - continue; - } else { - // Delivery to remote users is the source service's job. - continue; - } + // Any individual or group attn: targets? + $replies = $activity->context->attention; + $options['groups'] = $this->filterReplies($oprofile, $replies); + $options['replies'] = $replies; + + // Maintain direct reply associations + // @fixme what about conversation ID? + if (!empty($activity->context->replyToID)) { + $orig = Notice::staticGet('uri', + $activity->context->replyToID); + if (!empty($orig)) { + $options['reply_to'] = $orig->id; } - - $user = User::staticGet('uri', $recipient); - if ($user) { - // An @-reply directed to a local user. - // @fixme sender verification, spam etc? - $params['replies'][] = $recipient; - continue; - } - - // @fixme we need a uri on user_group - // $group = User_group::staticGet('uri', $recipient); - $template = common_local_url('groupbyid', array('id' => '31337')); - $template = preg_quote($template, '/'); - $template = str_replace('31337', '(\d+)', $template); - common_log(LOG_DEBUG, $template); - if (preg_match("/$template/", $recipient, $matches)) { - $id = $matches[1]; - $group = User_group::staticGet('id', $id); - if ($group) { - // Deliver to all members of this local group. - // @fixme sender verification? - if ($profile->isMember($group)) { - common_log(LOG_DEBUG, "delivering to group $id $group->nickname"); - $params['groups'][] = $group->id; - } else { - common_log(LOG_DEBUG, "not delivering to group $id $group->nickname because sender $profile->nickname is not a member"); - } - continue; - } else { - common_log(LOG_DEBUG, "not delivering to missing group $id"); - } - } else { - common_log(LOG_DEBUG, "not delivering to groups for $recipient"); + } + + $location = $activity->context->location; + if ($location) { + $options['lat'] = $location->lat; + $options['lon'] = $location->lon; + if ($location->location_id) { + $options['location_ns'] = $location->location_ns; + $options['location_id'] = $location->location_id; } } } try { - $saved = Notice::saveNew($profile->id, + $saved = Notice::saveNew($oprofile->profile_id, $content, 'ostatus', - $params); + $options); + if ($saved) { + Ostatus_source::saveNew($saved, $this, $method); + } } catch (Exception $e) { - common_log(LOG_ERR, "Failed saving notice entry for $sourceUri: " . $e->getMessage()); - return; + common_log(LOG_ERR, "OStatus save of remote message $sourceUri failed: " . $e->getMessage()); + throw $e; } + common_log(LOG_INFO, "OStatus saved remote message $sourceUri as notice id $saved->id"); + return $saved; + } - // Record which feed this came through... - try { - Ostatus_source::saveNew($saved, $this, 'push'); - } catch (Exception $e) { - common_log(LOG_ERR, "Failed saving ostatus_source entry for $saved->notice_id: " . $e->getMessage()); + /** + * Clean up HTML + */ + protected function purify($html) + { + // @fixme disable caching or set a sane temp dir + require_once(INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php'); + $purifier = new HTMLPurifier(); + return $purifier->purify($html); + } + + /** + * Filters a list of recipient ID URIs to just those for local delivery. + * @param Ostatus_profile local profile of sender + * @param array in/out &$attention_uris set of URIs, will be pruned on output + * @return array of group IDs + */ + protected function filterReplies($sender, &$attention_uris) + { + $groups = array(); + $replies = array(); + foreach ($attention_uris as $recipient) { + // Is the recipient a local user? + $user = User::staticGet('uri', $recipient); + if ($user) { + // @fixme sender verification, spam etc? + $replies[] = $recipient; + continue; + } + + // Is the recipient a remote group? + $oprofile = Ostatus_profile::staticGet('uri', $recipient); + if ($oprofile) { + if ($oprofile->isGroup()) { + // Deliver to local members of this remote group. + // @fixme sender verification? + $groups[] = $oprofile->group_id; + } + continue; + } + + // Is the recipient a local group? + // @fixme we need a uri on user_group + // $group = User_group::staticGet('uri', $recipient); + $template = common_local_url('groupbyid', array('id' => '31337')); + $template = preg_quote($template, '/'); + $template = str_replace('31337', '(\d+)', $template); + if (preg_match("/$template/", $recipient, $matches)) { + $id = $matches[1]; + $group = User_group::staticGet('id', $id); + if ($group) { + // Deliver to all members of this local group if allowed. + if ($sender->localProfile()->isMember($group)) { + $groups[] = $group->id; + } + continue; + } + } } + $attention_uris = $replies; + return $groups; } /** diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 83cf0b8f8a..9aac2ed52f 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -185,54 +185,6 @@ class SalmonAction extends Action function saveNotice() { $oprofile = $this->ensureProfile(); - - // Get (safe!) HTML and text versions of the content - - require_once(INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php'); - - $html = $this->act->object->content; - - $purifier = new HTMLPurifier(); - - $rendered = $purifier->purify($html); - - $content = html_entity_decode(strip_tags($rendered)); - - $options = array('is_local' => Notice::REMOTE_OMB, - 'uri' => $this->act->object->id, - 'url' => $this->act->object->link, - 'rendered' => $rendered, - 'replies' => $this->act->context->attention); - - if (!empty($this->act->context->location)) { - $options['lat'] = $location->lat; - $options['lon'] = $location->lon; - if ($location->location_id) { - $options['location_ns'] = $location->location_ns; - $options['location_id'] = $location->location_id; - } - } - - if (!empty($this->act->context->replyToID)) { - $orig = Notice::staticGet('uri', - $this->act->context->replyToID); - if (!empty($orig)) { - $options['reply_to'] = $orig->id; - } - } - - if (!empty($this->act->time)) { - $options['created'] = common_sql_date($this->act->time); - } - - $saved = Notice::saveNew($oprofile->profile_id, - $content, - 'ostatus+salmon', - $options); - - // Record that this was saved through a validated Salmon source - // @fixme actually do the signature validation! - Ostatus_source::saveNew($saved, $oprofile, 'salmon'); - return $saved; + return $oprofile->processPost($this->act, 'salmon'); } } From 2e58802cc9959763f28e2f43c8e0cd0dbe7bcd8e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Feb 2010 02:19:13 +0000 Subject: [PATCH 173/190] OStatus: fix group delivery, send reply/group Salmon pings from background. --- plugins/OStatus/OStatusPlugin.php | 28 ++---- plugins/OStatus/actions/groupsalmon.php | 9 +- plugins/OStatus/classes/Ostatus_profile.php | 15 ++- ...euehandler.php => ostatusqueuehandler.php} | 95 +++++++++++++------ plugins/OStatus/lib/salmonoutqueuehandler.php | 44 +++++++++ 5 files changed, 140 insertions(+), 51 deletions(-) rename plugins/OStatus/lib/{hubdistribqueuehandler.php => ostatusqueuehandler.php} (65%) create mode 100644 plugins/OStatus/lib/salmonoutqueuehandler.php diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 35f9529355..9376c048de 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -78,11 +78,16 @@ class OStatusPlugin extends Plugin */ function onEndInitializeQueueManager(QueueManager $qm) { + // Prepare outgoing distributions after notice save. + $qm->connect('ostatus', 'OStatusQueueHandler'); + // Outgoing from our internal PuSH hub $qm->connect('hubverify', 'HubVerifyQueueHandler'); - $qm->connect('hubdistrib', 'HubDistribQueueHandler'); $qm->connect('hubout', 'HubOutQueueHandler'); + // Outgoing Salmon replies (when we don't need a return value) + $qm->connect('salmonout', 'SalmonOutQueueHandler'); + // Incoming from a foreign PuSH hub $qm->connect('pushinput', 'PushInputQueueHandler'); return true; @@ -93,7 +98,7 @@ class OStatusPlugin extends Plugin */ function onStartEnqueueNotice($notice, &$transports) { - $transports[] = 'hubdistrib'; + $transports[] = 'ostatus'; return true; } @@ -199,25 +204,6 @@ class OStatusPlugin extends Plugin function onEndNoticeSave($notice) { - $mentioned = $notice->getReplies(); - - foreach ($mentioned as $profile_id) { - - $oprofile = Ostatus_profile::staticGet('profile_id', $profile_id); - - if (!empty($oprofile) && !empty($oprofile->salmonuri)) { - - common_log(LOG_INFO, "Sending notice '{$notice->uri}' to remote profile '{$oprofile->uri}'."); - - // FIXME: this needs to go out in a queue handler - - $xml = ''; - $xml .= $notice->asAtomEntry(true, true); - - $salmon = new Salmon(); - $salmon->post($oprofile->salmonuri, $xml); - } - } } /** diff --git a/plugins/OStatus/actions/groupsalmon.php b/plugins/OStatus/actions/groupsalmon.php index 2e4fe94436..29377b5fa0 100644 --- a/plugins/OStatus/actions/groupsalmon.php +++ b/plugins/OStatus/actions/groupsalmon.php @@ -46,6 +46,11 @@ class GroupsalmonAction extends SalmonAction $this->clientError(_('No such group.')); } + $oprofile = Ostatus_profile::staticGet('group_id', $id); + if ($oprofile) { + $this->clientError(_m("Can't accept remote posts for a remote group.")); + } + return true; } @@ -74,13 +79,13 @@ class GroupsalmonAction extends SalmonAction throw new ClientException("Not to the attention of anyone."); } else { $uri = common_local_url('groupbyid', array('id' => $this->group->id)); - if (!in_array($context->attention, $uri)) { + if (!in_array($uri, $context->attention)) { throw new ClientException("Not to the attention of this group."); } } $profile = $this->ensureProfile(); - // @fixme save the post + $this->saveNotice(); } /** diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 6beaf0f5d0..82dbf773dd 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -650,6 +650,7 @@ class Ostatus_profile extends Memcached_DataObject */ protected function filterReplies($sender, &$attention_uris) { + common_log(LOG_DEBUG, "Original reply recipients: " . implode(', ', $attention_uris)); $groups = array(); $replies = array(); foreach ($attention_uris as $recipient) { @@ -668,6 +669,8 @@ class Ostatus_profile extends Memcached_DataObject // Deliver to local members of this remote group. // @fixme sender verification? $groups[] = $oprofile->group_id; + } else { + common_log(LOG_DEBUG, "Skipping reply to remote profile $recipient"); } continue; } @@ -683,14 +686,24 @@ class Ostatus_profile extends Memcached_DataObject $group = User_group::staticGet('id', $id); if ($group) { // Deliver to all members of this local group if allowed. - if ($sender->localProfile()->isMember($group)) { + $profile = $sender->localProfile(); + if ($profile->isMember($group)) { $groups[] = $group->id; + } else { + common_log(LOG_DEBUG, "Skipping reply to local group $group->nickname as sender $profile->id is not a member"); } continue; + } else { + common_log(LOG_DEBUG, "Skipping reply to bogus group $recipient"); } } + + common_log(LOG_DEBUG, "Skipping reply to unrecognized profile $recipient"); + } $attention_uris = $replies; + common_log(LOG_DEBUG, "Local reply recipients: " . implode(', ', $replies)); + common_log(LOG_DEBUG, "Local group recipients: " . implode(', ', $groups)); return $groups; } diff --git a/plugins/OStatus/lib/hubdistribqueuehandler.php b/plugins/OStatus/lib/ostatusqueuehandler.php similarity index 65% rename from plugins/OStatus/lib/hubdistribqueuehandler.php rename to plugins/OStatus/lib/ostatusqueuehandler.php index c2bd630f9c..c1e50bffa1 100644 --- a/plugins/OStatus/lib/hubdistribqueuehandler.php +++ b/plugins/OStatus/lib/ostatusqueuehandler.php @@ -18,46 +18,89 @@ */ /** - * Send a PuSH subscription verification from our internal hub. - * Queue up final distribution for - * @package Hub + * Prepare PuSH and Salmon distributions for an outgoing message. + * + * @package OStatusPlugin * @author Brion Vibber */ -class HubDistribQueueHandler extends QueueHandler +class OStatusQueueHandler extends QueueHandler { function transport() { - return 'hubdistrib'; + return 'ostatus'; } function handle($notice) { assert($notice instanceof Notice); - $this->pushUser($notice); + $this->notice = $notice; + $this->user = User::staticGet($notice->profile_id); + + $this->pushUser(); + foreach ($notice->getGroups() as $group) { - $this->pushGroup($notice, $group->id); + $oprofile = Ostatus_profile::staticGet('group_id', $group->id); + if ($oprofile) { + $this->pingReply($oprofile); + } else { + $this->pushGroup($group->id); + } } + + foreach ($notice->getReplies() as $profile_id) { + $oprofile = Ostatus_profile::staticGet('profile_id', $profile_id); + if ($oprofile) { + $this->pingReply($oprofile); + } + } + return true; } - - function pushUser($notice) + + function pushUser() { - // See if there's any PuSH subscriptions, including OStatus clients. - // @fixme handle group subscriptions as well - // http://identi.ca/api/statuses/user_timeline/1.atom - $feed = common_local_url('ApiTimelineUser', - array('id' => $notice->profile_id, - 'format' => 'atom')); - $this->pushFeed($feed, array($this, 'userFeedForNotice'), $notice); + if ($this->user) { + // For local posts, ping the PuSH hub to update their feed. + // http://identi.ca/api/statuses/user_timeline/1.atom + $feed = common_local_url('ApiTimelineUser', + array('id' => $this->user->id, + 'format' => 'atom')); + $this->pushFeed($feed, array($this, 'userFeedForNotice')); + } } - function pushGroup($notice, $group_id) + function pushGroup($group_id) { + // For a local group, ping the PuSH hub to update its feed. + // Updates may come from either a local or a remote user. $feed = common_local_url('ApiTimelineGroup', array('id' => $group_id, 'format' => 'atom')); - $this->pushFeed($feed, array($this, 'groupFeedForNotice'), $group_id, $notice); + $this->pushFeed($feed, array($this, 'groupFeedForNotice'), $group_id); + } + + function pingReply($oprofile) + { + if ($this->user) { + if (!empty($oprofile->salmonuri)) { + // For local posts, send a Salmon ping to the mentioned + // remote user or group. + // @fixme as an optimization we can skip this if the + // remote profile is subscribed to the author. + + common_log(LOG_INFO, "Prepping to send notice '{$this->notice->uri}' to remote profile '{$oprofile->uri}'."); + + $xml = ''; + $xml .= $this->notice->asAtomEntry(true, true); + + $data = array('salmonuri' => $oprofile->salmonuri, + 'entry' => $xml); + + $qm = QueueManager::get(); + $qm->enqueue($data, 'salmonout'); + } + } } /** @@ -122,7 +165,6 @@ class HubDistribQueueHandler extends QueueHandler function pushFeedInternal($atom, $sub) { common_log(LOG_INFO, "Preparing $sub->N PuSH distribution(s) for $sub->topic"); - $qm = QueueManager::get(); while ($sub->fetch()) { $sub->distribute($atom); } @@ -130,20 +172,19 @@ class HubDistribQueueHandler extends QueueHandler /** * Build a single-item version of the sending user's Atom feed. - * @param Notice $notice * @return string */ - function userFeedForNotice($notice) + function userFeedForNotice() { // @fixme this feels VERY hacky... // should probably be a cleaner way to do it ob_start(); $api = new ApiTimelineUserAction(); - $api->prepare(array('id' => $notice->profile_id, + $api->prepare(array('id' => $this->notice->profile_id, 'format' => 'atom', - 'max_id' => $notice->id, - 'since_id' => $notice->id - 1)); + 'max_id' => $this->notice->id, + 'since_id' => $this->notice->id - 1)); $api->showTimeline(); $feed = ob_get_clean(); @@ -155,7 +196,7 @@ class HubDistribQueueHandler extends QueueHandler return $feed; } - function groupFeedForNotice($group_id, $notice) + function groupFeedForNotice($group_id) { // @fixme this feels VERY hacky... // should probably be a cleaner way to do it @@ -164,8 +205,8 @@ class HubDistribQueueHandler extends QueueHandler $api = new ApiTimelineGroupAction(); $args = array('id' => $group_id, 'format' => 'atom', - 'max_id' => $notice->id, - 'since_id' => $notice->id - 1); + 'max_id' => $this->notice->id, + 'since_id' => $this->notice->id - 1); $api->prepare($args); $api->handle($args); $feed = ob_get_clean(); diff --git a/plugins/OStatus/lib/salmonoutqueuehandler.php b/plugins/OStatus/lib/salmonoutqueuehandler.php new file mode 100644 index 0000000000..536ff94af6 --- /dev/null +++ b/plugins/OStatus/lib/salmonoutqueuehandler.php @@ -0,0 +1,44 @@ +. + */ + +/** + * Send a Salmon notification in the background. + * @package OStatusPlugin + * @author Brion Vibber + */ +class SalmonOutQueueHandler extends QueueHandler +{ + function transport() + { + return 'salmonout'; + } + + function handle($data) + { + assert(is_array($data)); + assert(is_string($data['salmonuri'])); + assert(is_string($data['entry'])); + + $salmon = new Salmon(); + $salmon->post($data['salmonuri'], $data['entry']); + + // @fixme detect failure and attempt to resend + return true; + } +} From 3a3af6782a82ca3512680a276b76d1d10de47d94 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 23 Feb 2010 22:35:48 -0800 Subject: [PATCH 174/190] Add PoCo parsing and some other fixes. --- lib/activity.php | 162 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 132 insertions(+), 30 deletions(-) diff --git a/lib/activity.php b/lib/activity.php index 853741a9a1..5cbab8d5f3 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -34,6 +34,7 @@ if (!defined('STATUSNET')) { class PoCoURL { + const URLS = 'urls'; const TYPE = 'type'; const VALUE = 'value'; const PRIMARY = 'primary'; @@ -55,7 +56,7 @@ class PoCoURL $xs->elementStart('poco:urls'); $xs->element('poco:type', null, $this->type); $xs->element('poco:value', null, $this->value); - if ($this->primary) { + if (!empty($this->primary)) { $xs->element('poco:primary', null, 'true'); } $xs->elementEnd('poco:urls'); @@ -70,21 +71,19 @@ class PoCoAddress public $formatted; - function __construct($formatted) - { - if (empty($formatted)) { - return null; - } - $this->formatted = $formatted; - } + // @todo Other address fields function asString() { - $xs = new XMLStringer(true); - $xs->elementStart('poco:address'); - $xs->element('poco:formatted', null, $this->formatted); - $xs->elementEnd('poco:address'); - return $xs->getString(); + if (!empty($this->formatted)) { + $xs = new XMLStringer(true); + $xs->elementStart('poco:address'); + $xs->element('poco:formatted', null, $this->formatted); + $xs->elementEnd('poco:address'); + return $xs->getString(); + } + + return null; } } @@ -92,26 +91,117 @@ class PoCo { const NS = 'http://portablecontacts.net/spec/1.0'; - const USERNAME = 'preferredUsername'; - const NOTE = 'note'; - const URLS = 'urls'; + const USERNAME = 'preferredUsername'; + const DISPLAYNAME = 'displayName'; + const NOTE = 'note'; public $preferredUsername; + public $displayName; public $note; public $address; public $urls = array(); - function __construct($profile) + function __construct($element = null) { - $this->preferredUsername = $profile->nickname; - $this->displayName = $profile->getBestName(); + if (empty($element)) { + return; + } - $this->note = $profile->bio; - $this->address = new PoCoAddress($profile->location); + $this->preferredUsername = ActivityUtils::childContent( + $element, + self::USERNAME, + self::NS + ); + + $this->displayName = ActivityUtils::childContent( + $element, + self::DISPLAYNAME, + self::NS + ); + + $this->note = ActivityUtils::childContent( + $element, + self::NOTE, + self::NS + ); + + $this->address = $this->_getAddress($element); + $this->urls = $this->_getURLs($element); + } + + private function _getURLs($element) + { + $urlEls = $element->getElementsByTagnameNS(self::NS, PoCoURL::URLS); + $urls = array(); + + foreach ($urlEls as $urlEl) { + + $type = ActivityUtils::childContent( + $urlEl, + PoCoURL::TYPE, + PoCo::NS + ); + + $value = ActivityUtils::childContent( + $urlEl, + PoCoURL::VALUE, + PoCo::NS + ); + + $primary = ActivityUtils::childContent( + $urlEl, + PoCoURL::PRIMARY, + PoCo::NS + ); + + array_push($urls, new PoCoURL($type, $value, $primary)); + } + return $urls; + } + + private function _getAddress($element) + { + $addressEl = ActivityUtils::child( + $element, + PoCoAddress::ADDRESS, + PoCo::NS + ); + + $formatted = ActivityUtils::childContent( + $addressEl, + PoCoAddress::FORMATTED, + self::NS + ); + + if (!empty($formatted)) { + $address = new PoCoAddress(); + $address->formatted = $formatted; + return $address; + } + + return null; + } + + function fromProfile($profile) + { + if (empty($profile)) { + return null; + } + + $poco = new PoCo(); + + $poco->preferredUsername = $profile->nickname; + $poco->displayName = $profile->getBestName(); + + $poco->note = $profile->bio; + + $paddy = new PoCoAddress(); + $paddy->formatted = $profile->location; + $poco->address = $paddy; if (!empty($profile->homepage)) { array_push( - $this->urls, + $poco->urls, new PoCoURL( 'homepage', $profile->homepage, @@ -119,6 +209,8 @@ class PoCo ) ); } + + return $poco; } function asString() @@ -381,6 +473,8 @@ class ActivityObject public $source; public $avatar; public $geopoint; + public $poco; + public $displayName; /** * Constructor @@ -433,7 +527,6 @@ class ActivityObject $this->link = ActivityUtils::getPermalink($element); - // XXX: grab PoCo stuff } // Some per-type attributes... @@ -441,8 +534,9 @@ class ActivityObject $this->displayName = $this->title; // @fixme we may have multiple avatars with different resolutions specified - $this->avatar = ActivityUtils::getLink($element, 'avatar'); - $this->nickname = ActivityUtils::childContent($element, PoCo::USERNAME, PoCo::NS); + $this->avatar = ActivityUtils::getLink($element, 'avatar'); + + $this->poco = new PoCo($element); } } @@ -497,7 +591,7 @@ class ActivityObject $object->geopoint = (float)$profile->lat . ' ' . (float)$profile->lon; } - $object->poco = new PoCo($profile); + $object->poco = PoCo::fromProfile($profile); return $object; } @@ -526,11 +620,19 @@ class ActivityObject } if (!empty($this->link)) { - $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html'), - $this->link); + $xs->element( + 'link', + array( + 'rel' => 'alternate', + 'type' => 'text/html', + 'href' => $this->link + ), + null + ); } - if ($this->type == ActivityObject::PERSON) { + if ($this->type == ActivityObject::PERSON + || $this->type == ActivityObject::GROUP) { $xs->element( 'link', array( 'type' => empty($this->avatar) ? 'image/png' : $this->avatar->mediatype, @@ -539,7 +641,7 @@ class ActivityObject ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) : $this->avatar->displayUrl() ), - '' + null ); } From 618ce6a855330f424d54c3dedf10acb60f7e3001 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 23 Feb 2010 23:58:21 -0800 Subject: [PATCH 175/190] - Move ActivityParseTests to core - Add test for Portable Contacts stuff --- .../tests => tests}/ActivityParseTests.php | 159 +++++++++++++++--- 1 file changed, 138 insertions(+), 21 deletions(-) rename {plugins/OStatus/tests => tests}/ActivityParseTests.php (57%) diff --git a/plugins/OStatus/tests/ActivityParseTests.php b/tests/ActivityParseTests.php similarity index 57% rename from plugins/OStatus/tests/ActivityParseTests.php rename to tests/ActivityParseTests.php index d7305dedea..5de97d2e2e 100644 --- a/plugins/OStatus/tests/ActivityParseTests.php +++ b/tests/ActivityParseTests.php @@ -7,11 +7,10 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { // XXX: we should probably have some common source for this stuff -define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..')); +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('STATUSNET', true); require_once INSTALLDIR . '/lib/common.php'; -require_once INSTALLDIR . '/plugins/OStatus/lib/activity.php'; class ActivityParseTests extends PHPUnit_Framework_TestCase { @@ -97,6 +96,45 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase $this->assertFalse(empty($act->actor)); } + + public function testExample5() + { + global $_example5; + $dom = DOMDocument::loadXML($_example5); + + $feed = $dom->documentElement; + + // @todo Test feed elements + + $entries = $feed->getElementsByTagName('entry'); + $entry = $entries->item(0); + + $act = new Activity($entry, $feed); + + // Post + $this->assertEquals($act->verb, ActivityVerb::POST); + $this->assertFalse(empty($act->context)); + + // Actor w/Portable Contacts stuff + $this->assertFalse(empty($act->actor)); + $this->assertEquals($act->actor->type, ActivityObject::PERSON); + $this->assertEquals($act->actor->title, 'Test User'); + $this->assertEquals($act->actor->id, 'http://example.net/mysite/user/3'); + $this->assertEquals($act->actor->link, 'http://example.net/mysite/testuser'); + $this->assertEquals( + $act->actor->avatar, + 'http://example.net/mysite/avatar/3-96-20100224004207.jpeg' + ); + $this->assertEquals($act->actor->displayName, 'Test User'); + + $poco = $act->actor->poco; + $this->assertEquals($poco->preferredUsername, 'testuser'); + $this->assertEquals($poco->address->formatted, 'San Francisco, CA'); + $this->assertEquals($poco->urls[0]->type, 'homepage'); + $this->assertEquals($poco->urls[0]->value, 'http://example.com/blog.html'); + $this->assertEquals($poco->urls[0]->primary, 'true'); + } + } $_example1 = << - Example Feed - A subtitle. - - - urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6 - 2003-12-13T18:30:02Z - - John Doe - johndoe@example.com - + Example Feed + A subtitle. + + + urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6 + 2003-12-13T18:30:02Z + + John Doe + johndoe@example.com + - - Atom-Powered Robots Run Amok - - - - urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a - 2003-12-13T18:30:02Z - Some text. - + + Atom-Powered Robots Run Amok + + + + urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a + 2003-12-13T18:30:02Z + Some text. + EXAMPLE3; @@ -207,3 +245,82 @@ $_example4 = << EXAMPLE4; + +$_example5 = << + + 3 + testuser timeline + Updates from testuser on Zach Dev! + http://example.net/mysite/avatar/3-96-20100224004207.jpeg + 2010-02-24T06:38:49+00:00 + + testuser + http://example.net/mysite/user/3 + + + + + + + + + http://activitystrea.ms/schema/1.0/person + http://example.net/mysite/user/3 + Test User + + + 37.7749295 -122.4194155 + +testuser +Test User +Just another test user. + + San Francisco, CA + + + homepage + http://example.com/blog.html + true + + + + + Hey man, is that Freedom Code?! #freedom #hippy + Hey man, is that Freedom Code?! #freedom #hippy + + testuser + http://example.net/mysite/user/3 + + + http://activitystrea.ms/schema/1.0/person + http://example.net/mysite/user/3 + Test User + + + 37.7749295 -122.4194155 + +testuser +Test User +Just another test user. + + San Francisco, CA + + + homepage + http://example.com/blog.html + true + + + + + http://example.net/mysite/notice/7 + 2010-02-24T00:53:06+00:00 + 2010-02-24T00:53:06+00:00 + + Hey man, is that Freedom Code?! #<span class="tag"><a href="http://example.net/mysite/tag/freedom" rel="tag">freedom</a></span> #<span class="tag"><a href="http://example.net/mysite/tag/hippy" rel="tag">hippy</a></span> + 37.8313160 -122.2852473 + + + +EXAMPLE5; From 2466dbfc97e81144d005fa546b387c9747ce00ad Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Feb 2010 14:55:35 +0100 Subject: [PATCH 176/190] Break long strings in tagcloud --- theme/base/css/display.css | 1 + 1 file changed, 1 insertion(+) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 380975e324..52f97f6b12 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -1490,6 +1490,7 @@ text-align:center; } .aside .tag-cloud { font-size:0.8em; +word-wrap:break-word; } .tag-cloud li { display:inline; From 8e7606cc8d9003cb5d58410678c2be0f812d0ed1 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Feb 2010 15:20:44 +0100 Subject: [PATCH 177/190] Added processing indicator for .form_remote_authorize on ostatussub page --- plugins/OStatus/js/ostatus.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 1fc44b21b6..3637b8725b 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -123,4 +123,6 @@ SN.Init.Subscribe = function() { $(document).ready(function() { SN.Init.Subscribe(); + + $('.form_remote_authorize').bind('submit', function() { $(this).addClass(SN.C.S.Processing); return true; }); }); From 1f45273d5303e98430a02d4480278c24733a5be9 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Feb 2010 16:35:20 +0100 Subject: [PATCH 178/190] Moved StatusNetInstance into SN in util.js --- js/util.js | 32 +++++++++++++++++++++++++++++++- plugins/OStatus/js/ostatus.js | 32 +++----------------------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/js/util.js b/js/util.js index 3623337b9f..78533ab731 100644 --- a/js/util.js +++ b/js/util.js @@ -54,7 +54,8 @@ var SN = { // StatusNet NoticeGeoName: 'notice_data-geo_name', NoticeDataGeo: 'notice_data-geo', NoticeDataGeoCookie: 'notice_data-geo_cookie', - NoticeDataGeoSelected: 'notice_data-geo_selected' + NoticeDataGeoSelected: 'notice_data-geo_selected', + StatusNetInstance:'StatusNetInstance' } }, @@ -670,6 +671,35 @@ var SN = { // StatusNet date.setFullYear(year, month, day); return date; + }, + + StatusNetInstance: { + Set: function(value) { + var SNI = SN.U.StatusNetInstance.Get(); + if (SNI !== null) { + value = $.extend(SNI, value); + } + + $.cookie( + SN.C.S.StatusNetInstance, + JSON.stringify(value), + { + path: '/', + expires: SN.U.GetFullYear(2029, 0, 1) + }); + }, + + Get: function() { + var cookieValue = $.cookie(SN.C.S.StatusNetInstance); + if (cookieValue !== null) { + return JSON.parse(cookieValue); + } + return null; + }, + + Delete: function() { + $.cookie(SN.C.S.StatusNetInstance, null); + } } }, diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js index 3637b8725b..bd29b5c0cf 100644 --- a/plugins/OStatus/js/ostatus.js +++ b/plugins/OStatus/js/ostatus.js @@ -24,35 +24,9 @@ * @note Everything in here should eventually migrate over to /js/util.js's SN. */ -SN.C.S.StatusNetInstance = 'StatusNetInstance'; - -SN.U.StatusNetInstance = { - Set: function(value) { - $.cookie( - SN.C.S.StatusNetInstance, - JSON.stringify(value), - { - path: '/', - expires: SN.U.GetFullYear(2029, 0, 1) - }); - }, - - Get: function() { - var cookieValue = $.cookie(SN.C.S.StatusNetInstance); - if (cookieValue !== null) { - return JSON.parse(cookieValue); - } - return null; - }, - - Delete: function() { - $.cookie(SN.C.S.StatusNetInstance, null); - } -}; - SN.Init.OStatusCookie = function() { if (SN.U.StatusNetInstance.Get() === null) { - SN.U.StatusNetInstance.Set({profile: null}); + SN.U.StatusNetInstance.Set({RemoteProfile: null}); } }; @@ -101,10 +75,10 @@ SN.U.DialogBox = { if (form.attr('id') == 'form_ostatus_connect') { SN.Init.OStatusCookie(); - form.find('#profile').val(SN.U.StatusNetInstance.Get().profile); + form.find('#profile').val(SN.U.StatusNetInstance.Get().RemoteProfile); form.find("[type=submit]").bind('click', function() { - SN.U.StatusNetInstance.Set({profile: form.find('#profile').val()}); + SN.U.StatusNetInstance.Set({RemoteProfile: form.find('#profile').val()}); return true; }); } From 959171acac5abc3716119f7d5a7918e7497fdbfd Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 24 Feb 2010 16:39:16 +0100 Subject: [PATCH 179/190] Added a cookie for the nickname cookie for the login page and prefill the input field. --- js/util.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/js/util.js b/js/util.js index 78533ab731..4b6c39a1dc 100644 --- a/js/util.js +++ b/js/util.js @@ -737,6 +737,20 @@ var SN = { // StatusNet SN.U.NewDirectMessage(); } + }, + + Login: function() { + if (SN.U.StatusNetInstance.Get() !== null) { + var nickname = SN.U.StatusNetInstance.Get().Nickname; + if (nickname !== null) { + $('#form_login #nickname').val(nickname); + } + } + + $('#form_login').bind('submit', function() { + SN.U.StatusNetInstance.Set({Nickname: $('#form_login #nickname').val()}); + return true; + }); } } }; @@ -751,5 +765,8 @@ $(document).ready(function(){ if ($('#content .entity_actions').length > 0) { SN.Init.EntityActions(); } + if ($('#form_login').length > 0) { + SN.Init.Login(); + } }); From 5cabb63e4eaf7cd3642bf7a0c4beb3fef2e1ba07 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Feb 2010 17:36:31 +0000 Subject: [PATCH 180/190] Include with actor ID and name in Activity::asString(); fixes Salmon signature on OStatus unsub pings --- lib/activity.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/activity.php b/lib/activity.php index 5cbab8d5f3..fa4ae02748 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -957,11 +957,24 @@ class Activity } // XXX: add context - // XXX: add target + $xs->elementStart('author'); + $xs->element('uri', array(), $this->actor->id); + if ($this->actor->title) { + $xs->element('name', array(), $this->actor->title); + } + $xs->elementEnd('author'); $xs->raw($this->actor->asString('activity:actor')); + $xs->element('activity:verb', null, $this->verb); - $xs->raw($this->object->asString()); + + if ($this->object) { + $xs->raw($this->object->asString()); + } + + if ($this->target) { + $xs->raw($this->target->asString('activity:target')); + } $xs->elementEnd('entry'); From 07214f1370547fcc64db34ce8c8a84ec70e0d5bd Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Feb 2010 19:06:10 +0000 Subject: [PATCH 181/190] OStatus: save updated profile bits when they come in over the wire; fix up nicknames --- plugins/OStatus/classes/Ostatus_profile.php | 147 +++++++++++++++----- 1 file changed, 112 insertions(+), 35 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 82dbf773dd..9f9efb96ee 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -33,6 +33,7 @@ class Ostatus_profile extends Memcached_DataObject public $feeduri; public $salmonuri; + public $avatar; // remote URL of the last avatar we saved public $created; public $modified; @@ -58,6 +59,7 @@ class Ostatus_profile extends Memcached_DataObject 'group_id' => DB_DATAOBJECT_INT, 'feeduri' => DB_DATAOBJECT_STR, 'salmonuri' => DB_DATAOBJECT_STR, + 'avatar' => DB_DATAOBJECT_STR, 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); } @@ -74,6 +76,8 @@ class Ostatus_profile extends Memcached_DataObject 255, true, 'UNI'), new ColumnDef('salmonuri', 'text', null, true), + new ColumnDef('avatar', 'text', + null, true), new ColumnDef('created', 'datetime', null, false), new ColumnDef('modified', 'datetime', @@ -543,7 +547,8 @@ class Ostatus_profile extends Memcached_DataObject // through PuSH setup or Salmon signature checks. $actorUri = self::getActorProfileURI($activity); if ($actorUri == $this->uri) { - // @fixme check if profile info has changed and update it + // Check if profile info has changed and update it + $this->updateFromActivityObject($activity->actor); } else { common_log(LOG_WARNING, "OStatus: skipping post with bad author: got $actorUri expected $this->uri"); return false; @@ -785,6 +790,11 @@ class Ostatus_profile extends Memcached_DataObject */ protected function updateAvatar($url) { + if ($url == $this->avatar) { + // We've already got this one. + return; + } + if ($this->isGroup()) { $self = $this->localGroup(); } else { @@ -816,12 +826,28 @@ class Ostatus_profile extends Memcached_DataObject common_timestamp()); rename($temp_filename, Avatar::path($filename)); $self->setOriginal($filename); + + $orig = clone($this); + $this->avatar = $url; + $this->update($orig); } - protected static function getActivityObjectAvatar($object) + /** + * Pull avatar URL from ActivityObject or profile hints + * + * @param ActivityObject $object + * @param array $hints + * @return mixed URL string or false + */ + + protected static function getActivityObjectAvatar($object, $hints=array()) { - // XXX: go poke around in the feed - return $object->avatar; + if ($object->avatar) { + return $object->avatar; + } else if (array_key_exists('avatar', $hints)) { + return $hints['avatar']; + } + return false; } /** @@ -888,7 +914,9 @@ class Ostatus_profile extends Memcached_DataObject public static function ensureActivityObjectProfile($object, $feeduri=null, $salmonuri=null, $hints=array()) { $profile = self::getActivityObjectProfile($object); - if (!$profile) { + if ($profile) { + $profile->updateFromActivityObject($object, $hints); + } else { $profile = self::createActivityObjectProfile($object, $feeduri, $salmonuri, $hints); } return $profile; @@ -957,8 +985,6 @@ class Ostatus_profile extends Memcached_DataObject protected static function createActivityObjectProfile($object, $feeduri=null, $salmonuri=null, $hints=array()) { $homeuri = $object->id; - $nickname = self::getActivityObjectNickname($object, $hints); - $avatar = self::getActivityObjectAvatar($object); if (!$homeuri) { common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true)); @@ -1002,43 +1028,19 @@ class Ostatus_profile extends Memcached_DataObject if ($object->type == ActivityObject::PERSON) { $profile = new Profile(); - $profile->nickname = $nickname; - $profile->fullname = $object->title; - if (!empty($object->link)) { - $profile->profileurl = $object->link; - } else if (array_key_exists('profileurl', $hints)) { - $profile->profileurl = $hints['profileurl']; - } - $profile->created = common_sql_now(); - - // @fixme bio - // @fixme tags/categories - // @fixme location? - // @todo tags from categories - // @todo lat/lon/location? - + self::updateProfile($profile, $object, $hints); + $profile->created = common_sql_now(); + $oprofile->profile_id = $profile->insert(); - if (!$oprofile->profile_id) { throw new ServerException("Can't save local profile"); } } else { $group = new User_group(); - $group->nickname = $nickname; - $group->fullname = $object->title; - // @fixme no canonical profileurl; using homepage instead for now - $group->homepage = $homeuri; $group->created = common_sql_now(); - - // @fixme homepage - // @fixme bio - // @fixme tags/categories - // @fixme location? - // @todo tags from categories - // @todo lat/lon/location? + self::updateGroup($group, $object, $hints); $oprofile->group_id = $group->insert(); - if (!$oprofile->group_id) { throw new ServerException("Can't save local profile"); } @@ -1047,6 +1049,7 @@ class Ostatus_profile extends Memcached_DataObject $ok = $oprofile->insert(); if ($ok) { + $avatar = self::getActivityObjectAvatar($object, $hints); if ($avatar) { $oprofile->updateAvatar($avatar); } @@ -1056,8 +1059,82 @@ class Ostatus_profile extends Memcached_DataObject } } + /** + * Save any updated profile information to our local copy. + * @param ActivityObject $object + * @param array $hints + */ + protected function updateFromActivityObject($object, $hints=array()) + { + if ($this->isGroup()) { + $group = $this->localGroup(); + self::updateGroup($group, $object, $hints); + } else { + $profile = $this->localProfile(); + self::updateProfile($profile, $object, $hints); + } + $avatar = self::getActivityObjectAvatar($object, $hints); + if ($avatar) { + $this->updateAvatar($avatar); + } + } + + protected static function updateProfile($profile, $object, $hints=array()) + { + $orig = clone($profile); + + $profile->nickname = self::getActivityObjectNickname($object, $hints); + $profile->fullname = $object->title; + if (!empty($object->link)) { + $profile->profileurl = $object->link; + } else if (array_key_exists('profileurl', $hints)) { + $profile->profileurl = $hints['profileurl']; + } + + // @fixme bio + // @fixme tags/categories + // @fixme location? + // @todo tags from categories + // @todo lat/lon/location? + + if ($profile->id) { + common_log(LOG_DEBUG, "Updating OStatus profile $profile->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true)); + $profile->update($orig); + } + } + + protected static function updateGroup($group, $object, $hints=array()) + { + $orig = clone($group); + + // @fixme need to make nick unique etc *hack hack* + $group->nickname = self::getActivityObjectNickname($object, $hints); + $group->fullname = $object->title; + + // @fixme no canonical profileurl; using homepage instead for now + $group->homepage = $object->id; + + // @fixme homepage + // @fixme bio + // @fixme tags/categories + // @fixme location? + // @todo tags from categories + // @todo lat/lon/location? + + if ($group->id) { + common_log(LOG_DEBUG, "Updating OStatus group $group->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true)); + $group->update($orig); + } + } + + protected static function getActivityObjectNickname($object, $hints=array()) { + if ($object->poco) { + if (!empty($object->poco->preferredUsername)) { + return common_nicknamize($object->poco->preferredUsername); + } + } if (!empty($object->nickname)) { return common_nicknamize($object->nickname); } From 269d567d9440e3c943f67aad428efce9d112385c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Feb 2010 15:20:06 -0500 Subject: [PATCH 182/190] use Subscription::start() for remote subscribes --- plugins/OStatus/classes/Ostatus_profile.php | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 9f9efb96ee..e8ab065224 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -299,18 +299,9 @@ class Ostatus_profile extends Memcached_DataObject throw new ServerException("Remote groups can't subscribe to local users"); } - // @fixme use regular channels for subbing, once they accept remote profiles - $sub = new Subscription(); - $sub->subscriber = $this->profile_id; - $sub->subscribed = $user->id; - $sub->created = common_sql_now(); // current time + Subscription::start($this->localProfile(), $user->getProfile()); - if ($sub->insert()) { - // @fixme use subs_notify() if refactored to take profiles? - mail_subscribe_notify_profile($user, $this->localProfile()); - return true; - } - return false; + return true; } /** @@ -1127,7 +1118,6 @@ class Ostatus_profile extends Memcached_DataObject } } - protected static function getActivityObjectNickname($object, $hints=array()) { if ($object->poco) { From c36bdc1ba535dc3e2dc9098dbe40735b1955d96d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Feb 2010 20:36:36 +0000 Subject: [PATCH 183/190] - break OMB profile update pings to a background queue - add event hooks to profile update pings - send Salmon pings with custom update-profile event to OStatus subscribees and groups (subscribers will see it on your next post) - fix OStatus queues with overlong transport names, should work on DB queues now - Ostatus_profile::notifyActivity() and ::notifyDeferred() now can take XML, Notice, or Activity for convenience --- lib/activity.php | 3 ++ lib/profilequeuehandler.php | 48 +++++++++++++++++ lib/queuemanager.php | 3 ++ lib/util.php | 14 +++-- plugins/OStatus/OStatusPlugin.php | 53 +++++++++++++++++-- plugins/OStatus/actions/pushcallback.php | 2 +- plugins/OStatus/classes/HubSub.php | 2 +- plugins/OStatus/classes/Ostatus_profile.php | 52 +++++++++++++++--- ...euehandler.php => hubconfqueuehandler.php} | 4 +- plugins/OStatus/lib/ostatusqueuehandler.php | 22 ++------ ...ueuehandler.php => pushinqueuehandler.php} | 4 +- ...ueuehandler.php => salmonqueuehandler.php} | 4 +- 12 files changed, 170 insertions(+), 41 deletions(-) create mode 100644 lib/profilequeuehandler.php rename plugins/OStatus/lib/{hubverifyqueuehandler.php => hubconfqueuehandler.php} (95%) rename plugins/OStatus/lib/{pushinputqueuehandler.php => pushinqueuehandler.php} (94%) rename plugins/OStatus/lib/{salmonoutqueuehandler.php => salmonqueuehandler.php} (94%) diff --git a/lib/activity.php b/lib/activity.php index fa4ae02748..33932ad0ef 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -691,6 +691,9 @@ class ActivityVerb const UNFAVORITE = 'http://ostatus.org/schema/1.0/unfavorite'; const UNFOLLOW = 'http://ostatus.org/schema/1.0/unfollow'; const LEAVE = 'http://ostatus.org/schema/1.0/leave'; + + // For simple profile-update pings; no content to share. + const UPDATE_PROFILE = 'http://ostatus.org/schema/1.0/update-profile'; } class ActivityContext diff --git a/lib/profilequeuehandler.php b/lib/profilequeuehandler.php new file mode 100644 index 0000000000..e8a00aef30 --- /dev/null +++ b/lib/profilequeuehandler.php @@ -0,0 +1,48 @@ +. + */ + +/** + * @package QueueHandler + * @maintainer Brion Vibber + */ + +class ProfileQueueHandler extends QueueHandler +{ + + function transport() + { + return 'profile'; + } + + function handle($profile) + { + if (!($profile instanceof Profile)) { + common_log(LOG_ERR, "Got a bogus profile, not broadcasting"); + return true; + } + + if (Event::handle('StartBroadcastProfile', array($profile))) { + require_once(INSTALLDIR.'/lib/omb.php'); + omb_broadcast_profile($profile); + } + Event::handle('EndBroadcastProfile', array($profile)); + return true; + } + +} diff --git a/lib/queuemanager.php b/lib/queuemanager.php index 8f8c8f133f..9fdc801100 100644 --- a/lib/queuemanager.php +++ b/lib/queuemanager.php @@ -262,6 +262,9 @@ abstract class QueueManager extends IoManager $this->connect('sms', 'SmsQueueHandler'); } + // Broadcasting profile updates to OMB remote subscribers + $this->connect('profile', 'ProfileQueueHandler'); + // XMPP output handlers... if (common_config('xmpp', 'enabled')) { // Delivery prep, read by queuedaemon.php: diff --git a/lib/util.php b/lib/util.php index 7fb2c6c4b0..9354431f27 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1119,12 +1119,16 @@ function common_enqueue_notice($notice) return true; } -function common_broadcast_profile($profile) +/** + * Broadcast profile updates to OMB and other remote subscribers. + * + * Since this may be slow with a lot of subscribers or bad remote sites, + * this is run through the background queues if possible. + */ +function common_broadcast_profile(Profile $profile) { - // XXX: optionally use a queue system like http://code.google.com/p/microapps/wiki/NQDQ - require_once(INSTALLDIR.'/lib/omb.php'); - omb_broadcast_profile($profile); - // XXX: Other broadcasts...? + $qm = QueueManager::get(); + $qm->enqueue($profile, "profile"); return true; } diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 9376c048de..90abe034de 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -82,14 +82,14 @@ class OStatusPlugin extends Plugin $qm->connect('ostatus', 'OStatusQueueHandler'); // Outgoing from our internal PuSH hub - $qm->connect('hubverify', 'HubVerifyQueueHandler'); + $qm->connect('hubconf', 'HubConfQueueHandler'); $qm->connect('hubout', 'HubOutQueueHandler'); // Outgoing Salmon replies (when we don't need a return value) - $qm->connect('salmonout', 'SalmonOutQueueHandler'); + $qm->connect('salmon', 'SalmonQueueHandler'); // Incoming from a foreign PuSH hub - $qm->connect('pushinput', 'PushInputQueueHandler'); + $qm->connect('pushin', 'PushInQueueHandler'); return true; } @@ -656,4 +656,51 @@ class OStatusPlugin extends Plugin return true; } + + /** + * Ping remote profiles with updates to this profile. + * Salmon pings are queued for background processing. + */ + function onEndBroadcastProfile(Profile $profile) + { + $user = User::staticGet('id', $profile->id); + + // Find foreign accounts I'm subscribed to that support Salmon pings. + // + // @fixme we could run updates through the PuSH feed too, + // in which case we can skip Salmon pings to folks who + // are also subscribed to me. + $sql = "SELECT * FROM ostatus_profile " . + "WHERE profile_id IN " . + "(SELECT subscribed FROM subscription WHERE subscriber=%d) " . + "OR group_id IN " . + "(SELECT group_id FROM group_member WHERE profile_id=%d)"; + $oprofile = new Ostatus_profile(); + $oprofile->query(sprintf($sql, $profile->id, $profile->id)); + + if ($oprofile->N == 0) { + common_log(LOG_DEBUG, "No OStatus remote subscribees for $profile->nickname"); + return true; + } + + $act = new Activity(); + + $act->verb = ActivityVerb::UPDATE_PROFILE; + $act->id = TagURI::mint('update-profile:%d:%s', + $profile->id, + common_date_iso8601(time())); + $act->time = time(); + $act->title = _m("Profile update"); + $act->content = sprintf(_m("%s has updated their profile page."), + $profile->getBestName()); + + $act->actor = ActivityObject::fromProfile($profile); + $act->object = $act->actor; + + while ($oprofile->fetch()) { + $oprofile->notifyDeferred($act); + } + + return true; + } } diff --git a/plugins/OStatus/actions/pushcallback.php b/plugins/OStatus/actions/pushcallback.php index 4184f0e0c0..9a2067b8ca 100644 --- a/plugins/OStatus/actions/pushcallback.php +++ b/plugins/OStatus/actions/pushcallback.php @@ -68,7 +68,7 @@ class PushCallbackAction extends Action 'post' => $post, 'hmac' => $hmac); $qm = QueueManager::get(); - $qm->enqueue($data, 'pushinput'); + $qm->enqueue($data, 'pushin'); } /** diff --git a/plugins/OStatus/classes/HubSub.php b/plugins/OStatus/classes/HubSub.php index eae2928c32..1ac181feeb 100644 --- a/plugins/OStatus/classes/HubSub.php +++ b/plugins/OStatus/classes/HubSub.php @@ -164,7 +164,7 @@ class HubSub extends Memcached_DataObject 'token' => $token, 'retries' => $retries); $qm = QueueManager::get(); - $qm->enqueue($data, 'hubverify'); + $qm->enqueue($data, 'hubconf'); } /** diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 9f9efb96ee..61505206ec 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -431,21 +431,57 @@ class Ostatus_profile extends Memcached_DataObject return false; } - public function notifyActivity($activity) + /** + * Send a Salmon notification ping immediately, and confirm that we got + * an acceptable response from the remote site. + * + * @param mixed $entry XML string, Notice, or Activity + * @return boolean success + */ + public function notifyActivity($entry) { if ($this->salmonuri) { - - $xml = '' . - $activity->asString(true); - - $salmon = new Salmon(); // ? - - return $salmon->post($this->salmonuri, $xml); + $salmon = new Salmon(); + return $salmon->post($this->salmonuri, $this->notifyPrepXml($entry)); } return false; } + /** + * Queue a Salmon notification for later. If queues are disabled we'll + * send immediately but won't get the return value. + * + * @param mixed $entry XML string, Notice, or Activity + * @return boolean success + */ + public function notifyDeferred($entry) + { + if ($this->salmonuri) { + $data = array('salmonuri' => $this->salmonuri, + 'entry' => $this->notifyPrepXml($entry)); + + $qm = QueueManager::get(); + return $qm->enqueue($data, 'salmon'); + } + + return false; + } + + protected function notifyPrepXml($entry) + { + $preamble = ''; + if (is_string($entry)) { + return $entry; + } else if ($entry instanceof Activity) { + return $preamble . $entry->asString(true); + } else if ($entry instanceof Notice) { + return $preamble . $entry->asAtomEntry(true, true); + } else { + throw new ServerException("Invalid type passed to Ostatus_profile::notify; must be XML string or Activity entry"); + } + } + function getBestName() { if ($this->isGroup()) { diff --git a/plugins/OStatus/lib/hubverifyqueuehandler.php b/plugins/OStatus/lib/hubconfqueuehandler.php similarity index 95% rename from plugins/OStatus/lib/hubverifyqueuehandler.php rename to plugins/OStatus/lib/hubconfqueuehandler.php index 7ce9e14312..c8e0b72fee 100644 --- a/plugins/OStatus/lib/hubverifyqueuehandler.php +++ b/plugins/OStatus/lib/hubconfqueuehandler.php @@ -22,11 +22,11 @@ * @package Hub * @author Brion Vibber */ -class HubVerifyQueueHandler extends QueueHandler +class HubConfQueueHandler extends QueueHandler { function transport() { - return 'hubverify'; + return 'hubconf'; } function handle($data) diff --git a/plugins/OStatus/lib/ostatusqueuehandler.php b/plugins/OStatus/lib/ostatusqueuehandler.php index c1e50bffa1..0da85600fb 100644 --- a/plugins/OStatus/lib/ostatusqueuehandler.php +++ b/plugins/OStatus/lib/ostatusqueuehandler.php @@ -83,23 +83,11 @@ class OStatusQueueHandler extends QueueHandler function pingReply($oprofile) { if ($this->user) { - if (!empty($oprofile->salmonuri)) { - // For local posts, send a Salmon ping to the mentioned - // remote user or group. - // @fixme as an optimization we can skip this if the - // remote profile is subscribed to the author. - - common_log(LOG_INFO, "Prepping to send notice '{$this->notice->uri}' to remote profile '{$oprofile->uri}'."); - - $xml = ''; - $xml .= $this->notice->asAtomEntry(true, true); - - $data = array('salmonuri' => $oprofile->salmonuri, - 'entry' => $xml); - - $qm = QueueManager::get(); - $qm->enqueue($data, 'salmonout'); - } + // For local posts, send a Salmon ping to the mentioned + // remote user or group. + // @fixme as an optimization we can skip this if the + // remote profile is subscribed to the author. + $oprofile->notifyDeferred($this->notice); } } diff --git a/plugins/OStatus/lib/pushinputqueuehandler.php b/plugins/OStatus/lib/pushinqueuehandler.php similarity index 94% rename from plugins/OStatus/lib/pushinputqueuehandler.php rename to plugins/OStatus/lib/pushinqueuehandler.php index cbd9139b50..a90f52df26 100644 --- a/plugins/OStatus/lib/pushinputqueuehandler.php +++ b/plugins/OStatus/lib/pushinqueuehandler.php @@ -23,11 +23,11 @@ * @author Brion Vibber */ -class PushInputQueueHandler extends QueueHandler +class PushInQueueHandler extends QueueHandler { function transport() { - return 'pushinput'; + return 'pushin'; } function handle($data) diff --git a/plugins/OStatus/lib/salmonoutqueuehandler.php b/plugins/OStatus/lib/salmonqueuehandler.php similarity index 94% rename from plugins/OStatus/lib/salmonoutqueuehandler.php rename to plugins/OStatus/lib/salmonqueuehandler.php index 536ff94af6..aa97018dc9 100644 --- a/plugins/OStatus/lib/salmonoutqueuehandler.php +++ b/plugins/OStatus/lib/salmonqueuehandler.php @@ -22,11 +22,11 @@ * @package OStatusPlugin * @author Brion Vibber */ -class SalmonOutQueueHandler extends QueueHandler +class SalmonQueueHandler extends QueueHandler { function transport() { - return 'salmonout'; + return 'salmon'; } function handle($data) From c0d13097dd96b3596b43e34e7fff0acd97a838f0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Feb 2010 15:54:13 -0500 Subject: [PATCH 184/190] use Notice::bestUrl() to determine notice url in NoticeListItem::showNoticeLink() --- lib/noticelist.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/noticelist.php b/lib/noticelist.php index dcf17be08c..28a563d875 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -380,12 +380,12 @@ class NoticeListItem extends Widget function showNoticeLink() { - if($this->notice->is_local == Notice::LOCAL_PUBLIC || $this->notice->is_local == Notice::LOCAL_NONPUBLIC){ - $noticeurl = common_local_url('shownotice', - array('notice' => $this->notice->id)); - }else{ - $noticeurl = $this->notice->uri; - } + $noticeurl = $this->notice->bestUrl(); + + // above should always return an URL + + assert(!empty($noticeurl)); + $this->out->elementStart('a', array('rel' => 'bookmark', 'class' => 'timestamp', 'href' => $noticeurl)); From ec4899e6179f2d9b368e6fc04041dd72c2ac2596 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 24 Feb 2010 22:16:17 +0000 Subject: [PATCH 185/190] OStatus: disable HTMLPurify cache unless we've configured a writable path for it. Updated plugin README with available config options. Cleanup for a bad element fallback lookup in Activity --- lib/activity.php | 26 ++++++----- plugins/OStatus/README | 50 +++++++++++++-------- plugins/OStatus/classes/Ostatus_profile.php | 22 ++++++++- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/lib/activity.php b/lib/activity.php index 33932ad0ef..25727bf2b5 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -167,16 +167,18 @@ class PoCo PoCo::NS ); - $formatted = ActivityUtils::childContent( - $addressEl, - PoCoAddress::FORMATTED, - self::NS - ); + if (!empty($addressEl)) { + $formatted = ActivityUtils::childContent( + $addressEl, + PoCoAddress::FORMATTED, + self::NS + ); - if (!empty($formatted)) { - $address = new PoCoAddress(); - $address->formatted = $formatted; - return $address; + if (!empty($formatted)) { + $address = new PoCoAddress(); + $address->formatted = $formatted; + return $address; + } } return null; @@ -292,7 +294,7 @@ class ActivityUtils * @return string related link, if any */ - static function getLink($element, $rel, $type=null) + static function getLink(DOMNode $element, $rel, $type=null) { $links = $element->getElementsByTagnameNS(self::ATOM, self::LINK); @@ -320,7 +322,7 @@ class ActivityUtils * @return DOMElement found element or null */ - static function child($element, $tag, $namespace=self::ATOM) + static function child(DOMNode $element, $tag, $namespace=self::ATOM) { $els = $element->childNodes; if (empty($els) || $els->length == 0) { @@ -345,7 +347,7 @@ class ActivityUtils * @return string content of the child */ - static function childContent($element, $tag, $namespace=self::ATOM) + static function childContent(DOMNode $element, $tag, $namespace=self::ATOM) { $el = self::child($element, $tag, $namespace); diff --git a/plugins/OStatus/README b/plugins/OStatus/README index cbf3adbb9c..09a59e3497 100644 --- a/plugins/OStatus/README +++ b/plugins/OStatus/README @@ -2,23 +2,37 @@ Plugin to support importing updates from external RSS and Atom feeds into your t Uses PubSubHubbub for push feed updates; currently non-PuSH feeds cannot be subscribed. +Configuration options available: + +$config['ostatus']['hub'] + (default internal hub) + Set to URL of an external PuSH hub to use it instead of our internal hub. + +$config['ostatus']['hub_retries'] + (default 0) + Number of times to retry a PuSH send to consumers if using internal hub + +$config['ostatus']['purify_cache'] + (default cache disabled) + Set to a writable cache directory for HTMLPurifier's configuration settings, can speed up processing of remote messages (have not tested by how much) + + +For testing, shouldn't be used in production: + +$config['ostatus']['skip_signatures'] + (default use signatures) + Disable generation and validation of Salmon magicenv signatures + +$config['feedsub']['nohub'] + (default require hub) + Allow low-level feed subscription setup for feeds without hubs. + Not actually usable at this stage, OStatus will check for hubs too + and we have no polling backend. + + Todo: -* set feed icon avatar for actual profiles as well as for preview -* use channel image and/or favicon for avatar? -* garbage-collect subscriptions that are no longer being used -* administrative way to kill feeds? -* functional l10n -* clean up subscription form look and workflow -* use ajax for test/preview in subscription form -* rssCloud support? (Does anything use it that doesn't support PuSH as well?) -* possibly a polling daemon to support non-PuSH feeds? -* likely problems with multiple feeds from the same site, such as category feeds on a blog - (currently each feed would publish a separate notice on a separate profile, but pointing to the same post URI.) - (could use the local URI I guess, but that's so icky!) -* problems with Atom feeds that list but don't have the type - (such as http://atomgen.appspot.com/feed/5 demo feed); currently it's not recognized and we end up with the feed's master URI -* make it easier to see what you're subscribed to and unsub from things -* saner treatment of fullname/nickname? +* fully functional l10n +* redo non-OStatus feed support +** rssCloud support? +** possibly a polling daemon to support non-PuSH feeds? * make use of tags/categories from feeds -* update feed profile data when it changes -* XML_Feed_Parser has major problems with category and link tags; consider replacing? diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 5e38a523ea..c755a094e6 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -668,9 +668,27 @@ class Ostatus_profile extends Memcached_DataObject */ protected function purify($html) { - // @fixme disable caching or set a sane temp dir require_once(INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php'); - $purifier = new HTMLPurifier(); + + // By default Purifier wants to cache data to its own code directories, + // and spews error messages if they're not writable. + $config = HTMLPurifier_Config::createDefault(); + if (common_config('ostatus', 'purify_cache')) { + $config->set('Cache.SerializerPath', common_config('ostatus', 'purify_cache')); + } else { + // Although recommended in the documentation, this produces a notice: + // "Core.DefinitionCache is an alias, preferred directive name is Cache.DefinitionImpl" + // If I then follow *those* directions, I get a warning and it doesn't work: + // "Cannot set undefined directive Core.DefinitionImpl" + // So... lesser of two evils. Suppressing the notice from output, + // though it'll still be seen and logged by StatusNet's error handler. + $old = error_reporting(); + error_reporting($old & ~E_NOTICE); + $config->set('Core.DefinitionCache', null); + error_reporting($old); + } + + $purifier = new HTMLPurifier($config); return $purifier->purify($html); } From b782225ade7ac213222882513d89008902910256 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Feb 2010 00:10:36 +0100 Subject: [PATCH 186/190] Revert "Updated jQuery Form Plugin from v2.17 to v2.36" This reverts commit 72037d61436978daa1edbd19d52b7e6fc6ae1fa8. Until some of the XHR notice related bugs are sorted out in Opera and Chromium, reverting back to the previous version. It throws slightly less errors. XHR file attachments is still a bit problematic in Opera 10.10/Ubuntu, Opera 10.10/Windows, and Chrome 4/Ubuntu. But this revert will at least allow regular XHR notices to work okay in Opera and Chromium. Standards suck! --- js/jquery.form.js | 1292 ++++++++++++++++++++++----------------------- 1 file changed, 632 insertions(+), 660 deletions(-) diff --git a/js/jquery.form.js b/js/jquery.form.js index dde394270f..936b847abe 100644 --- a/js/jquery.form.js +++ b/js/jquery.form.js @@ -1,660 +1,632 @@ -/* - * jQuery Form Plugin - * version: 2.36 (07-NOV-2009) - * @requires jQuery v1.2.6 or later - * - * Examples and documentation at: http://malsup.com/jquery/form/ - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - */ -;(function($) { - -/* - Usage Note: - ----------- - Do not use both ajaxSubmit and ajaxForm on the same form. These - functions are intended to be exclusive. Use ajaxSubmit if you want - to bind your own submit handler to the form. For example, - - $(document).ready(function() { - $('#myForm').bind('submit', function() { - $(this).ajaxSubmit({ - target: '#output' - }); - return false; // <-- important! - }); - }); - - Use ajaxForm when you want the plugin to manage all the event binding - for you. For example, - - $(document).ready(function() { - $('#myForm').ajaxForm({ - target: '#output' - }); - }); - - When using ajaxForm, the ajaxSubmit function will be invoked for you - at the appropriate time. -*/ - -/** - * ajaxSubmit() provides a mechanism for immediately submitting - * an HTML form using AJAX. - */ -$.fn.ajaxSubmit = function(options) { - // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) - if (!this.length) { - log('ajaxSubmit: skipping submit process - no element selected'); - return this; - } - - if (typeof options == 'function') - options = { success: options }; - - var url = $.trim(this.attr('action')); - if (url) { - // clean url (don't include hash vaue) - url = (url.match(/^([^#]+)/)||[])[1]; - } - url = url || window.location.href || ''; - - options = $.extend({ - url: url, - type: this.attr('method') || 'GET', - iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' - }, options || {}); - - // hook for manipulating the form data before it is extracted; - // convenient for use with rich editors like tinyMCE or FCKEditor - var veto = {}; - this.trigger('form-pre-serialize', [this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); - return this; - } - - // provide opportunity to alter form data before it is serialized - if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSerialize callback'); - return this; - } - - var a = this.formToArray(options.semantic); - if (options.data) { - options.extraData = options.data; - for (var n in options.data) { - if(options.data[n] instanceof Array) { - for (var k in options.data[n]) - a.push( { name: n, value: options.data[n][k] } ); - } - else - a.push( { name: n, value: options.data[n] } ); - } - } - - // give pre-submit callback an opportunity to abort the submit - if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSubmit callback'); - return this; - } - - // fire vetoable 'validate' event - this.trigger('form-submit-validate', [a, this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); - return this; - } - - var q = $.param(a); - - if (options.type.toUpperCase() == 'GET') { - options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; - options.data = null; // data is null for 'get' - } - else - options.data = q; // data is the query string for 'post' - - var $form = this, callbacks = []; - if (options.resetForm) callbacks.push(function() { $form.resetForm(); }); - if (options.clearForm) callbacks.push(function() { $form.clearForm(); }); - - // perform a load on the target only if dataType is not provided - if (!options.dataType && options.target) { - var oldSuccess = options.success || function(){}; - callbacks.push(function(data) { - $(options.target).html(data).each(oldSuccess, arguments); - }); - } - else if (options.success) - callbacks.push(options.success); - - options.success = function(data, status) { - for (var i=0, max=callbacks.length; i < max; i++) - callbacks[i].apply(options, [data, status, $form]); - }; - - // are there files to upload? - var files = $('input:file', this).fieldValue(); - var found = false; - for (var j=0; j < files.length; j++) - if (files[j]) - found = true; - - var multipart = false; -// var mp = 'multipart/form-data'; -// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); - - // options.iframe allows user to force iframe mode - // 06-NOV-09: now defaulting to iframe mode if file input is detected - if ((files.length && options.iframe !== false) || options.iframe || found || multipart) { - // hack to fix Safari hang (thanks to Tim Molendijk for this) - // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d - if (options.closeKeepAlive) - $.get(options.closeKeepAlive, fileUpload); - else - fileUpload(); - } - else - $.ajax(options); - - // fire 'notify' event - this.trigger('form-submit-notify', [this, options]); - return this; - - - // private function for handling file uploads (hat tip to YAHOO!) - function fileUpload() { - var form = $form[0]; - - if ($(':input[name=submit]', form).length) { - alert('Error: Form elements must not be named "submit".'); - return; - } - - var opts = $.extend({}, $.ajaxSettings, options); - var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts); - - var id = 'jqFormIO' + (new Date().getTime()); - var $io = $('