]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch 'testing' into 0.9.x
authorBrion Vibber <brion@pobox.com>
Mon, 3 May 2010 19:25:29 +0000 (12:25 -0700)
committerBrion Vibber <brion@pobox.com>
Mon, 3 May 2010 19:25:29 +0000 (12:25 -0700)
172 files changed:
EVENTS.txt
actions/allrss.php
actions/apigrouplist.php
actions/apigrouplistall.php
actions/apistatusesupdate.php
actions/apitimelinefriends.php
actions/apitimelinehome.php
actions/apitimelinepublic.php
actions/block.php
actions/confirmaddress.php
actions/deleteapplication.php
actions/deletenotice.php
actions/deleteuser.php
actions/designadminpanel.php
actions/emailsettings.php
actions/groupblock.php
actions/grouprss.php
actions/imsettings.php
actions/invite.php
actions/register.php
actions/shownotice.php
actions/smssettings.php
actions/snapshotadminpanel.php
actions/tag.php
actions/usergroups.php
actions/userrss.php
classes/File.php
classes/Notice.php
classes/Safe_DataObject.php
classes/Subscription.php
extlib/Net/LDAP2.php [deleted file]
extlib/Net/LDAP2/Entry.php [deleted file]
extlib/Net/LDAP2/Filter.php [deleted file]
extlib/Net/LDAP2/LDIF.php [deleted file]
extlib/Net/LDAP2/RootDSE.php [deleted file]
extlib/Net/LDAP2/Schema.php [deleted file]
extlib/Net/LDAP2/SchemaCache.interface.php [deleted file]
extlib/Net/LDAP2/Search.php [deleted file]
extlib/Net/LDAP2/SimpleFileSchemaCache.php [deleted file]
extlib/Net/LDAP2/Util.php [deleted file]
index.php
lib/accountsettingsaction.php
lib/action.php
lib/activity.php
lib/adminpanelaction.php
lib/apiaction.php
lib/apiauth.php
lib/applicationeditform.php
lib/applicationlist.php
lib/atomgroupnoticefeed.php
lib/atomusernoticefeed.php
lib/attachmentlist.php
lib/authorizationplugin.php
lib/command.php
lib/htmloutputter.php
lib/language.php
lib/mediafile.php
lib/noticeform.php
lib/noticelist.php
lib/profileaction.php
lib/util.php
locale/af/LC_MESSAGES/statusnet.po
locale/ar/LC_MESSAGES/statusnet.po
locale/arz/LC_MESSAGES/statusnet.po
locale/bg/LC_MESSAGES/statusnet.po
locale/br/LC_MESSAGES/statusnet.po
locale/ca/LC_MESSAGES/statusnet.po
locale/cs/LC_MESSAGES/statusnet.po
locale/de/LC_MESSAGES/statusnet.po
locale/el/LC_MESSAGES/statusnet.po
locale/en_GB/LC_MESSAGES/statusnet.po
locale/es/LC_MESSAGES/statusnet.po
locale/fa/LC_MESSAGES/statusnet.po
locale/fi/LC_MESSAGES/statusnet.po
locale/fr/LC_MESSAGES/statusnet.po
locale/ga/LC_MESSAGES/statusnet.po
locale/gl/LC_MESSAGES/statusnet.po
locale/he/LC_MESSAGES/statusnet.po
locale/hsb/LC_MESSAGES/statusnet.po
locale/ia/LC_MESSAGES/statusnet.po
locale/is/LC_MESSAGES/statusnet.po
locale/it/LC_MESSAGES/statusnet.po
locale/ja/LC_MESSAGES/statusnet.po
locale/ko/LC_MESSAGES/statusnet.po
locale/mk/LC_MESSAGES/statusnet.po
locale/nb/LC_MESSAGES/statusnet.po
locale/nl/LC_MESSAGES/statusnet.po
locale/nn/LC_MESSAGES/statusnet.po
locale/pl/LC_MESSAGES/statusnet.po
locale/pt/LC_MESSAGES/statusnet.po
locale/pt_BR/LC_MESSAGES/statusnet.po
locale/ru/LC_MESSAGES/statusnet.po
locale/statusnet.pot
locale/sv/LC_MESSAGES/statusnet.po
locale/te/LC_MESSAGES/statusnet.po
locale/tr/LC_MESSAGES/statusnet.po
locale/uk/LC_MESSAGES/statusnet.po
locale/vi/LC_MESSAGES/statusnet.po
locale/zh_CN/LC_MESSAGES/statusnet.po
locale/zh_TW/LC_MESSAGES/statusnet.po
plugins/AutoSandbox/AutoSandboxPlugin.php [new file with mode: 0644]
plugins/AutoSandbox/LICENSE [new file with mode: 0644]
plugins/AutoSandbox/README [new file with mode: 0644]
plugins/AutoSandbox/locale/AutoSandbox.pot [new file with mode: 0644]
plugins/Autocomplete/AutocompletePlugin.php
plugins/Autocomplete/locale/Autocomplete.pot [new file with mode: 0644]
plugins/BitlyUrl/locale/BitlyUrl.pot [new file with mode: 0644]
plugins/Blacklist/locale/Blacklist.pot [new file with mode: 0644]
plugins/CasAuthentication/locale/CasAuthentication.pot [new file with mode: 0644]
plugins/ClientSideShorten/ClientSideShortenPlugin.php [new file with mode: 0644]
plugins/ClientSideShorten/README [new file with mode: 0644]
plugins/ClientSideShorten/locale/ClientSideShorten.pot [new file with mode: 0644]
plugins/ClientSideShorten/shorten.js [new file with mode: 0644]
plugins/ClientSideShorten/shorten.php [new file with mode: 0644]
plugins/DirectionDetector/locale/DirectionDetector.pot [new file with mode: 0644]
plugins/EmailAuthentication/locale/EmailAuthentication.pot [new file with mode: 0644]
plugins/Facebook/locale/Facebook.pot
plugins/FirePHP/FirePHPPlugin.php
plugins/FirePHP/locale/FirePHP.pot [new file with mode: 0644]
plugins/Gravatar/locale/Gravatar.pot
plugins/Imap/locale/Imap.pot [new file with mode: 0644]
plugins/InfiniteScroll/locale/InfiniteScroll.pot [new file with mode: 0644]
plugins/LdapAuthentication/LdapAuthenticationPlugin.php
plugins/LdapAuthentication/MemcacheSchemaCache.php [deleted file]
plugins/LdapAuthentication/locale/LdapAuthentication.pot [new file with mode: 0644]
plugins/LdapAuthorization/LdapAuthorizationPlugin.php
plugins/LdapAuthorization/locale/LdapAuthorization.pot [new file with mode: 0644]
plugins/LdapCommon/LdapCommon.php [new file with mode: 0644]
plugins/LdapCommon/MemcacheSchemaCache.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/Entry.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/Filter.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/Schema.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/SchemaCache.interface.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/Search.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/SimpleFileSchemaCache.php [new file with mode: 0644]
plugins/LdapCommon/extlib/Net/LDAP2/Util.php [new file with mode: 0644]
plugins/LilUrl/locale/LilUrl.pot [new file with mode: 0644]
plugins/Mapstraction/locale/Mapstraction.pot
plugins/Minify/locale/Minify.pot [new file with mode: 0644]
plugins/MobileProfile/locale/MobileProfile.pot [new file with mode: 0644]
plugins/OStatus/locale/OStatus.pot
plugins/OStatus/locale/fr/LC_MESSAGES/OStatus.po [deleted file]
plugins/OpenExternalLinkTarget/locale/OpenExternalLinkTarget.pot [new file with mode: 0644]
plugins/OpenID/OpenIDPlugin.php
plugins/OpenID/finishaddopenid.php
plugins/OpenID/finishopenidlogin.php
plugins/OpenID/locale/OpenID.pot
plugins/OpenID/locale/nl/LC_MESSAGES/OpenID.po
plugins/OpenID/openid.php
plugins/OpenID/openidlogin.php
plugins/OpenID/openidserver.php
plugins/PostDebug/locale/PostDebug.pot [new file with mode: 0644]
plugins/PoweredByStatusNet/locale/PoweredByStatusNet.pot
plugins/PtitUrl/locale/PtitUrl.pot [new file with mode: 0644]
plugins/RSSCloud/locale/RSSCloud.pot [new file with mode: 0644]
plugins/Recaptcha/locale/Recaptcha.pot [new file with mode: 0644]
plugins/RegisterThrottle/locale/RegisterThrottle.pot [new file with mode: 0644]
plugins/RequireValidatedEmail/locale/RequireValidatedEmail.pot
plugins/ReverseUsernameAuthentication/locale/ReverseUsernameAuthentication.pot [new file with mode: 0644]
plugins/Sample/locale/Sample.pot
plugins/SimpleUrl/locale/SimpleUrl.pot [new file with mode: 0644]
plugins/SpotifyPlugin.php [new file with mode: 0644]
plugins/TabFocus/locale/TabFocus.pot [new file with mode: 0644]
plugins/TightUrl/locale/TightUrl.pot [new file with mode: 0644]
plugins/TwitterBridge/locale/TwitterBridge.pot
scripts/apidocs.config [new file with mode: 0644]
scripts/docgen.php [new file with mode: 0755]
scripts/doxygen.tmpl [new file with mode: 0644]
scripts/update_translations.php

index 2da6f3da61b1e89438e269424c8ad2fdc2f3f307..cf9c6123f34894f9bdaa0f737317ab87f78ebbdd 100644 (file)
@@ -141,7 +141,7 @@ StartLogout: Before logging out
 EndLogout: After logging out
 - $action: the logout action
 
-ArgsInitialized: After the argument array has been initialized
+ArgsInitialize: After the argument array has been initialized
 - $args: associative array of arguments, can be modified
 
 StartAddressData: Allows the site owner to provide additional information about themselves for contact (e.g., tagline, email, location)
index 01e737ad7bb65300df8b166dd39eb6351b2deada..7df0b1ef7c67c0ee2dc7389f9bede96d7373cdda 100644 (file)
@@ -112,10 +112,12 @@ class AllrssAction extends Rss10Action
         $c    = array('url' => common_local_url('allrss',
                                              array('nickname' =>
                                                    $user->nickname)),
+                   // TRANS: Message is used as link title. %s is a user nickname.
                    'title' => sprintf(_('%s and friends'), $user->nickname),
                    'link' => common_local_url('all',
                                              array('nickname' =>
                                                    $user->nickname)),
+                   // TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
                    'description' => sprintf(_('Updates from %1$s and friends on %2$s!'),
                                             $user->nickname, common_config('site', 'name')));
         return $c;
index dd2a68c66e9089fde8f63cc02c526ca05ad8dd4f..3ea2c30cbb8e55e11522ee036745d4a8df76b801 100644 (file)
@@ -93,6 +93,7 @@ class ApiGroupListAction extends ApiBareAuthAction
         parent::handle($args);
 
         $sitename   = common_config('site', 'name');
+        // TRANS: %s is a user name
         $title      = sprintf(_("%s's groups"), $this->user->nickname);
         $taguribase = TagURI::base();
         $id         = "tag:$taguribase:Groups";
@@ -100,10 +101,12 @@ class ApiGroupListAction extends ApiBareAuthAction
             'usergroups',
             array('nickname' => $this->user->nickname)
         );
+
         $subtitle   = sprintf(
-            _("Groups %1\$s is a member of on %2\$s."),
-            $this->user->nickname,
-            $sitename
+            // TRANS: Meant to convey the user %2$s is a member of each of the groups listed on site %1$s
+            _("%1\$s groups %2\$s is a member of."),
+            $sitename,
+            $this->user->nickname
         );
 
         switch($this->format) {
index f7677970f8e387442c49569c57e07c1ddbd318a2..bd05fa3ea880712a1c1061af5d7039d0730bbbd4 100644 (file)
@@ -87,6 +87,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
         parent::handle($args);
 
         $sitename   = common_config('site', 'name');
+        // TRANS: Message is used as a title. %s is a site name.
         $title      = sprintf(_("%s groups"), $sitename);
         $taguribase = TagURI::base();
         $id         = "tag:$taguribase:Groups";
index d4ef6b550d974743f26858c945bf576bda05eb24..5f3a447c23867505827e60946fd8c43906fe1e8a 100644 (file)
  * @link      http://status.net/
  */
 
+/* External API usage documentation. Please update when you change how this method works. */
+
+/*! @page statusesupdate statuses/update
+
+    @section Description
+    Updates the authenticating user's status. Requires the status parameter specified below.
+    Request must be a POST.
+
+    @par URL pattern
+    /api/statuses/update.:format
+
+    @par Formats (:format)
+    xml, json
+
+    @par HTTP Method(s)
+    POST
+
+    @par Requires Authentication
+    Yes
+
+    @param status (Required) The URL-encoded text of the status update.
+    @param source (Optional) The source of the status.
+    @param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
+    @param lat (Optional) The latitude the status refers to.
+    @param long (Optional) The longitude the status refers to.
+    @param media (Optional) a media upload, such as an image or movie file.
+
+    @sa @ref authentication
+    @sa @ref apiroot
+
+    @subsection usagenotes Usage notes
+
+    @li The URL pattern is relative to the @ref apiroot.
+    @li If the @e source parameter is not supplied the source of the status will default to 'api'.
+    @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
+    to encode the latitude and longitude (see example response below <georss:point>).
+    @li Data uploaded via the @e media parameter should be multipart/form-data encoded.
+
+    @subsection exampleusage Example usage
+
+    @verbatim
+    curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743'
+    @endverbatim
+
+    @subsection exampleresponse Example response
+
+    @verbatim
+    <?xml version="1.0" encoding="UTF-8"?>
+    <status>
+      <text>Howdy!</text>
+      <truncated>false</truncated>
+      <created_at>Tue Mar 30 23:28:05 +0000 2010</created_at>
+      <in_reply_to_status_id/>
+      <source>api</source>
+      <id>26668724</id>
+      <in_reply_to_user_id/>
+      <in_reply_to_screen_name/>
+      <geo xmlns:georss="http://www.georss.org/georss">
+        <georss:point>30.468 -94.743</georss:point>
+      </geo>
+      <favorited>false</favorited>
+      <user>
+        <id>25803</id>
+        <name>Jed Sanders</name>
+        <screen_name>jedsanders</screen_name>
+        <location>Hoop and Holler, Texas</location>
+        <description>I like to think of myself as America's Favorite.</description>
+        <profile_image_url>http://avatar.example.com/25803-48-20080924200604.png</profile_image_url>
+        <url>http://jedsanders.net</url>
+        <protected>false</protected>
+        <followers_count>5</followers_count>
+        <profile_background_color/>
+        <profile_text_color/>
+        <profile_link_color/>
+        <profile_sidebar_fill_color/>
+        <profile_sidebar_border_color/>
+        <friends_count>2</friends_count>
+        <created_at>Wed Sep 24 20:04:00 +0000 2008</created_at>
+        <favourites_count>0</favourites_count>
+        <utc_offset>0</utc_offset>
+        <time_zone>UTC</time_zone>
+        <profile_background_image_url/>
+        <profile_background_tile>false</profile_background_tile>
+        <statuses_count>70</statuses_count>
+        <following>true</following>
+        <notifications>true</notifications>
+      </user>
+    </status>
+    @endverbatim
+*/
+
 if (!defined('STATUSNET')) {
     exit(1);
 }
index ac350ab1b7a25acf8c5ee77dba5cd6269089670c..3c25c049e970e2d49ed845291ccec5afca204c08 100644 (file)
  * @author    Mike Cochrane <mikec@mikenz.geek.nz>
  * @author    Robin Millette <robin@millette.info>
  * @author    Zach Copley <zach@status.net>
- * @copyright 2009 StatusNet, Inc.
+ * @copyright 2009-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/
  */
 
+/* External API usage documentation. Please update when you change how this method works. */
+
+/*! @page friendstimeline statuses/friends_timeline
+
+    @section Description
+    Returns the 20 most recent statuses posted by the authenticating
+    user and that user's friends. This is the equivalent of "You and
+    friends" page in the web interface.
+
+    @par URL patterns
+    @li /api/statuses/friends_timeline.:format
+    @li /api/statuses/friends_timeline/:id.:format
+
+    @par Formats (:format)
+    xml, json, rss, atom
+
+    @par ID (:id)
+    username, user id
+
+    @par HTTP Method(s)
+    GET
+
+    @par Requires Authentication
+    Sometimes (see: @ref authentication)
+
+    @param user_id (Optional) Specifies a user by ID
+    @param screen_name (Optional) Specifies a user by screename (nickname)
+    @param since_id (Optional) Returns only statuses with an ID greater
+    than (that is, more recent than) the specified ID.
+    @param max_id (Optional) Returns only statuses with an ID less than
+    (that is, older than) or equal to the specified ID.
+    @param count (Optional) Specifies the number of statuses to retrieve.
+    @param page (Optional) Specifies the page of results to retrieve.
+
+    @sa @ref authentication
+    @sa @ref apiroot
+
+    @subsection usagenotes Usage notes
+    @li The URL pattern is relative to the @ref apiroot.
+    @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
+    to encode the latitude and longitude (see example response below <georss:point>).
+
+    @subsection exampleusage Example usage
+
+    @verbatim
+    curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
+    @endverbatim
+
+    @subsection exampleresponse Example response
+
+    @verbatim
+    <?xml version="1.0"?>
+    <statuses type="array">
+      <status>
+        <text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
+        <truncated>false</truncated>
+        <created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
+        <in_reply_to_status_id/>
+        <source>&lt;a href="http://code.google.com/p/microblog-purple/"&gt;mbpidgin&lt;/a&gt;</source>
+        <id>26674201</id>
+        <in_reply_to_user_id/>
+        <in_reply_to_screen_name/>
+        <geo/>
+        <favorited>false</favorited>
+        <user>
+          <id>246</id>
+          <name>Mark</name>
+          <screen_name>lambic</screen_name>
+          <location>Montreal, Canada</location>
+          <description>Geek</description>
+          <profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
+          <url>http://lambic.co.uk</url>
+          <protected>false</protected>
+          <followers_count>73</followers_count>
+          <profile_background_color>#F0F2F5</profile_background_color>
+          <profile_text_color/>
+          <profile_link_color>#002E6E</profile_link_color>
+          <profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
+          <profile_sidebar_border_color/>
+          <friends_count>58</friends_count>
+          <created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
+          <favourites_count>2</favourites_count>
+          <utc_offset>-14400</utc_offset>
+          <time_zone>US/Eastern</time_zone>
+          <profile_background_image_url/>
+          <profile_background_tile>false</profile_background_tile>
+          <statuses_count>933</statuses_count>
+          <following>false</following>
+          <notifications>false</notifications>
+        </user>
+      </status>
+    </statuses>
+    @endverbatim
+*/
+
 if (!defined('STATUSNET')) {
     exit(1);
 }
@@ -116,6 +211,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
         $id         = "tag:$taguribase:FriendsTimeline:" . $this->user->id;
 
         $subtitle = sprintf(
+            // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
             _('Updates from %1$s and friends on %2$s!'),
             $this->user->nickname,
             $sitename
index 1618c9923c8be7eb79b4c8bd2221afb982bca4b8..43a13dcda9ca09aa1b9786251bb3a9cb25fd4de7 100644 (file)
@@ -117,6 +117,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
         $id         = "tag:$taguribase:HomeTimeline:" . $this->user->id;
 
         $subtitle   = sprintf(
+            // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
             _('Updates from %1$s and friends on %2$s!'),
             $this->user->nickname, $sitename
         );
index 9034614253d438b5566a1993c6b1da0182094b18..30f9f4cda6735ac6dbf5899156d1d08d819e9b48 100644 (file)
@@ -55,6 +55,95 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
  * @link     http://status.net/
  */
 
+/* External API usage documentation. Please update when you change how this method works. */
+
+/*! @page publictimeline statuses/public_timeline
+
+    @section Description
+    Returns the 20 most recent notices from users throughout the system who have
+    uploaded their own avatars. Depending on configuration, it may or may not
+    not include notices from automatic posting services.
+
+    @par URL patterns
+    @li /api/statuses/public_timeline.:format
+
+    @par Formats (:format)
+    xml, json, rss, atom
+
+    @par HTTP Method(s)
+    GET
+
+    @par Requires Authentication
+    No
+
+    @param since_id (Optional) Returns only statuses with an ID greater
+    than (that is, more recent than) the specified ID.
+    @param max_id (Optional) Returns only statuses with an ID less than
+    (that is, older than) or equal to the specified ID.
+    @param count (Optional) Specifies the number of statuses to retrieve.
+    @param page (Optional) Specifies the page of results to retrieve.
+
+    @sa @ref apiroot
+
+    @subsection usagenotes Usage notes
+    @li The URL pattern is relative to the @ref apiroot.
+    @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
+    to encode the latitude and longitude (see example response below <georss:point>).
+
+    @subsection exampleusage Example usage
+
+    @verbatim
+    curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
+    @endverbatim
+
+    @subsection exampleresponse Example response
+
+    @verbatim
+    <?xml version="1.0" encoding="UTF-8"?>
+    <statuses type="array">
+     <status>
+      <text>@skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though</text>
+      <truncated>false</truncated>
+      <created_at>Sat Apr 17 00:49:12 +0000 2010</created_at>
+      <in_reply_to_status_id>28838393</in_reply_to_status_id>
+      <source>xmpp</source>
+      <id>28838456</id>
+      <in_reply_to_user_id>39303</in_reply_to_user_id>
+      <in_reply_to_screen_name>skwashd</in_reply_to_screen_name>
+      <geo></geo>
+      <favorited>false</favorited>
+      <user>
+       <id>44517</id>
+       <name>joshua may</name>
+       <screen_name>notjosh</screen_name>
+       <location></location>
+       <description></description>
+       <profile_image_url>http://avatar.identi.ca/44517-48-20090321004106.jpeg</profile_image_url>
+       <url></url>
+       <protected>false</protected>
+       <followers_count>17</followers_count>
+       <profile_background_color></profile_background_color>
+       <profile_text_color></profile_text_color>
+       <profile_link_color></profile_link_color>
+       <profile_sidebar_fill_color></profile_sidebar_fill_color>
+       <profile_sidebar_border_color></profile_sidebar_border_color>
+       <friends_count>20</friends_count>
+       <created_at>Sat Mar 21 00:40:25 +0000 2009</created_at>
+       <favourites_count>0</favourites_count>
+       <utc_offset>0</utc_offset>
+       <time_zone>UTC</time_zone>
+       <profile_background_image_url></profile_background_image_url>
+       <profile_background_tile>false</profile_background_tile>
+       <statuses_count>100</statuses_count>
+       <following>false</following>
+       <notifications>false</notifications>
+    </user>
+    </status>
+    [....]
+    </statuses>
+@endverbatim
+*/
+
 class ApiTimelinePublicAction extends ApiPrivateAuthAction
 {
 
index 7f609c253b99b2d270f65c2779f784ebdf0a2d83..11565e20c528d63a4d6920b25180d9ed63a77d9b 100644 (file)
@@ -140,8 +140,20 @@ class BlockAction extends ProfileFormAction
                 $this->hidden($k, $v);
             }
         }
-        $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user"));
-        $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user'));
+        $this->submit('form_action-no',
+                      // TRANS: Button label on the user block form.
+                      _m('BUTTON','No'),
+                      'submit form_action-primary',
+                      'no',
+                      // TRANS: Submit button title for 'No' when blocking a user.
+                      _('Do not block this user'));
+        $this->submit('form_action-yes',
+                      // TRANS: Button label on the user block form.
+                      _m('BUTTON','Yes'),
+                      'submit form_action-secondary',
+                      'yes',
+                      // TRANS: Submit button title for 'Yes' when blocking a user.
+                      _('Block this user'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
index dc17499f551161b6f1f936daa862d7f158cd3ba5..8bf8c8c4d4d7a75de8c27ba5029421d88b3c0aac 100644 (file)
@@ -87,10 +87,12 @@ class ConfirmaddressAction extends Action
         }
         $type = $confirm->address_type;
         if (!in_array($type, array('email', 'jabber', 'sms'))) {
+            // TRANS: Server error for an unknow address type, which can be 'email', 'jabber', or 'sms'.
             $this->serverError(sprintf(_('Unrecognized address type %s.'), $type));
             return;
         }
         if ($cur->$type == $confirm->address) {
+            // TRANS: Client error for an already confirmed email/jabbel/sms address.
             $this->clientError(_('That address has already been confirmed.'));
             return;
         }
index 17526e1118de6647d0df6a858b87be526a133d8e..806de0be6eccbee182f8dfe45184bb7f68f7c179 100644 (file)
@@ -150,13 +150,17 @@ class DeleteapplicationAction extends Action
                          'This will clear all data about the application from the '.
                          'database, including all existing user connections.'));
         $this->submit('form_action-no',
-                      _('No'),
+                      // TRANS: Button label on the delete application form.
+                      _m('BUTTON','No'),
                       'submit form_action-primary',
                       'no',
-                      _("Do not delete this application"));
+                      // TRANS: Submit button title for 'No' when deleting an application.
+                      _('Do not delete this application'));
         $this->submit('form_action-yes',
-                      _('Yes'),
+                      // TRANS: Button label on the delete application form.
+                      _m('BUTTON','Yes'),
                       'submit form_action-secondary',
+                      // TRANS: Submit button title for 'Yes' when deleting an application.
                       'yes', _('Delete this application'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
index 69cb1ebe87982e912dc41ba19d0d740ff0a8e303..f8010a814a330f57ae5da3e82b73d16566da017b 100644 (file)
@@ -142,8 +142,20 @@ class DeletenoticeAction extends Action
         $this->hidden('token', common_session_token());
         $this->hidden('notice', $this->trimmed('notice'));
         $this->element('p', null, _('Are you sure you want to delete this notice?'));
-        $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not delete this notice"));
-        $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Delete this notice'));
+        $this->submit('form_action-no',
+                      // TRANS: Button label on the delete notice form.
+                      _m('BUTTON','No'),
+                      'submit form_action-primary',
+                      'no',
+                      // TRANS: Submit button title for 'No' when deleting a notice.
+                      _("Do not delete this notice"));
+        $this->submit('form_action-yes',
+                      // TRANS: Button label on the delete notice form.
+                      _m('BUTTON','Yes'),
+                      'submit form_action-secondary',
+                      'yes',
+                      // TRANS: Submit button title for 'Yes' when deleting a notice.
+                      _('Delete this notice'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
index 42ef4b9f513de031b77f05acaeb2908c2cd96f75..1c1f19b0e60eb05a8ce7c576928dce2338a418e9 100644 (file)
@@ -147,8 +147,20 @@ class DeleteuserAction extends ProfileFormAction
             }
             Event::handle('EndDeleteUserForm', array($this, $this->user));
         }
-        $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user"));
-        $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Delete this user'));
+        $this->submit('form_action-no',
+                      // TRANS: Button label on the delete user form.
+                      _m('BUTTON','No'),
+                      'submit form_action-primary',
+                      'no',
+                      // TRANS: Submit button title for 'No' when deleting a user.
+                      _('Do not block this user'));
+        $this->submit('form_action-yes',
+                      // TRANS: Button label on the delete user form.
+                      _m('BUTTON','Yes'),
+                      'submit form_action-secondary',
+                      'yes',
+                      // TRANS: Submit button title for 'Yes' when deleting a user.
+                      _('Delete this user'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
index 41d917e3ca2a961256d648244d089fdcc82bca52..8c08581b5d1243af59bbb4ce9a2707396ccb6b41 100644 (file)
@@ -59,6 +59,7 @@ class DesignadminpanelAction extends AdminPanelAction
 
     function title()
     {
+        // TRANS: Message used as title for design settings for the site.
         return _('Design');
     }
 
@@ -454,6 +455,7 @@ class DesignAdminPanelForm extends AdminForm
 
             $this->out->element('label', array('for' => 'design_background-image_on',
                                           'class' => 'radio'),
+                                          // TRANS: Used as radio button label to add a background image.
                                           _('On'));
 
             $attrs = array('name' => 'design_background-image_onoff',
@@ -470,6 +472,7 @@ class DesignAdminPanelForm extends AdminForm
 
             $this->out->element('label', array('for' => 'design_background-image_off',
                                           'class' => 'radio'),
+                                          // TRANS: Used as radio button label to not add a background image.
                                           _('Off'));
             $this->out->element('p', 'form_guide', _('Turn background image on or off.'));
             $this->unli();
index 08608348cdae1f79f077df2dc9b70581996485ed..6138a88f9055ae5af1a58c42cec29ef2595561ac 100644 (file)
@@ -57,6 +57,7 @@ class EmailsettingsAction extends AccountSettingsAction
 
     function title()
     {
+        // TRANS: Title for e-mail settings.
         return _('Email settings');
     }
 
@@ -68,6 +69,10 @@ class EmailsettingsAction extends AccountSettingsAction
 
     function getInstructions()
     {
+        // XXX: For consistency of parameters in messages, this should be a
+        //      regular parameters, replaced with sprintf().
+        // TRANS: E-mail settings page instructions.
+        // TRANS: %%site.name%% is the name of the site.
         return _('Manage how you get email from %%site.name%%.');
     }
 
@@ -97,102 +102,126 @@ class EmailsettingsAction extends AccountSettingsAction
                                           common_local_url('emailsettings')));
         $this->elementStart('fieldset');
         $this->elementStart('fieldset', array('id' => 'settings_email_address'));
-        $this->element('legend', null, _('Address'));
+        // TRANS: Form legend for e-mail settings form.
+        $this->element('legend', null, _('Email address'));
         $this->hidden('token', common_session_token());
 
         if ($user->email) {
             $this->element('p', array('id' => 'form_confirmed'), $user->email);
+            // TRANS: Form note in e-mail settings form.
             $this->element('p', array('class' => 'form_note'), _('Current confirmed email address.'));
             $this->hidden('email', $user->email);
-            $this->submit('remove', _('Remove'));
+            // TRANS: Button label to remove a confirmed e-mail address.
+            $this->submit('remove', _m('BUTTON','Remove'));
         } else {
             $confirm = $this->getConfirmation();
             if ($confirm) {
                 $this->element('p', array('id' => 'form_unconfirmed'), $confirm->address);
+                // TRANS: Form note in e-mail settings form.
                 $this->element('p', array('class' => 'form_note'),
                                         _('Awaiting confirmation on this address. '.
                                         'Check your inbox (and spam box!) for a message '.
                                         'with further instructions.'));
                 $this->hidden('email', $confirm->address);
-                $this->submit('cancel', _('Cancel'));
+                // TRANS: Button label to cancel an e-mail address confirmation procedure.
+                $this->submit('cancel', _m('BUTTON','Cancel'));
             } else {
                 $this->elementStart('ul', 'form_data');
                 $this->elementStart('li');
+                // TRANS: Field label for e-mail address input in e-mail settings form.
                 $this->input('email', _('Email address'),
                              ($this->arg('email')) ? $this->arg('email') : null,
+                             // TRANS: Instructions for e-mail address input form.
                              _('Email address, like "UserName@example.org"'));
                 $this->elementEnd('li');
                 $this->elementEnd('ul');
-                $this->submit('add', _('Add'));
+                // TRANS: Button label for adding an e-mail address in e-mail settings form.
+                $this->submit('add', _m('BUTTON','Add'));
             }
         }
         $this->elementEnd('fieldset');
 
        if (common_config('emailpost', 'enabled') && $user->email) {
             $this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
+            // TRANS: Form legend for incoming e-mail settings form.
             $this->element('legend', null, _('Incoming email'));
             if ($user->incomingemail) {
                 $this->elementStart('p');
                 $this->element('span', 'address', $user->incomingemail);
+                // XXX: Looks a little awkward in the UI.
+                //      Something like "xxxx@identi.ca  Send email ..". Needs improvement.
                 $this->element('span', 'input_instructions',
+                               // TRANS: Form instructions for incoming e-mail form in e-mail settings.
                                _('Send email to this address to post new notices.'));
                 $this->elementEnd('p');
-                $this->submit('removeincoming', _('Remove'));
+                // TRANS: Button label for removing a set sender e-mail address to post notices from.
+                $this->submit('removeincoming', _m('BUTTON','Remove'));
             }
 
             $this->elementStart('p');
             $this->element('span', 'input_instructions',
+                           // TRANS: Instructions for incoming e-mail address input form.
                            _('Make a new email address for posting to; '.
                              'cancels the old one.'));
             $this->elementEnd('p');
-            $this->submit('newincoming', _('New'));
+            // TRANS: Button label for adding an e-mail address to send notices from.
+            $this->submit('newincoming', _m('BUTTON','New'));
             $this->elementEnd('fieldset');
         }
 
         $this->elementStart('fieldset', array('id' => 'settings_email_preferences'));
-        $this->element('legend', null, _('Preferences'));
+        // TRANS: Form legend for e-mail preferences form.
+        $this->element('legend', null, _('Email preferences'));
 
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
         $this->checkbox('emailnotifysub',
+                        // TRANS: Checkbox label in e-mail preferences form.
                         _('Send me notices of new subscriptions through email.'),
                         $user->emailnotifysub);
         $this->elementEnd('li');
         $this->elementStart('li');
         $this->checkbox('emailnotifyfav',
+                        // TRANS: Checkbox label in e-mail preferences form.
                         _('Send me email when someone '.
                           'adds my notice as a favorite.'),
                         $user->emailnotifyfav);
         $this->elementEnd('li');
         $this->elementStart('li');
         $this->checkbox('emailnotifymsg',
+                        // TRANS: Checkbox label in e-mail preferences form.
                         _('Send me email when someone sends me a private message.'),
                         $user->emailnotifymsg);
         $this->elementEnd('li');
         $this->elementStart('li');
         $this->checkbox('emailnotifyattn',
+                        // TRANS: Checkbox label in e-mail preferences form.
                         _('Send me email when someone sends me an "@-reply".'),
                         $user->emailnotifyattn);
         $this->elementEnd('li');
         $this->elementStart('li');
         $this->checkbox('emailnotifynudge',
+                        // TRANS: Checkbox label in e-mail preferences form.
                         _('Allow friends to nudge me and send me an email.'),
                         $user->emailnotifynudge);
         $this->elementEnd('li');
         if (common_config('emailpost', 'enabled')) {
             $this->elementStart('li');
             $this->checkbox('emailpost',
+                            // TRANS: Checkbox label in e-mail preferences form.
                             _('I want to post notices by email.'),
                             $user->emailpost);
             $this->elementEnd('li');
         }
         $this->elementStart('li');
         $this->checkbox('emailmicroid',
+                        // TRANS: Checkbox label in e-mail preferences form.
                         _('Publish a MicroID for my email address.'),
                         $user->emailmicroid);
         $this->elementEnd('li');
         $this->elementEnd('ul');
-        $this->submit('save', _('Save'));
+        // TRANS: Button label to save e-mail preferences.
+        $this->submit('save', _m('BUTTON','Save'));
         $this->elementEnd('fieldset');
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
@@ -253,6 +282,7 @@ class EmailsettingsAction extends AccountSettingsAction
         } else if ($this->arg('newincoming')) {
             $this->newIncoming();
         } else {
+            // TRANS: Message given submitting a form with an unknown action in e-mail settings.
             $this->showForm(_('Unexpected form submission.'));
         }
     }
@@ -293,13 +323,15 @@ class EmailsettingsAction extends AccountSettingsAction
 
         if ($result === false) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error updating e-mail preferences.
             $this->serverError(_('Couldn\'t update user.'));
             return;
         }
 
         $user->query('COMMIT');
 
-        $this->showForm(_('Preferences saved.'), true);
+        // TRANS: Confirmation message for successful e-mail preferences save.
+        $this->showForm(_('Email preferences saved.'), true);
     }
 
     /**
@@ -317,6 +349,7 @@ class EmailsettingsAction extends AccountSettingsAction
         // Some validation
 
         if (!$email) {
+            // TRANS: Message given saving e-mail address without having provided one.
             $this->showForm(_('No email address.'));
             return;
         }
@@ -324,16 +357,20 @@ class EmailsettingsAction extends AccountSettingsAction
         $email = common_canonical_email($email);
 
         if (!$email) {
+            // TRANS: Message given saving e-mail address that cannot be normalised.
             $this->showForm(_('Cannot normalize that email address'));
             return;
         }
         if (!Validate::email($email, common_config('email', 'check_domain'))) {
+            // TRANS: Message given saving e-mail address that not valid.
             $this->showForm(_('Not a valid email address.'));
             return;
         } else if ($user->email == $email) {
+            // TRANS: Message given saving e-mail address that is already set.
             $this->showForm(_('That is already your email address.'));
             return;
         } else if ($this->emailExists($email)) {
+            // TRANS: Message given saving e-mail address that is already set for another user.
             $this->showForm(_('That email address already belongs '.
                               'to another user.'));
             return;
@@ -350,12 +387,14 @@ class EmailsettingsAction extends AccountSettingsAction
 
         if ($result === false) {
             common_log_db_error($confirm, 'INSERT', __FILE__);
+            // TRANS: Server error thrown on database error adding e-mail confirmation code.
             $this->serverError(_('Couldn\'t insert confirmation code.'));
             return;
         }
 
         mail_confirm_address($user, $confirm->code, $user->nickname, $email);
 
+        // TRANS: Message given saving valid e-mail address that is to be confirmed.
         $msg = _('A confirmation code was sent to the email address you added. '.
                  'Check your inbox (and spam box!) for the code and instructions '.
                  'on how to use it.');
@@ -376,11 +415,13 @@ class EmailsettingsAction extends AccountSettingsAction
         $confirm = $this->getConfirmation();
 
         if (!$confirm) {
+            // TRANS: Message given canceling e-mail address confirmation that is not pending.
             $this->showForm(_('No pending confirmation to cancel.'));
             return;
         }
         if ($confirm->address != $email) {
-            $this->showForm(_('That is the wrong IM address.'));
+            // TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address.
+            $this->showForm(_('That is the wrong email address.'));
             return;
         }
 
@@ -388,11 +429,13 @@ class EmailsettingsAction extends AccountSettingsAction
 
         if (!$result) {
             common_log_db_error($confirm, 'DELETE', __FILE__);
+            // TRANS: Server error thrown on database error canceling e-mail address confirmation.
             $this->serverError(_('Couldn\'t delete email confirmation.'));
             return;
         }
 
-        $this->showForm(_('Confirmation cancelled.'), true);
+        // TRANS: Message given after successfully canceling e-mail address confirmation.
+        $this->showForm(_('Email confirmation cancelled.'), true);
     }
 
     /**
@@ -410,6 +453,8 @@ class EmailsettingsAction extends AccountSettingsAction
         // Maybe an old tab open...?
 
         if ($user->email != $email) {
+            // TRANS: Message given trying to remove an e-mail address that is not
+            // TRANS: registered for the active user.
             $this->showForm(_('That is not your email address.'));
             return;
         }
@@ -424,12 +469,14 @@ class EmailsettingsAction extends AccountSettingsAction
 
         if (!$result) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error removing a registered e-mail address.
             $this->serverError(_('Couldn\'t update user.'));
             return;
         }
         $user->query('COMMIT');
 
-        $this->showForm(_('The address was removed.'), true);
+        // TRANS: Message given after successfully removing a registered e-mail address.
+        $this->showForm(_('The email address was removed.'), true);
     }
 
     /**
@@ -453,9 +500,11 @@ class EmailsettingsAction extends AccountSettingsAction
 
         if (!$user->updateKeys($orig)) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error removing incoming e-mail address.
             $this->serverError(_("Couldn't update user record."));
         }
 
+        // TRANS: Message given after successfully removing an incoming e-mail address.
         $this->showForm(_('Incoming email address removed.'), true);
     }
 
@@ -475,9 +524,11 @@ class EmailsettingsAction extends AccountSettingsAction
 
         if (!$user->updateKeys($orig)) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error adding incoming e-mail address.
             $this->serverError(_("Couldn't update user record."));
         }
 
+        // TRANS: Message given after successfully adding an incoming e-mail address.
         $this->showForm(_('New incoming email address added.'), true);
     }
 
index fc95c0e66963f06e4d7b22a57af94df7dcb7f89e..e52db6e111dc5fff6c2a84257fc3175a30d95ea1 100644 (file)
@@ -173,8 +173,20 @@ class GroupblockAction extends RedirectingAction
                 $this->hidden($k, $v);
             }
         }
-        $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group"));
-        $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group'));
+        $this->submit('form_action-no',
+                      // TRANS: Button label on the form to block a user from a group.
+                      _m('BUTTON','No'),
+                      'submit form_action-primary',
+                      'no',
+                      // TRANS: Submit button title for 'No' when blocking a user from a group.
+                      _('Do not block this user from this group'));
+        $this->submit('form_action-yes',
+                      // TRANS: Button label on the form to block a user from a group.
+                      _m('BUTTON','Yes'),
+                      'submit form_action-secondary',
+                      'yes',
+                      // TRANS: Submit button title for 'Yes' when blocking a user from a group.
+                      _('Block this user from this group'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
index 490f6f945cac57b509f968b3f771aea5b3f3c5c5..98fdea38defe9e9a1747a2b72f0334bf02cb55a3 100644 (file)
@@ -135,8 +135,10 @@ class groupRssAction extends Rss10Action
         $c = array('url' => common_local_url('grouprss',
                                              array('nickname' =>
                                                    $group->nickname)),
+                   // TRANS: Message is used as link title. %s is a user nickname.
                    'title' => sprintf(_('%s timeline'), $group->nickname),
                    'link' => common_local_url('showgroup', array('nickname' => $group->nickname)),
+                   // TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
                    'description' => sprintf(_('Updates from members of %1$s on %2$s!'),
                                             $group->nickname, common_config('site', 'name')));
         return $c;
index c3360fb12a5b16483428f118d10a9699b703e3d0..6691c8dad76e95f53cbcf621810a3490ea813f95 100644 (file)
@@ -56,6 +56,7 @@ class ImsettingsAction extends ConnectSettingsAction
 
     function title()
     {
+        // TRANS: Title for instance messaging settings.
         return _('IM settings');
     }
 
@@ -67,6 +68,9 @@ class ImsettingsAction extends ConnectSettingsAction
 
     function getInstructions()
     {
+        // TRANS: Instant messaging settings page instructions.
+        // TRANS: [instant messages] is link text, "(%%doc.im%%)" is the link.
+        // TRANS: the order and formatting of link text and link should remain unchanged.
         return _('You can send and receive notices through '.
                  'Jabber/GTalk [instant messages](%%doc.im%%). '.
                  'Configure your address and settings below.');
@@ -86,6 +90,7 @@ class ImsettingsAction extends ConnectSettingsAction
     {
         if (!common_config('xmpp', 'enabled')) {
             $this->element('div', array('class' => 'error'),
+                           // TRANS: Message given in the IM settings if XMPP is not enabled on the site.
                            _('IM is not available.'));
             return;
         }
@@ -97,32 +102,41 @@ class ImsettingsAction extends ConnectSettingsAction
                                           'action' =>
                                           common_local_url('imsettings')));
         $this->elementStart('fieldset', array('id' => 'settings_im_address'));
-        $this->element('legend', null, _('Address'));
+        // TRANS: Form legend for IM settings form.
+        $this->element('legend', null, _('IM address'));
         $this->hidden('token', common_session_token());
 
         if ($user->jabber) {
             $this->element('p', 'form_confirmed', $user->jabber);
+            // TRANS: Form note in IM settings form.
             $this->element('p', 'form_note',
                            _('Current confirmed Jabber/GTalk address.'));
             $this->hidden('jabber', $user->jabber);
-            $this->submit('remove', _('Remove'));
+            // TRANS: Button label to remove a confirmed IM address.
+            $this->submit('remove', _m('BUTTON','Remove'));
         } else {
             $confirm = $this->getConfirmation();
             if ($confirm) {
                 $this->element('p', 'form_unconfirmed', $confirm->address);
                 $this->element('p', 'form_note',
+                               // TRANS: Form note in IM settings form.
+                               // TRANS: %s is the IM address set for the site.
                                sprintf(_('Awaiting confirmation on this address. '.
                                          'Check your Jabber/GTalk account for a '.
                                          'message with further instructions. '.
                                          '(Did you add %s to your buddy list?)'),
                                        jabber_daemon_address()));
                 $this->hidden('jabber', $confirm->address);
-                $this->submit('cancel', _('Cancel'));
+                // TRANS: Button label to cancel an IM address confirmation procedure.
+                $this->submit('cancel', _m('BUTTON','Cancel'));
             } else {
                 $this->elementStart('ul', 'form_data');
                 $this->elementStart('li');
+                // TRANS: Field label for IM address input in IM settings form.
                 $this->input('jabber', _('IM address'),
                              ($this->arg('jabber')) ? $this->arg('jabber') : null,
+                             // TRANS: IM address input field instructions in IM settings form.
+                             // TRANS: %s is the IM address set for the site.
                              sprintf(_('Jabber or GTalk address, '.
                                        'like "UserName@example.org". '.
                                        'First, make sure to add %s to your '.
@@ -130,37 +144,44 @@ class ImsettingsAction extends ConnectSettingsAction
                                      jabber_daemon_address()));
                 $this->elementEnd('li');
                 $this->elementEnd('ul');
-                $this->submit('add', _('Add'));
+                // TRANS: Button label for adding an IM address in IM settings form.
+                $this->submit('add', _m('BUTTON','Add'));
             }
         }
         $this->elementEnd('fieldset');
         
         $this->elementStart('fieldset', array('id' => 'settings_im_preferences'));
-        $this->element('legend', null, _('Preferences'));
+        // TRANS: Form legend for IM preferences form.
+        $this->element('legend', null, _('IM preferences'));
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
         $this->checkbox('jabbernotify',
+                        // TRANS: Checkbox label in IM preferences form.
                         _('Send me notices through Jabber/GTalk.'),
                         $user->jabbernotify);
         $this->elementEnd('li');
         $this->elementStart('li');
         $this->checkbox('updatefrompresence',
+                        // TRANS: Checkbox label in IM preferences form.
                         _('Post a notice when my Jabber/GTalk status changes.'),
                         $user->updatefrompresence);
         $this->elementEnd('li');
         $this->elementStart('li');
         $this->checkbox('jabberreplies',
+                        // TRANS: Checkbox label in IM preferences form.
                         _('Send me replies through Jabber/GTalk '.
                           'from people I\'m not subscribed to.'),
                         $user->jabberreplies);
         $this->elementEnd('li');
         $this->elementStart('li');
         $this->checkbox('jabbermicroid',
+                        // TRANS: Checkbox label in IM preferences form.
                         _('Publish a MicroID for my Jabber/GTalk address.'),
                         $user->jabbermicroid);
         $this->elementEnd('li');
         $this->elementEnd('ul');
-        $this->submit('save', _('Save'));
+        // TRANS: Button label to save IM preferences.
+        $this->submit('save', _m('BUTTON','Save'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
@@ -217,6 +238,7 @@ class ImsettingsAction extends ConnectSettingsAction
         } else if ($this->arg('remove')) {
             $this->removeAddress();
         } else {
+            // TRANS: Message given submitting a form with an unknown action in IM settings.
             $this->showForm(_('Unexpected form submission.'));
         }
     }
@@ -232,7 +254,6 @@ class ImsettingsAction extends ConnectSettingsAction
 
     function savePreferences()
     {
-
         $jabbernotify       = $this->boolean('jabbernotify');
         $updatefrompresence = $this->boolean('updatefrompresence');
         $jabberreplies      = $this->boolean('jabberreplies');
@@ -255,12 +276,14 @@ class ImsettingsAction extends ConnectSettingsAction
 
         if ($result === false) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error updating IM preferences.
             $this->serverError(_('Couldn\'t update user.'));
             return;
         }
 
         $user->query('COMMIT');
 
+        // TRANS: Confirmation message for successful IM preferences save.
         $this->showForm(_('Preferences saved.'), true);
     }
 
@@ -282,6 +305,7 @@ class ImsettingsAction extends ConnectSettingsAction
         // Some validation
 
         if (!$jabber) {
+            // TRANS: Message given saving IM address without having provided one.
             $this->showForm(_('No Jabber ID.'));
             return;
         }
@@ -289,16 +313,20 @@ class ImsettingsAction extends ConnectSettingsAction
         $jabber = jabber_normalize_jid($jabber);
 
         if (!$jabber) {
+            // TRANS: Message given saving IM address that cannot be normalised.
             $this->showForm(_('Cannot normalize that Jabber ID'));
             return;
         }
         if (!jabber_valid_base_jid($jabber, common_config('email', 'domain_check'))) {
+            // TRANS: Message given saving IM address that not valid.
             $this->showForm(_('Not a valid Jabber ID'));
             return;
         } else if ($user->jabber == $jabber) {
+            // TRANS: Message given saving IM address that is already set.
             $this->showForm(_('That is already your Jabber ID.'));
             return;
         } else if ($this->jabberExists($jabber)) {
+            // TRANS: Message given saving IM address that is already set for another user.
             $this->showForm(_('Jabber ID already belongs to another user.'));
             return;
         }
@@ -316,6 +344,7 @@ class ImsettingsAction extends ConnectSettingsAction
 
         if ($result === false) {
             common_log_db_error($confirm, 'INSERT', __FILE__);
+            // TRANS: Server error thrown on database error adding IM confirmation code.
             $this->serverError(_('Couldn\'t insert confirmation code.'));
             return;
         }
@@ -324,6 +353,8 @@ class ImsettingsAction extends ConnectSettingsAction
                                $user->nickname,
                                $jabber);
 
+        // TRANS: Message given saving valid IM address that is to be confirmed.
+        // TRANS: %s is the IM address set for the site.
         $msg = sprintf(_('A confirmation code was sent '.
                          'to the IM address you added. '.
                          'You must approve %s for '.
@@ -348,10 +379,12 @@ class ImsettingsAction extends ConnectSettingsAction
         $confirm = $this->getConfirmation();
 
         if (!$confirm) {
+            // TRANS: Message given canceling IM address confirmation that is not pending.
             $this->showForm(_('No pending confirmation to cancel.'));
             return;
         }
         if ($confirm->address != $jabber) {
+            // TRANS: Message given canceling IM address confirmation for the wrong IM address.
             $this->showForm(_('That is the wrong IM address.'));
             return;
         }
@@ -360,11 +393,13 @@ class ImsettingsAction extends ConnectSettingsAction
 
         if (!$result) {
             common_log_db_error($confirm, 'DELETE', __FILE__);
-            $this->serverError(_('Couldn\'t delete email confirmation.'));
+            // TRANS: Server error thrown on database error canceling IM address confirmation.
+            $this->serverError(_('Couldn\'t delete IM confirmation.'));
             return;
         }
 
-        $this->showForm(_('Confirmation cancelled.'), true);
+        // TRANS: Message given after successfully canceling IM address confirmation.
+        $this->showForm(_('IM confirmation cancelled.'), true);
     }
 
     /**
@@ -384,6 +419,8 @@ class ImsettingsAction extends ConnectSettingsAction
         // Maybe an old tab open...?
 
         if ($user->jabber != $jabber) {
+            // TRANS: Message given trying to remove an IM address that is not
+            // TRANS: registered for the active user.
             $this->showForm(_('That is not your Jabber ID.'));
             return;
         }
@@ -398,6 +435,7 @@ class ImsettingsAction extends ConnectSettingsAction
 
         if (!$result) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error removing a registered IM address.
             $this->serverError(_('Couldn\'t update user.'));
             return;
         }
@@ -405,7 +443,8 @@ class ImsettingsAction extends ConnectSettingsAction
 
         // XXX: unsubscribe to the old address
 
-        $this->showForm(_('The address was removed.'), true);
+        // TRANS: Message given after successfully removing a registered IM address.
+        $this->showForm(_('The IM address was removed.'), true);
     }
 
     /**
index 5dac048b061e6990922ddd28e84a76430e5ed599..4bba8893d6d136a194b0e419b89f9fb7fb5a2862 100644 (file)
@@ -224,8 +224,10 @@ class InviteAction extends CurrentUserDesignAction
 
         $headers['From'] = mail_notify_from();
         $headers['To'] = trim($email);
+        // TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English.
         $headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename);
 
+        // TRANS: Body text for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English.
         $body = sprintf(_("%1\$s has invited you to join them on %2\$s (%3\$s).\n\n".
                           "%2\$s is a micro-blogging service that lets you keep up-to-date with people you know and people who interest you.\n\n".
                           "You can also share news about yourself, your thoughts, or your life online with people who know about you. ".
index da8d0a0bbcdd83ce26ca2757d504fde0e7f89bd0..d1bc381fbc52358ea8ed7d9dcc01deda5a0a0c04 100644 (file)
@@ -341,7 +341,7 @@ class RegisterAction extends Action
         } else {
             $instr =
               common_markup_to_html(_('With this form you can create '.
-                                      ' a new account. ' .
+                                      'a new account. ' .
                                       'You can then post notices and '.
                                       'link up to friends and colleagues. '));
 
index 7be9618f864f7bc99f9e7199d4b9bf2c82101fa0..9c5d83441b8688e6ed08b52cf22c9dfdf71f6ba5 100644 (file)
@@ -167,7 +167,7 @@ class ShownoticeAction extends OwnerDesignAction
     function title()
     {
         if (!empty($this->profile->fullname)) {
-            $base = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
+            $base = $this->profile->fullname . ' (' . $this->profile->nickname . ')';
         } else {
             $base = $this->profile->nickname;
         }
index 751495d57aad809a548ad990a9a63bc251073ddc..6af1872a0ec1d88bcf117ff20ba4ef2cadc57a6b 100644 (file)
@@ -55,6 +55,7 @@ class SmssettingsAction extends ConnectSettingsAction
 
     function title()
     {
+        // TRANS: Title for SMS settings.
         return _('SMS settings');
     }
 
@@ -66,6 +67,10 @@ class SmssettingsAction extends ConnectSettingsAction
 
     function getInstructions()
     {
+        // XXX: For consistency of parameters in messages, this should be a
+        //      regular parameters, replaced with sprintf().
+        // TRANS: SMS settings page instructions.
+        // TRANS: %%site.name%% is the name of the site.
         return _('You can receive SMS messages through email from %%site.name%%.');
     }
 
@@ -88,6 +93,7 @@ class SmssettingsAction extends ConnectSettingsAction
     {
         if (!common_config('sms', 'enabled')) {
             $this->element('div', array('class' => 'error'),
+                           // TRANS: Message given in the SMS settings if SMS is not enabled on the site.
                            _('SMS is not available.'));
             return;
         }
@@ -101,7 +107,8 @@ class SmssettingsAction extends ConnectSettingsAction
                                           common_local_url('smssettings')));
 
         $this->elementStart('fieldset', array('id' => 'settings_sms_address'));
-        $this->element('legend', null, _('Address'));
+        // TRANS: Form legend for SMS settings form.
+        $this->element('legend', null, _('SMS address'));
         $this->hidden('token', common_session_token());
 
         if ($user->sms) {
@@ -109,10 +116,12 @@ class SmssettingsAction extends ConnectSettingsAction
             $this->element('p', 'form_confirmed',
                            $user->sms . ' (' . $carrier->name . ')');
             $this->element('p', 'form_guide',
+                           // TRANS: Form guide in SMS settings form.
                            _('Current confirmed SMS-enabled phone number.'));
             $this->hidden('sms', $user->sms);
             $this->hidden('carrier', $user->carrier);
-            $this->submit('remove', _('Remove'));
+            // TRANS: Button label to remove a confirmed SMS address.
+            $this->submit('remove', _m('BUTTON','Remove'));
         } else {
             $confirm = $this->getConfirmation();
             if ($confirm) {
@@ -120,57 +129,75 @@ class SmssettingsAction extends ConnectSettingsAction
                 $this->element('p', 'form_unconfirmed',
                                $confirm->address . ' (' . $carrier->name . ')');
                 $this->element('p', 'form_guide',
+                               // TRANS: Form guide in IM settings form.
                                _('Awaiting confirmation on this phone number.'));
                 $this->hidden('sms', $confirm->address);
                 $this->hidden('carrier', $confirm->address_extra);
-                $this->submit('cancel', _('Cancel'));
+                // TRANS: Button label to cancel a SMS address confirmation procedure.
+                $this->submit('cancel', _m('BUTTON','Cancel'));
 
                 $this->elementStart('ul', 'form_data');
                 $this->elementStart('li');
+                // TRANS: Field label for SMS address input in SMS settings form.
                 $this->input('code', _('Confirmation code'), null,
+                             // TRANS: Form field instructions in SMS settings form.
                              _('Enter the code you received on your phone.'));
                 $this->elementEnd('li');
                 $this->elementEnd('ul');
-                $this->submit('confirm', _('Confirm'));
+                // TRANS: Button label to confirm SMS confirmation code in SMS settings.
+                $this->submit('confirm', _m('BUTTON','Confirm'));
             } else {
                 $this->elementStart('ul', 'form_data');
                 $this->elementStart('li');
+                // TRANS: Field label for SMS phone number input in SMS settings form.
                 $this->input('sms', _('SMS phone number'),
                              ($this->arg('sms')) ? $this->arg('sms') : null,
+                             // TRANS: SMS phone number input field instructions in SMS settings form.
                              _('Phone number, no punctuation or spaces, '.
                                'with area code'));
                 $this->elementEnd('li');
                 $this->elementEnd('ul');
                 $this->carrierSelect();
-                $this->submit('add', _('Add'));
+                // TRANS: Button label for adding a SMS phone number in SMS settings form.
+                $this->submit('add', _m('BUTTON','Add'));
             }
         }
         $this->elementEnd('fieldset');
 
         if ($user->sms) {
         $this->elementStart('fieldset', array('id' => 'settings_sms_incoming_email'));
+            // XXX: Confused! This is about SMS. Should this message be updated?
+            // TRANS: Form legend for incoming SMS settings form.
             $this->element('legend', null, _('Incoming email'));
 
             if ($user->incomingemail) {
                 $this->element('p', 'form_unconfirmed', $user->incomingemail);
                 $this->element('p', 'form_note',
+                               // XXX: Confused! This is about SMS. Should this message be updated?
+                               // TRANS: Form instructions for incoming SMS e-mail address form in SMS settings.
                                _('Send email to this address to post new notices.'));
-                $this->submit('removeincoming', _('Remove'));
+                // TRANS: Button label for removing a set sender SMS e-mail address to post notices from.
+                $this->submit('removeincoming', _m('BUTTON','Remove'));
             }
 
             $this->element('p', 'form_guide',
+                           // XXX: Confused! This is about SMS. Should this message be updated?
+                           // TRANS: Instructions for incoming SMS e-mail address input form.
                            _('Make a new email address for posting to; '.
                              'cancels the old one.'));
-            $this->submit('newincoming', _('New'));
+            // TRANS: Button label for adding an SMS e-mail address to send notices from.
+            $this->submit('newincoming', _m('BUTTON','New'));
             $this->elementEnd('fieldset');
         }
 
         $this->elementStart('fieldset', array('id' => 'settings_sms_preferences'));
-        $this->element('legend', null, _('Preferences'));
+        // TRANS: Form legend for SMS preferences form.
+        $this->element('legend', null, _('SMS preferences'));
 
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
         $this->checkbox('smsnotify',
+                        // TRANS: Checkbox label in SMS preferences form.
                         _('Send me notices through SMS; '.
                           'I understand I may incur '.
                           'exorbitant charges from my carrier.'),
@@ -178,7 +205,8 @@ class SmssettingsAction extends ConnectSettingsAction
         $this->elementEnd('li');
         $this->elementEnd('ul');
 
-        $this->submit('save', _('Save'));
+        // TRANS: Button label to save SMS preferences.
+        $this->submit('save', _m('BUTTON','Save'));
 
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
@@ -245,6 +273,7 @@ class SmssettingsAction extends ConnectSettingsAction
         } else if ($this->arg('confirm')) {
             $this->confirmCode();
         } else {
+            // TRANS: Message given submitting a form with an unknown action in SMS settings.
             $this->showForm(_('Unexpected form submission.'));
         }
     }
@@ -275,13 +304,15 @@ class SmssettingsAction extends ConnectSettingsAction
 
         if ($result === false) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error updating SMS preferences.
             $this->serverError(_('Couldn\'t update user.'));
             return;
         }
 
         $user->query('COMMIT');
 
-        $this->showForm(_('Preferences saved.'), true);
+        // TRANS: Confirmation message for successful SMS preferences save.
+        $this->showForm(_('SMS preferences saved.'), true);
     }
 
     /**
@@ -303,11 +334,13 @@ class SmssettingsAction extends ConnectSettingsAction
         // Some validation
 
         if (!$sms) {
+            // TRANS: Message given saving SMS phone number without having provided one.
             $this->showForm(_('No phone number.'));
             return;
         }
 
         if (!$carrier_id) {
+            // TRANS: Message given saving SMS phone number without having selected a carrier.
             $this->showForm(_('No carrier selected.'));
             return;
         }
@@ -315,9 +348,11 @@ class SmssettingsAction extends ConnectSettingsAction
         $sms = common_canonical_sms($sms);
 
         if ($user->sms == $sms) {
+            // TRANS: Message given saving SMS phone number that is already set.
             $this->showForm(_('That is already your phone number.'));
             return;
         } else if ($this->smsExists($sms)) {
+            // TRANS: Message given saving SMS phone number that is already set for another user.
             $this->showForm(_('That phone number already belongs to another user.'));
             return;
         }
@@ -334,6 +369,7 @@ class SmssettingsAction extends ConnectSettingsAction
 
         if ($result === false) {
             common_log_db_error($confirm, 'INSERT', __FILE__);
+            // TRANS: Server error thrown on database error adding SMS confirmation code.
             $this->serverError(_('Couldn\'t insert confirmation code.'));
             return;
         }
@@ -344,6 +380,7 @@ class SmssettingsAction extends ConnectSettingsAction
                          $user->nickname,
                          $carrier->toEmailAddress($sms));
 
+        // TRANS: Message given saving valid SMS phone number that is to be confirmed.
         $msg = _('A confirmation code was sent to the phone number you added. '.
                  'Check your phone for the code and instructions '.
                  'on how to use it.');
@@ -367,10 +404,12 @@ class SmssettingsAction extends ConnectSettingsAction
         $confirm = $this->getConfirmation();
 
         if (!$confirm) {
+            // TRANS: Message given canceling SMS phone number confirmation that is not pending.
             $this->showForm(_('No pending confirmation to cancel.'));
             return;
         }
         if ($confirm->address != $sms) {
+            // TRANS: Message given canceling SMS phone number confirmation for the wrong phone number.
             $this->showForm(_('That is the wrong confirmation number.'));
             return;
         }
@@ -379,11 +418,13 @@ class SmssettingsAction extends ConnectSettingsAction
 
         if (!$result) {
             common_log_db_error($confirm, 'DELETE', __FILE__);
+            // TRANS: Server error thrown on database error canceling SMS phone number confirmation.
             $this->serverError(_('Couldn\'t delete email confirmation.'));
             return;
         }
 
-        $this->showForm(_('Confirmation cancelled.'), true);
+        // TRANS: Message given after successfully canceling SMS phone number confirmation.
+        $this->showForm(_('SMS confirmation cancelled.'), true);
     }
 
     /**
@@ -402,6 +443,8 @@ class SmssettingsAction extends ConnectSettingsAction
         // Maybe an old tab open...?
 
         if ($user->sms != $sms) {
+            // TRANS: Message given trying to remove an SMS phone number that is not
+            // TRANS: registered for the active user.
             $this->showForm(_('That is not your phone number.'));
             return;
         }
@@ -417,12 +460,14 @@ class SmssettingsAction extends ConnectSettingsAction
         $result = $user->updateKeys($original);
         if (!$result) {
             common_log_db_error($user, 'UPDATE', __FILE__);
+            // TRANS: Server error thrown on database error removing a registered SMS phone number.
             $this->serverError(_('Couldn\'t update user.'));
             return;
         }
         $user->query('COMMIT');
 
-        $this->showForm(_('The address was removed.'), true);
+        // TRANS: Message given after successfully removing a registered SMS phone number.
+        $this->showForm(_('The SMS phone number was removed.'), true);
     }
 
     /**
@@ -462,10 +507,12 @@ class SmssettingsAction extends ConnectSettingsAction
 
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
+        // TRANS: Label for mobile carrier dropdown menu in SMS settings.
         $this->element('label', array('for' => 'carrier'), _('Mobile carrier'));
         $this->elementStart('select', array('name' => 'carrier',
                                             'id' => 'carrier'));
         $this->element('option', array('value' => 0),
+                       // TRANS: Default option for mobile carrier dropdown menu in SMS settings.
                        _('Select a carrier'));
         while ($carrier->fetch()) {
             $this->element('option', array('value' => $carrier->id),
@@ -473,6 +520,8 @@ class SmssettingsAction extends ConnectSettingsAction
         }
         $this->elementEnd('select');
         $this->element('p', 'form_guide',
+                       // TRANS: Form instructions for mobile carrier dropdown menu in SMS settings.
+                       // TRANS: %s is an administrative contact's e-mail address.
                        sprintf(_('Mobile carrier for your phone. '.
                                  'If you know a carrier that accepts ' .
                                  'SMS over email but isn\'t listed here, ' .
@@ -495,6 +544,7 @@ class SmssettingsAction extends ConnectSettingsAction
         $code = $this->trimmed('code');
 
         if (!$code) {
+            // TRANS: Message given saving SMS phone number confirmation code without having provided one.
             $this->showForm(_('No code entered'));
             return;
         }
index df6b168dc8e0cfb77a8330aa34ca87affcd74864..be0a793e51bb0f339b68b4ec76aa8ecd85fd4ae8 100644 (file)
@@ -197,7 +197,7 @@ class SnapshotAdminPanelForm extends AdminForm
         $this->out->elementStart('ul', 'form_data');
         $this->li();
         $snapshot = array(
-            'web' => _('Randomly during Web hit'),
+            'web' => _('Randomly during web hit'),
             'cron'  => _('In a scheduled job'),
             'never' => _('Never')
         );
index 9532404041597f44e94fe50fce2ac9725c37fca3..7c6f99d92bac58cb6ef98d8641c425f2169b5653 100644 (file)
@@ -102,12 +102,17 @@ class TagAction extends Action
 
     function showContent()
     {
-        $nl = new NoticeList($this->notice, $this);
+        if(Event::handle('StartTagShowContent', array($this))) {
+            
+            $nl = new NoticeList($this->notice, $this);
 
-        $cnt = $nl->show();
+            $cnt = $nl->show();
 
-        $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
-                          $this->page, 'tag', array('tag' => $this->tag));
+            $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
+                              $this->page, 'tag', array('tag' => $this->tag));
+
+            Event::handle('EndTagShowContent', array($this));
+        }
     }
 
     function isReadOnly($args)
index 29bda0a765c289dc107316bd1f1a4a5135346472..6606e76cdb907c641bf8594dbf4fb34c66111e17 100644 (file)
@@ -59,8 +59,10 @@ class UsergroupsAction extends OwnerDesignAction
     function title()
     {
         if ($this->page == 1) {
+            // TRANS: Message is used as a page title. %s is a nick name.
             return sprintf(_('%s groups'), $this->user->nickname);
         } else {
+            // TRANS: Message is used as a page title. %1$s is a nick name, %2$d is a page number.
             return sprintf(_('%1$s groups, page %2$d'),
                            $this->user->nickname,
                            $this->page);
index cf7d18ca88c8b9c9867ba4e1e5c90ed58b71c2b0..b7078fcaf886a2967a11cc3d2b058b89cf6f37c2 100644 (file)
@@ -72,7 +72,7 @@ class UserrssAction extends Rss10Action
     {
         $notice = $this->user->getNotices(
             0,
-            ($limit == 0) ? NOTICES_PER_PAGE : $limit
+            ($this->limit == 0) ? NOTICES_PER_PAGE : $this->limit
         );
 
         $notices = array();
@@ -90,8 +90,10 @@ class UserrssAction extends Rss10Action
         $c = array('url' => common_local_url('userrss',
                                              array('nickname' =>
                                                    $user->nickname)),
+                   // TRANS: Message is used as link title. %s is a user nickname.
                    'title' => sprintf(_('%s timeline'), $user->nickname),
                    'link' => $profile->profileurl,
+                   // TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
                    'description' => sprintf(_('Updates from %1$s on %2$s!'),
                                             $user->nickname, common_config('site', 'name')));
         return $c;
index 33273bbdccb577047e545f77504da008cd31fd35..c9477f5f1eeb802474d2a2ad4781fa43e7ec0dfd 100644 (file)
@@ -286,7 +286,9 @@ class File extends Memcached_DataObject
 
         if(! isset($this->filename)){
             $notEnclosureMimeTypes = array(null,'text/html','application/xhtml+xml');
-            $mimetype = strtolower($this->mimetype);
+            if($mimetype != null){
+                $mimetype = strtolower($this->mimetype);
+            }
             $semicolon = strpos($mimetype,';');
             if($semicolon){
                 $mimetype = substr($mimetype,0,$semicolon);
index 0b1b2e402dfc05178651f6134f830ab7763af75b..c0828674d17e5643b514316992644a5728e0a8a6 100644 (file)
@@ -172,7 +172,8 @@ class Notice extends Memcached_DataObject
         $id = $tag->insert();
 
         if (!$id) {
-            throw new ServerException(sprintf(_('DB error inserting hashtag: %s'),
+            // TRANS: Server exception. %s are the error details.
+            throw new ServerException(sprintf(_('Database error inserting hashtag: %s'),
                                               $last_error->message));
             return;
         }
@@ -1527,6 +1528,8 @@ class Notice extends Memcached_DataObject
     {
         $author = Profile::staticGet('id', $this->profile_id);
 
+        // TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
+        // TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
         $content = sprintf(_('RT @%1$s %2$s'),
                            $author->nickname,
                            $this->content);
index 08bc6846f47bb905ac3893562ee7c5667fb51696..e926cb0d588375f5724855259b7c9ac2f46fd28a 100644 (file)
@@ -96,6 +96,30 @@ class Safe_DataObject extends DB_DataObject
         $this->_link_loaded = false;
     }
 
+    /**
+     * Magic function called when someone attempts to call a method
+     * that doesn't exist. DB_DataObject uses this to implement
+     * setters and getters for fields, but neglects to throw an error
+     * when you just misspell an actual method name. This leads to
+     * silent failures which can cause all kinds of havoc.
+     *
+     * @param string $method
+     * @param array $params
+     * @return mixed
+     * @throws Exception
+     */
+    function __call($method, $params)
+    {
+        $return = null;
+        // Yes, that's _call with one underscore, which does the
+        // actual implementation.
+        if ($this->_call($method, $params, $return)) {
+            return $return;
+        } else {
+            throw new Exception('Call to undefined method ' .
+                get_class($this) . '::' . $method);
+        }
+    }
 
     /**
      * Work around memory-leak bugs...
index 60c12cccc3d8d67545679355d2eb944e6e9f0612..0679c0925004bbdbb9410e3624fef8ff899a8774 100644 (file)
@@ -88,8 +88,8 @@ class Subscription extends Memcached_DataObject
 
             self::blow('user:notices_with_friends:%d', $subscriber->id);
 
-            $subscriber->blowSubscriptionsCount();
-            $other->blowSubscribersCount();
+            $subscriber->blowSubscriptionCount();
+            $other->blowSubscriberCount();
 
             $otherUser = User::staticGet('id', $other->id);
 
@@ -213,8 +213,8 @@ class Subscription extends Memcached_DataObject
 
             self::blow('user:notices_with_friends:%d', $subscriber->id);
 
-            $subscriber->blowSubscriptionsCount();
-            $other->blowSubscribersCount();
+            $subscriber->blowSubscriptionCount();
+            $other->blowSubscriberCount();
 
             Event::handle('EndUnsubscribe', array($subscriber, $other));
         }
diff --git a/extlib/Net/LDAP2.php b/extlib/Net/LDAP2.php
deleted file mode 100644 (file)
index 26f5e75..0000000
+++ /dev/null
@@ -1,1791 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2 interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Tarjej Huse <tarjei@bergfald.no>
-* @author    Jan Wagner <wagner@netsols.de>
-* @author    Del <del@babel.com.au>
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: LDAP2.php 286788 2009-08-04 06:05:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Package includes.
-*/
-require_once 'PEAR.php';
-require_once 'Net/LDAP2/RootDSE.php';
-require_once 'Net/LDAP2/Schema.php';
-require_once 'Net/LDAP2/Entry.php';
-require_once 'Net/LDAP2/Search.php';
-require_once 'Net/LDAP2/Util.php';
-require_once 'Net/LDAP2/Filter.php';
-require_once 'Net/LDAP2/LDIF.php';
-require_once 'Net/LDAP2/SchemaCache.interface.php';
-require_once 'Net/LDAP2/SimpleFileSchemaCache.php';
-
-/**
-*  Error constants for errors that are not LDAP errors.
-*/
-define('NET_LDAP2_ERROR', 1000);
-
-/**
-* Net_LDAP2 Version
-*/
-define('NET_LDAP2_VERSION', '2.0.7');
-
-/**
-* Net_LDAP2 - manipulate LDAP servers the right way!
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Tarjej Huse <tarjei@bergfald.no>
-* @author    Jan Wagner <wagner@netsols.de>
-* @author    Del <del@babel.com.au>
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger
-* @license   http://www.gnu.org/copyleft/lesser.html LGPL
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-class Net_LDAP2 extends PEAR
-{
-    /**
-    * Class configuration array
-    *
-    * host     = the ldap host to connect to
-    *            (may be an array of several hosts to try)
-    * port     = the server port
-    * version  = ldap version (defaults to v 3)
-    * starttls = when set, ldap_start_tls() is run after connecting.
-    * bindpw   = no explanation needed
-    * binddn   = the DN to bind as.
-    * basedn   = ldap base
-    * options  = hash of ldap options to set (opt => val)
-    * filter   = default search filter
-    * scope    = default search scope
-    *
-    * Newly added in 2.0.0RC4, for auto-reconnect:
-    * auto_reconnect  = if set to true then the class will automatically
-    *                   attempt to reconnect to the LDAP server in certain
-    *                   failure conditionswhen attempting a search, or other
-    *                   LDAP operation.  Defaults to false.  Note that if you
-    *                   set this to true, calls to search() may block
-    *                   indefinitely if there is a catastrophic server failure.
-    * min_backoff     = minimum reconnection delay period (in seconds).
-    * current_backoff = initial reconnection delay period (in seconds).
-    * max_backoff     = maximum reconnection delay period (in seconds).
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_config = array('host'            => 'localhost',
-                               'port'            => 389,
-                               'version'         => 3,
-                               'starttls'        => false,
-                               'binddn'          => '',
-                               'bindpw'          => '',
-                               'basedn'          => '',
-                               'options'         => array(),
-                               'filter'          => '(objectClass=*)',
-                               'scope'           => 'sub',
-                               'auto_reconnect'  => false,
-                               'min_backoff'     => 1,
-                               'current_backoff' => 1,
-                               'max_backoff'     => 32);
-
-    /**
-    * List of hosts we try to establish a connection to
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_host_list = array();
-
-    /**
-    * List of hosts that are known to be down.
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_down_host_list = array();
-
-    /**
-    * LDAP resource link.
-    *
-    * @access protected
-    * @var resource
-    */
-    protected $_link = false;
-
-    /**
-    * Net_LDAP2_Schema object
-    *
-    * This gets set and returned by {@link schema()}
-    *
-    * @access protected
-    * @var object Net_LDAP2_Schema
-    */
-    protected $_schema = null;
-
-    /**
-    * Schema cacher function callback
-    *
-    * @see registerSchemaCache()
-    * @var string
-    */
-    protected $_schema_cache = null;
-
-    /**
-    * Cache for attribute encoding checks
-    *
-    * @access protected
-    * @var array Hash with attribute names as key and boolean value
-    *            to determine whether they should be utf8 encoded or not.
-    */
-    protected $_schemaAttrs = array();
-
-    /**
-    * Cache for rootDSE objects
-    *
-    * Hash with requested rootDSE attr names as key and rootDSE object as value
-    *
-    * Since the RootDSE object itself may request a rootDSE object,
-    * {@link rootDse()} caches successful requests.
-    * Internally, Net_LDAP2 needs several lookups to this object, so
-    * caching increases performance significally.
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_rootDSE_cache = array();
-
-    /**
-    * Returns the Net_LDAP2 Release version, may be called statically
-    *
-    * @static
-    * @return string Net_LDAP2 version
-    */
-    public static function getVersion()
-    {
-        return NET_LDAP2_VERSION;
-    }
-
-    /**
-    * Configure Net_LDAP2, connect and bind
-    *
-    * Use this method as starting point of using Net_LDAP2
-    * to establish a connection to your LDAP server.
-    *
-    * Static function that returns either an error object or the new Net_LDAP2
-    * object. Something like a factory. Takes a config array with the needed
-    * parameters.
-    *
-    * @param array $config Configuration array
-    *
-    * @access public
-    * @return Net_LDAP2_Error|Net_LDAP2   Net_LDAP2_Error or Net_LDAP2 object
-    */
-    public static function &connect($config = array())
-    {
-        $ldap_check = self::checkLDAPExtension();
-        if (self::iserror($ldap_check)) {
-            return $ldap_check;
-        }
-
-        @$obj = new Net_LDAP2($config);
-
-        // todo? better errorhandling for setConfig()?
-
-        // connect and bind with credentials in config
-        $err = $obj->bind();
-        if (self::isError($err)) {
-            return $err;
-        }
-
-        return $obj;
-    }
-
-    /**
-    * Net_LDAP2 constructor
-    *
-    * Sets the config array
-    *
-    * Please note that the usual way of getting Net_LDAP2 to work is
-    * to call something like:
-    * <code>$ldap = Net_LDAP2::connect($ldap_config);</code>
-    *
-    * @param array $config Configuration array
-    *
-    * @access protected
-    * @return void
-    * @see $_config
-    */
-    public function __construct($config = array())
-    {
-        $this->PEAR('Net_LDAP2_Error');
-        $this->setConfig($config);
-    }
-
-    /**
-    * Sets the internal configuration array
-    *
-    * @param array $config Configuration array
-    *
-    * @access protected
-    * @return void
-    */
-    protected function setConfig($config)
-    {
-        //
-        // Parameter check -- probably should raise an error here if config
-        // is not an array.
-        //
-        if (! is_array($config)) {
-            return;
-        }
-
-        foreach ($config as $k => $v) {
-            if (isset($this->_config[$k])) {
-                $this->_config[$k] = $v;
-            } else {
-                // map old (Net_LDAP2) parms to new ones
-                switch($k) {
-                case "dn":
-                    $this->_config["binddn"] = $v;
-                    break;
-                case "password":
-                    $this->_config["bindpw"] = $v;
-                    break;
-                case "tls":
-                    $this->_config["starttls"] = $v;
-                    break;
-                case "base":
-                    $this->_config["basedn"] = $v;
-                    break;
-                }
-            }
-        }
-
-        //
-        // Ensure the host list is an array.
-        //
-        if (is_array($this->_config['host'])) {
-            $this->_host_list = $this->_config['host'];
-        } else {
-            if (strlen($this->_config['host']) > 0) {
-                $this->_host_list = array($this->_config['host']);
-            } else {
-                $this->_host_list = array();
-                // ^ this will cause an error in performConnect(),
-                // so the user is notified about the failure
-            }
-        }
-
-        //
-        // Reset the down host list, which seems like a sensible thing to do
-        // if the config is being reset for some reason.
-        //
-        $this->_down_host_list = array();
-    }
-
-    /**
-    * Bind or rebind to the ldap-server
-    *
-    * This function binds with the given dn and password to the server. In case
-    * no connection has been made yet, it will be started and startTLS issued
-    * if appropiate.
-    *
-    * The internal bind configuration is not being updated, so if you call
-    * bind() without parameters, you can rebind with the credentials
-    * provided at first connecting to the server.
-    *
-    * @param string $dn       Distinguished name for binding
-    * @param string $password Password for binding
-    *
-    * @access public
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    */
-    public function bind($dn = null, $password = null)
-    {
-        // fetch current bind credentials
-        if (is_null($dn)) {
-            $dn = $this->_config["binddn"];
-        }
-        if (is_null($password)) {
-            $password = $this->_config["bindpw"];
-        }
-
-        // Connect first, if we haven't so far.
-        // This will also bind us to the server.
-        if ($this->_link === false) {
-            // store old credentials so we can revert them later
-            // then overwrite config with new bind credentials
-            $olddn = $this->_config["binddn"];
-            $oldpw = $this->_config["bindpw"];
-
-            // overwrite bind credentials in config
-            // so performConnect() knows about them
-            $this->_config["binddn"] = $dn;
-            $this->_config["bindpw"] = $password;
-
-            // try to connect with provided credentials
-            $msg = $this->performConnect();
-
-            // reset to previous config
-            $this->_config["binddn"] = $olddn;
-            $this->_config["bindpw"] = $oldpw;
-
-            // see if bind worked
-            if (self::isError($msg)) {
-                return $msg;
-            }
-        } else {
-            // do the requested bind as we are
-            // asked to bind manually
-            if (is_null($dn)) {
-                // anonymous bind
-                $msg = @ldap_bind($this->_link);
-            } else {
-                // privileged bind
-                $msg = @ldap_bind($this->_link, $dn, $password);
-            }
-            if (false === $msg) {
-                return PEAR::raiseError("Bind failed: " .
-                                        @ldap_error($this->_link),
-                                        @ldap_errno($this->_link));
-            }
-        }
-        return true;
-    }
-
-    /**
-    * Connect to the ldap-server
-    *
-    * This function connects to the LDAP server specified in
-    * the configuration, binds and set up the LDAP protocol as needed.
-    *
-    * @access protected
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    */
-    protected function performConnect()
-    {
-        // Note: Connecting is briefly described in RFC1777.
-        // Basicly it works like this:
-        //  1. set up TCP connection
-        //  2. secure that connection if neccessary
-        //  3a. setLDAPVersion to tell server which version we want to speak
-        //  3b. perform bind
-        //  3c. setLDAPVersion to tell server which version we want to speak
-        //      together with a test for supported versions
-        //  4. set additional protocol options
-
-        // Return true if we are already connected.
-        if ($this->_link !== false) {
-            return true;
-        }
-
-        // Connnect to the LDAP server if we are not connected.  Note that
-        // with some LDAP clients, ldapperformConnect returns a link value even
-        // if no connection is made.  We need to do at least one anonymous
-        // bind to ensure that a connection is actually valid.
-        //
-        // Ref: http://www.php.net/manual/en/function.ldap-connect.php
-
-        // Default error message in case all connection attempts
-        // fail but no message is set
-        $current_error = new PEAR_Error('Unknown connection error');
-
-        // Catch empty $_host_list arrays.
-        if (!is_array($this->_host_list) || count($this->_host_list) == 0) {
-            $current_error = PEAR::raiseError('No Servers configured! Please '.
-               'pass in an array of servers to Net_LDAP2');
-            return $current_error;
-        }
-
-        // Cycle through the host list.
-        foreach ($this->_host_list as $host) {
-
-            // Ensure we have a valid string for host name
-            if (is_array($host)) {
-                $current_error = PEAR::raiseError('No Servers configured! '.
-                   'Please pass in an one dimensional array of servers to '.
-                   'Net_LDAP2! (multidimensional array detected!)');
-                continue;
-            }
-
-            // Skip this host if it is known to be down.
-            if (in_array($host, $this->_down_host_list)) {
-                continue;
-            }
-
-            // Record the host that we are actually connecting to in case
-            // we need it later.
-            $this->_config['host'] = $host;
-
-            // Attempt a connection.
-            $this->_link = @ldap_connect($host, $this->_config['port']);
-            if (false === $this->_link) {
-                $current_error = PEAR::raiseError('Could not connect to ' .
-                    $host . ':' . $this->_config['port']);
-                $this->_down_host_list[] = $host;
-                continue;
-            }
-
-            // If we're supposed to use TLS, do so before we try to bind,
-            // as some strict servers only allow binding via secure connections
-            if ($this->_config["starttls"] === true) {
-                if (self::isError($msg = $this->startTLS())) {
-                    $current_error           = $msg;
-                    $this->_link             = false;
-                    $this->_down_host_list[] = $host;
-                    continue;
-                }
-            }
-
-            // Try to set the configured LDAP version on the connection if LDAP
-            // server needs that before binding (eg OpenLDAP).
-            // This could be necessary since rfc-1777 states that the protocol version
-            // has to be set at the bind request.
-            // We use force here which means that the test in the rootDSE is skipped;
-            // this is neccessary, because some strict LDAP servers only allow to
-            // read the LDAP rootDSE (which tells us the supported protocol versions)
-            // with authenticated clients.
-            // This may fail in which case we try again after binding.
-            // In this case, most probably the bind() or setLDAPVersion()-call
-            // below will also fail, providing error messages.
-            $version_set = false;
-            $ignored_err = $this->setLDAPVersion(0, true);
-            if (!self::isError($ignored_err)) {
-                $version_set = true;
-            }
-
-            // Attempt to bind to the server. If we have credentials configured,
-            // we try to use them, otherwise its an anonymous bind.
-            // As stated by RFC-1777, the bind request should be the first
-            // operation to be performed after the connection is established.
-            // This may give an protocol error if the server does not support
-            // V2 binds and the above call to setLDAPVersion() failed.
-            // In case the above call failed, we try an V2 bind here and set the
-            // version afterwards (with checking to the rootDSE).
-            $msg = $this->bind();
-            if (self::isError($msg)) {
-                // The bind failed, discard link and save error msg.
-                // Then record the host as down and try next one
-                if ($msg->getCode() == 0x02 && !$version_set) {
-                    // provide a finer grained error message
-                    // if protocol error arieses because of invalid version
-                    $msg = new Net_LDAP2_Error($msg->getMessage().
-                        " (could not set LDAP protocol version to ".
-                        $this->_config['version'].")",
-                        $msg->getCode());
-                }
-                $this->_link             = false;
-                $current_error           = $msg;
-                $this->_down_host_list[] = $host;
-                continue;
-            }
-
-            // Set desired LDAP version if not successfully set before.
-            // Here, a check against the rootDSE is performed, so we get a
-            // error message if the server does not support the version.
-            // The rootDSE entry should tell us which LDAP versions are
-            // supported. However, some strict LDAP servers only allow
-            // bound suers to read the rootDSE.
-            if (!$version_set) {
-                if (self::isError($msg = $this->setLDAPVersion())) {
-                    $current_error           = $msg;
-                    $this->_link             = false;
-                    $this->_down_host_list[] = $host;
-                    continue;
-                }
-            }
-
-            // Set LDAP parameters, now we know we have a valid connection.
-            if (isset($this->_config['options']) &&
-                is_array($this->_config['options']) &&
-                count($this->_config['options'])) {
-                foreach ($this->_config['options'] as $opt => $val) {
-                    $err = $this->setOption($opt, $val);
-                    if (self::isError($err)) {
-                        $current_error           = $err;
-                        $this->_link             = false;
-                        $this->_down_host_list[] = $host;
-                        continue 2;
-                    }
-                }
-            }
-
-            // At this stage we have connected, bound, and set up options,
-            // so we have a known good LDAP server.  Time to go home.
-            return true;
-        }
-
-
-        // All connection attempts have failed, return the last error.
-        return $current_error;
-    }
-
-    /**
-    * Reconnect to the ldap-server.
-    *
-    * In case the connection to the LDAP
-    * service has dropped out for some reason, this function will reconnect,
-    * and re-bind if a bind has been attempted in the past.  It is probably
-    * most useful when the server list provided to the new() or connect()
-    * function is an array rather than a single host name, because in that
-    * case it will be able to connect to a failover or secondary server in
-    * case the primary server goes down.
-    *
-    * This doesn't return anything, it just tries to re-establish
-    * the current connection.  It will sleep for the current backoff
-    * period (seconds) before attempting the connect, and if the
-    * connection fails it will double the backoff period, but not
-    * try again.  If you want to ensure a reconnection during a
-    * transient period of server downtime then you need to call this
-    * function in a loop.
-    *
-    * @access protected
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    */
-    protected function performReconnect()
-    {
-
-        // Return true if we are already connected.
-        if ($this->_link !== false) {
-            return true;
-        }
-
-        // Default error message in case all connection attempts
-        // fail but no message is set
-        $current_error = new PEAR_Error('Unknown connection error');
-
-        // Sleep for a backoff period in seconds.
-        sleep($this->_config['current_backoff']);
-
-        // Retry all available connections.
-        $this->_down_host_list = array();
-        $msg = $this->performConnect();
-
-        // Bail out if that fails.
-        if (self::isError($msg)) {
-            $this->_config['current_backoff'] =
-               $this->_config['current_backoff'] * 2;
-            if ($this->_config['current_backoff'] > $this->_config['max_backoff']) {
-                $this->_config['current_backoff'] = $this->_config['max_backoff'];
-            }
-            return $msg;
-        }
-
-        // Now we should be able to safely (re-)bind.
-        $msg = $this->bind();
-        if (self::isError($msg)) {
-            $this->_config['current_backoff'] = $this->_config['current_backoff'] * 2;
-            if ($this->_config['current_backoff'] > $this->_config['max_backoff']) {
-                $this->_config['current_backoff'] = $this->_config['max_backoff'];
-            }
-
-            // _config['host'] should have had the last connected host stored in it
-            // by performConnect().  Since we are unable to bind to that host we can safely
-            // assume that it is down or has some other problem.
-            $this->_down_host_list[] = $this->_config['host'];
-            return $msg;
-        }
-
-        // At this stage we have connected, bound, and set up options,
-        // so we have a known good LDAP server. Time to go home.
-        $this->_config['current_backoff'] = $this->_config['min_backoff'];
-        return true;
-    }
-
-    /**
-    * Starts an encrypted session
-    *
-    * @access public
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    */
-    public function startTLS()
-    {
-        // Test to see if the server supports TLS first.
-        // This is done via testing the extensions offered by the server.
-        // The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported.
-        $rootDSE = $this->rootDse();
-        if (self::isError($rootDSE)) {
-            return $this->raiseError("Unable to fetch rootDSE entry ".
-            "to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode());
-        }
-
-        $supported_extensions = $rootDSE->getValue('supportedExtension');
-        if (self::isError($supported_extensions)) {
-            return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ".
-            "to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode());
-        }
-
-        if (in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) {
-            if (false === @ldap_start_tls($this->_link)) {
-                return $this->raiseError("TLS not started: " .
-                                        @ldap_error($this->_link),
-                                        @ldap_errno($this->_link));
-            }
-            return true;
-        } else {
-            return $this->raiseError("Server reports that it does not support TLS");
-        }
-    }
-
-    /**
-    * alias function of startTLS() for perl-ldap interface
-    *
-    * @return void
-    * @see startTLS()
-    */
-    public function start_tls()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array( &$this, 'startTLS' ), $args);
-    }
-
-    /**
-    * Close LDAP connection.
-    *
-    * Closes the connection. Use this when the session is over.
-    *
-    * @return void
-    */
-    public function done()
-    {
-        $this->_Net_LDAP2();
-    }
-
-    /**
-    * Alias for {@link done()}
-    *
-    * @return void
-    * @see done()
-    */
-    public function disconnect()
-    {
-        $this->done();
-    }
-
-    /**
-    * Destructor
-    *
-    * @access protected
-    */
-    public function _Net_LDAP2()
-    {
-        @ldap_close($this->_link);
-    }
-
-    /**
-    * Add a new entryobject to a directory.
-    *
-    * Use add to add a new Net_LDAP2_Entry object to the directory.
-    * This also links the entry to the connection used for the add,
-    * if it was a fresh entry ({@link Net_LDAP2_Entry::createFresh()})
-    *
-    * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry
-    *
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    */
-    public function add(&$entry)
-    {
-        if (!$entry instanceof Net_LDAP2_Entry) {
-            return PEAR::raiseError('Parameter to Net_LDAP2::add() must be a Net_LDAP2_Entry object.');
-        }
-
-        // Continue attempting the add operation in a loop until we
-        // get a success, a definitive failure, or the world ends.
-        $foo = 0;
-        while (true) {
-            $link = $this->getLink();
-
-            if ($link === false) {
-                // We do not have a successful connection yet.  The call to
-                // getLink() would have kept trying if we wanted one.  Go
-                // home now.
-                return PEAR::raiseError("Could not add entry " . $entry->dn() .
-                       " no valid LDAP connection could be found.");
-            }
-
-            if (@ldap_add($link, $entry->dn(), $entry->getValues())) {
-                // entry successfully added, we should update its $ldap reference
-                // in case it is not set so far (fresh entry)
-                if (!$entry->getLDAP() instanceof Net_LDAP2) {
-                    $entry->setLDAP($this);
-                }
-                // store, that the entry is present inside the directory
-                $entry->markAsNew(false);
-                return true;
-            } else {
-                // We have a failure.  What type?  We may be able to reconnect
-                // and try again.
-                $error_code = @ldap_errno($link);
-                $error_name = $this->errorMessage($error_code);
-
-                if (($error_name === 'LDAP_OPERATIONS_ERROR') &&
-                    ($this->_config['auto_reconnect'])) {
-
-                    // The server has become disconnected before trying the
-                    // operation.  We should try again, possibly with a different
-                    // server.
-                    $this->_link = false;
-                    $this->performReconnect();
-                } else {
-                    // Errors other than the above catched are just passed
-                    // back to the user so he may react upon them.
-                    return PEAR::raiseError("Could not add entry " . $entry->dn() . " " .
-                                            $error_name,
-                                            $error_code);
-                }
-            }
-        }
-    }
-
-    /**
-    * Delete an entry from the directory
-    *
-    * The object may either be a string representing the dn or a Net_LDAP2_Entry
-    * object. When the boolean paramter recursive is set, all subentries of the
-    * entry will be deleted as well.
-    *
-    * @param string|Net_LDAP2_Entry $dn        DN-string or Net_LDAP2_Entry
-    * @param boolean                $recursive Should we delete all children recursive as well?
-    *
-    * @access public
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    */
-    public function delete($dn, $recursive = false)
-    {
-        if ($dn instanceof Net_LDAP2_Entry) {
-             $dn = $dn->dn();
-        }
-        if (false === is_string($dn)) {
-            return PEAR::raiseError("Parameter is not a string nor an entry object!");
-        }
-        // Recursive delete searches for children and calls delete for them
-        if ($recursive) {
-            $result = @ldap_list($this->_link, $dn, '(objectClass=*)', array(null), 0, 0);
-            if (@ldap_count_entries($this->_link, $result)) {
-                $subentry = @ldap_first_entry($this->_link, $result);
-                $this->delete(@ldap_get_dn($this->_link, $subentry), true);
-                while ($subentry = @ldap_next_entry($this->_link, $subentry)) {
-                    $this->delete(@ldap_get_dn($this->_link, $subentry), true);
-                }
-            }
-        }
-
-        // Continue attempting the delete operation in a loop until we
-        // get a success, a definitive failure, or the world ends.
-        while (true) {
-            $link = $this->getLink();
-
-            if ($link === false) {
-                // We do not have a successful connection yet.  The call to
-                // getLink() would have kept trying if we wanted one.  Go
-                // home now.
-                return PEAR::raiseError("Could not add entry " . $dn .
-                       " no valid LDAP connection could be found.");
-            }
-
-            if (@ldap_delete($link, $dn)) {
-                // entry successfully deleted.
-                return true;
-            } else {
-                // We have a failure.  What type?
-                // We may be able to reconnect and try again.
-                $error_code = @ldap_errno($link);
-                $error_name = $this->errorMessage($error_code);
-
-                if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
-                    ($this->_config['auto_reconnect'])) {
-                    // The server has become disconnected before trying the
-                    // operation.  We should try again, possibly with a 
-                    // different server.
-                    $this->_link = false;
-                    $this->performReconnect();
-
-                } elseif ($error_code == 66) {
-                    // Subentries present, server refused to delete.
-                    // Deleting subentries is the clients responsibility, but
-                    // since the user may not know of the subentries, we do not
-                    // force that here but instead notify the developer so he
-                    // may take actions himself.
-                    return PEAR::raiseError("Could not delete entry $dn because of subentries. Use the recursive parameter to delete them.");
-
-                } else {
-                    // Errors other than the above catched are just passed
-                    // back to the user so he may react upon them.
-                    return PEAR::raiseError("Could not delete entry " . $dn . " " .
-                                            $error_name,
-                                            $error_code);
-                }
-            }
-        }
-    }
-
-    /**
-    * Modify an ldapentry directly on the server
-    *
-    * This one takes the DN or a Net_LDAP2_Entry object and an array of actions.
-    * This array should be something like this:
-    *
-    * array('add' => array('attribute1' => array('val1', 'val2'),
-    *                      'attribute2' => array('val1')),
-    *       'delete' => array('attribute1'),
-    *       'replace' => array('attribute1' => array('val1')),
-    *       'changes' => array('add' => ...,
-    *                          'replace' => ...,
-    *                          'delete' => array('attribute1', 'attribute2' => array('val1')))
-    *
-    * The changes array is there so the order of operations can be influenced
-    * (the operations are done in order of appearance).
-    * The order of execution is as following:
-    *   1. adds from 'add' array
-    *   2. deletes from 'delete' array
-    *   3. replaces from 'replace' array
-    *   4. changes (add, replace, delete) in order of appearance
-    * All subarrays (add, replace, delete, changes) may be given at the same time.
-    *
-    * The function calls the corresponding functions of an Net_LDAP2_Entry
-    * object. A detailed description of array structures can be found there.
-    *
-    * Unlike the modification methods provided by the Net_LDAP2_Entry object,
-    * this method will instantly carry out an update() after each operation,
-    * thus modifying "directly" on the server.
-    *
-    * @param string|Net_LDAP2_Entry $entry DN-string or Net_LDAP2_Entry
-    * @param array                  $parms Array of changes
-    *
-    * @access public
-    * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true
-    */
-    public function modify($entry, $parms = array())
-    {
-        if (is_string($entry)) {
-            $entry = $this->getEntry($entry);
-            if (self::isError($entry)) {
-                return $entry;
-            }
-        }
-        if (!$entry instanceof Net_LDAP2_Entry) {
-            return PEAR::raiseError("Parameter is not a string nor an entry object!");
-        }
-
-        // Perform changes mentioned separately
-        foreach (array('add', 'delete', 'replace') as $action) {
-            if (isset($parms[$action])) {
-                $msg = $entry->$action($parms[$action]);
-                if (self::isError($msg)) {
-                    return $msg;
-                }
-                $entry->setLDAP($this);
-
-                // Because the @ldap functions are called inside Net_LDAP2_Entry::update(),
-                // we have to trap the error codes issued from that if we want to support
-                // reconnection.
-                while (true) {
-                    $msg = $entry->update();
-
-                    if (self::isError($msg)) {
-                        // We have a failure.  What type?  We may be able to reconnect
-                        // and try again.
-                        $error_code = $msg->getCode();
-                        $error_name = $this->errorMessage($error_code);
-
-                        if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
-                            ($this->_config['auto_reconnect'])) {
-
-                            // The server has become disconnected before trying the
-                            // operation.  We should try again, possibly with a different
-                            // server.
-                            $this->_link = false;
-                            $this->performReconnect();
-
-                        } else {
-
-                            // Errors other than the above catched are just passed
-                            // back to the user so he may react upon them.
-                            return PEAR::raiseError("Could not modify entry: ".$msg->getMessage());
-                        }
-                    } else {
-                        // modification succeedet, evaluate next change
-                        break;
-                    }
-                }
-            }
-        }
-
-        // perform combined changes in 'changes' array
-        if (isset($parms['changes']) && is_array($parms['changes'])) {
-            foreach ($parms['changes'] as $action => $value) {
-
-                // Because the @ldap functions are called inside Net_LDAP2_Entry::update,
-                // we have to trap the error codes issued from that if we want to support
-                // reconnection.
-                while (true) {
-                    $msg = $this->modify($entry, array($action => $value));
-
-                    if (self::isError($msg)) {
-                        // We have a failure.  What type?  We may be able to reconnect
-                        // and try again.
-                        $error_code = $msg->getCode();
-                        $error_name = $this->errorMessage($error_code);
-
-                        if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
-                            ($this->_config['auto_reconnect'])) {
-
-                            // The server has become disconnected before trying the
-                            // operation.  We should try again, possibly with a different
-                            // server.
-                            $this->_link = false;
-                            $this->performReconnect();
-
-                        } else {
-                            // Errors other than the above catched are just passed
-                            // back to the user so he may react upon them.
-                            return $msg;
-                        }
-                    } else {
-                        // modification succeedet, evaluate next change
-                        break;
-                    }
-                }
-            }
-        }
-
-        return true;
-    }
-
-    /**
-    * Run a ldap search query
-    *
-    * Search is used to query the ldap-database.
-    * $base and $filter may be ommitted. The one from config will
-    * then be used. $base is either a DN-string or an Net_LDAP2_Entry
-    * object in which case its DN willb e used.
-    *
-    * Params may contain:
-    *
-    * scope: The scope which will be used for searching
-    *        base - Just one entry
-    *        sub  - The whole tree
-    *        one  - Immediately below $base
-    * sizelimit: Limit the number of entries returned (default: 0 = unlimited),
-    * timelimit: Limit the time spent for searching (default: 0 = unlimited),
-    * attrsonly: If true, the search will only return the attribute names,
-    * attributes: Array of attribute names, which the entry should contain.
-    *             It is good practice to limit this to just the ones you need.
-    * [NOT IMPLEMENTED]
-    * deref: By default aliases are dereferenced to locate the base object for the search, but not when
-    *        searching subordinates of the base object. This may be changed by specifying one of the
-    *        following values:
-    *
-    *        never  - Do not dereference aliases in searching or in locating the base object of the search.
-    *        search - Dereference aliases in subordinates of the base object in searching, but not in
-    *                locating the base object of the search.
-    *        find
-    *        always
-    *
-    * Please note, that you cannot override server side limitations to sizelimit
-    * and timelimit: You can always only lower a given limit.
-    *
-    * @param string|Net_LDAP2_Entry  $base   LDAP searchbase
-    * @param string|Net_LDAP2_Filter $filter LDAP search filter or a Net_LDAP2_Filter object
-    * @param array                   $params Array of options
-    *
-    * @access public
-    * @return Net_LDAP2_Search|Net_LDAP2_Error Net_LDAP2_Search object or Net_LDAP2_Error object
-    * @todo implement search controls (sorting etc)
-    */
-    public function search($base = null, $filter = null, $params = array())
-    {
-        if (is_null($base)) {
-            $base = $this->_config['basedn'];
-        }
-        if ($base instanceof Net_LDAP2_Entry) {
-            $base = $base->dn(); // fetch DN of entry, making searchbase relative to the entry
-        }
-        if (is_null($filter)) {
-            $filter = $this->_config['filter'];
-        }
-        if ($filter instanceof Net_LDAP2_Filter) {
-            $filter = $filter->asString(); // convert Net_LDAP2_Filter to string representation
-        }
-        if (PEAR::isError($filter)) {
-            return $filter;
-        }
-        if (PEAR::isError($base)) {
-            return $base;
-        }
-
-        /* setting searchparameters  */
-        (isset($params['sizelimit']))  ? $sizelimit  = $params['sizelimit']  : $sizelimit = 0;
-        (isset($params['timelimit']))  ? $timelimit  = $params['timelimit']  : $timelimit = 0;
-        (isset($params['attrsonly']))  ? $attrsonly  = $params['attrsonly']  : $attrsonly = 0;
-        (isset($params['attributes'])) ? $attributes = $params['attributes'] : $attributes = array();
-
-        // Ensure $attributes to be an array in case only one
-        // attribute name was given as string
-        if (!is_array($attributes)) {
-            $attributes = array($attributes);
-        }
-
-        // reorganize the $attributes array index keys
-        // sometimes there are problems with not consecutive indexes
-        $attributes = array_values($attributes);
-
-        // scoping makes searches faster!
-        $scope = (isset($params['scope']) ? $params['scope'] : $this->_config['scope']);
-
-        switch ($scope) {
-        case 'one':
-            $search_function = 'ldap_list';
-            break;
-        case 'base':
-            $search_function = 'ldap_read';
-            break;
-        default:
-            $search_function = 'ldap_search';
-        }
-
-        // Continue attempting the search operation until we get a success
-        // or a definitive failure.
-        while (true) {
-            $link = $this->getLink();
-            $search = @call_user_func($search_function,
-                                      $link,
-                                      $base,
-                                      $filter,
-                                      $attributes,
-                                      $attrsonly,
-                                      $sizelimit,
-                                      $timelimit);
-
-            if ($err = @ldap_errno($link)) {
-                if ($err == 32) {
-                    // Errorcode 32 = no such object, i.e. a nullresult.
-                    return $obj = new Net_LDAP2_Search ($search, $this, $attributes);
-                } elseif ($err == 4) {
-                    // Errorcode 4 = sizelimit exeeded.
-                    return $obj = new Net_LDAP2_Search ($search, $this, $attributes);
-                } elseif ($err == 87) {
-                    // bad search filter
-                    return $this->raiseError($this->errorMessage($err) . "($filter)", $err);
-                } elseif (($err == 1) && ($this->_config['auto_reconnect'])) {
-                    // Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect.
-                    $this->_link = false;
-                    $this->performReconnect();
-                } else {
-                    $msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope";
-                    return $this->raiseError($this->errorMessage($err) . $msg, $err);
-                }
-            } else {
-                return $obj = new Net_LDAP2_Search($search, $this, $attributes);
-            }
-        }
-    }
-
-    /**
-    * Set an LDAP option
-    *
-    * @param string $option Option to set
-    * @param mixed  $value  Value to set Option to
-    *
-    * @access public
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    */
-    public function setOption($option, $value)
-    {
-        if ($this->_link) {
-            if (defined($option)) {
-                if (@ldap_set_option($this->_link, constant($option), $value)) {
-                    return true;
-                } else {
-                    $err = @ldap_errno($this->_link);
-                    if ($err) {
-                        $msg = @ldap_err2str($err);
-                    } else {
-                        $err = NET_LDAP2_ERROR;
-                        $msg = $this->errorMessage($err);
-                    }
-                    return $this->raiseError($msg, $err);
-                }
-            } else {
-                return $this->raiseError("Unkown Option requested");
-            }
-        } else {
-            return $this->raiseError("Could not set LDAP option: No LDAP connection");
-        }
-    }
-
-    /**
-    * Get an LDAP option value
-    *
-    * @param string $option Option to get
-    *
-    * @access public
-    * @return Net_LDAP2_Error|string Net_LDAP2_Error or option value
-    */
-    public function getOption($option)
-    {
-        if ($this->_link) {
-            if (defined($option)) {
-                if (@ldap_get_option($this->_link, constant($option), $value)) {
-                    return $value;
-                } else {
-                    $err = @ldap_errno($this->_link);
-                    if ($err) {
-                        $msg = @ldap_err2str($err);
-                    } else {
-                        $err = NET_LDAP2_ERROR;
-                        $msg = $this->errorMessage($err);
-                    }
-                    return $this->raiseError($msg, $err);
-                }
-            } else {
-                $this->raiseError("Unkown Option requested");
-            }
-        } else {
-            $this->raiseError("No LDAP connection");
-        }
-    }
-
-    /**
-    * Get the LDAP_PROTOCOL_VERSION that is used on the connection.
-    *
-    * A lot of ldap functionality is defined by what protocol version the ldap server speaks.
-    * This might be 2 or 3.
-    *
-    * @return int
-    */
-    public function getLDAPVersion()
-    {
-        if ($this->_link) {
-            $version = $this->getOption("LDAP_OPT_PROTOCOL_VERSION");
-        } else {
-            $version = $this->_config['version'];
-        }
-        return $version;
-    }
-
-    /**
-    * Set the LDAP_PROTOCOL_VERSION that is used on the connection.
-    *
-    * @param int     $version LDAP-version that should be used
-    * @param boolean $force   If set to true, the check against the rootDSE will be skipped
-    *
-    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
-    * @todo Checking via the rootDSE takes much time - why? fetching and instanciation is quick!
-    */
-    public function setLDAPVersion($version = 0, $force = false)
-    {
-        if (!$version) {
-            $version = $this->_config['version'];
-        }
-
-        //
-        // Check to see if the server supports this version first.
-        //
-        // Todo: Why is this so horribly slow?
-        // $this->rootDse() is very fast, as well as Net_LDAP2_RootDSE::fetch()
-        // seems like a problem at copiyng the object inside PHP??
-        // Additionally, this is not always reproducable...
-        //
-        if (!$force) {
-            $rootDSE = $this->rootDse();
-            if ($rootDSE instanceof Net_LDAP2_Error) {
-                return $rootDSE;
-            } else {
-                $supported_versions = $rootDSE->getValue('supportedLDAPVersion');
-                if (is_string($supported_versions)) {
-                    $supported_versions = array($supported_versions);
-                }
-                $check_ok = in_array($version, $supported_versions);
-            }
-        }
-
-        if ($force || $check_ok) {
-            return $this->setOption("LDAP_OPT_PROTOCOL_VERSION", $version);
-        } else {
-            return $this->raiseError("LDAP Server does not support protocol version " . $version);
-        }
-    }
-
-
-    /**
-    * Tells if a DN does exist in the directory
-    *
-    * @param string|Net_LDAP2_Entry $dn The DN of the object to test
-    *
-    * @return boolean|Net_LDAP2_Error
-    */
-    public function dnExists($dn)
-    {
-        if (PEAR::isError($dn)) {
-            return $dn;
-        }
-        if ($dn instanceof Net_LDAP2_Entry) {
-             $dn = $dn->dn();
-        }
-        if (false === is_string($dn)) {
-            return PEAR::raiseError('Parameter $dn is not a string nor an entry object!');
-        }
-
-        // make dn relative to parent
-        $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false));
-        if (self::isError($base)) {
-            return $base;
-        }
-        $entry_rdn = array_shift($base);
-        if (is_array($entry_rdn)) {
-            // maybe the dn consist of a multivalued RDN, we must build the dn in this case
-            // because the $entry_rdn is an array!
-            $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn);
-        }
-        $base = Net_LDAP2_Util::canonical_dn($base);
-
-        $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1);
-        if (@ldap_count_entries($this->_link, $result)) {
-            return true;
-        }
-        if (ldap_errno($this->_link) == 32) {
-            return false;
-        }
-        if (ldap_errno($this->_link) != 0) {
-            return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link));
-        }
-        return false;
-    }
-
-
-    /**
-    * Get a specific entry based on the DN
-    *
-    * @param string $dn   DN of the entry that should be fetched
-    * @param array  $attr Array of Attributes to select. If ommitted, all attributes are fetched.
-    *
-    * @return Net_LDAP2_Entry|Net_LDAP2_Error    Reference to a Net_LDAP2_Entry object or Net_LDAP2_Error object
-    * @todo Maybe check against the shema should be done to be sure the attribute type exists
-    */
-    public function &getEntry($dn, $attr = array())
-    {
-        if (!is_array($attr)) {
-            $attr = array($attr);
-        }
-        $result = $this->search($dn, '(objectClass=*)',
-                                array('scope' => 'base', 'attributes' => $attr));
-        if (self::isError($result)) {
-            return $result;
-        } elseif ($result->count() == 0) {
-            return PEAR::raiseError('Could not fetch entry '.$dn.': no entry found');
-        }
-        $entry = $result->shiftEntry();
-        if (false == $entry) {
-            return PEAR::raiseError('Could not fetch entry (error retrieving entry from search result)');
-        }
-        return $entry;
-    }
-
-    /**
-    * Rename or move an entry
-    *
-    * This method will instantly carry out an update() after the move,
-    * so the entry is moved instantly.
-    * You can pass an optional Net_LDAP2 object. In this case, a cross directory
-    * move will be performed which deletes the entry in the source (THIS) directory
-    * and adds it in the directory $target_ldap.
-    * A cross directory move will switch the Entrys internal LDAP reference so
-    * updates to the entry will go to the new directory.
-    *
-    * Note that if you want to do a cross directory move, you need to
-    * pass an Net_LDAP2_Entry object, otherwise the attributes will be empty.
-    *
-    * @param string|Net_LDAP2_Entry $entry       Entry DN or Entry object
-    * @param string                 $newdn       New location
-    * @param Net_LDAP2              $target_ldap (optional) Target directory for cross server move; should be passed via reference
-    *
-    * @return Net_LDAP2_Error|true
-    */
-    public function move($entry, $newdn, $target_ldap = null)
-    {
-        if (is_string($entry)) {
-            $entry_o = $this->getEntry($entry);
-        } else {
-            $entry_o =& $entry;
-        }
-        if (!$entry_o instanceof Net_LDAP2_Entry) {
-            return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object! (If DN was passed, conversion failed)');
-        }
-        if (null !== $target_ldap && !$target_ldap instanceof Net_LDAP2) {
-            return PEAR::raiseError('Parameter $target_ldap is expected to be a Net_LDAP2 object!');
-        }
-
-        if ($target_ldap && $target_ldap !== $this) {
-            // cross directory move
-            if (is_string($entry)) {
-                return PEAR::raiseError('Unable to perform cross directory move: operation requires a Net_LDAP2_Entry object');
-            }
-            if ($target_ldap->dnExists($newdn)) {
-                return PEAR::raiseError('Unable to perform cross directory move: entry does exist in target directory');
-            }
-            $entry_o->dn($newdn);
-            $res = $target_ldap->add($entry_o);
-            if (self::isError($res)) {
-                return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in target directory');
-            }
-            $res = $this->delete($entry_o->currentDN());
-            if (self::isError($res)) {
-                $res2 = $target_ldap->delete($entry_o); // undo add
-                if (self::isError($res2)) {
-                    $add_error_string = 'Additionally, the deletion (undo add) of $entry in target directory failed.';
-                }
-                return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in source directory. '.$add_error_string);
-            }
-            $entry_o->setLDAP($target_ldap);
-            return true;
-        } else {
-            // local move
-            $entry_o->dn($newdn);
-            $entry_o->setLDAP($this);
-            return $entry_o->update();
-        }
-    }
-
-    /**
-    * Copy an entry to a new location
-    *
-    * The entry will be immediately copied.
-    * Please note that only attributes you have
-    * selected will be copied.
-    *
-    * @param Net_LDAP2_Entry &$entry Entry object
-    * @param string          $newdn  New FQF-DN of the entry
-    *
-    * @return Net_LDAP2_Error|Net_LDAP2_Entry Error Message or reference to the copied entry
-    */
-    public function &copy(&$entry, $newdn)
-    {
-        if (!$entry instanceof Net_LDAP2_Entry) {
-            return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object!');
-        }
-
-        $newentry = Net_LDAP2_Entry::createFresh($newdn, $entry->getValues());
-        $result   = $this->add($newentry);
-
-        if ($result instanceof Net_LDAP2_Error) {
-            return $result;
-        } else {
-            return $newentry;
-        }
-    }
-
-
-    /**
-    * Returns the string for an ldap errorcode.
-    *
-    * Made to be able to make better errorhandling
-    * Function based on DB::errorMessage()
-    * Tip: The best description of the errorcodes is found here:
-    * http://www.directory-info.com/LDAP2/LDAPErrorCodes.html
-    *
-    * @param int $errorcode Error code
-    *
-    * @return string The errorstring for the error.
-    */
-    public function errorMessage($errorcode)
-    {
-        $errorMessages = array(
-                              0x00 => "LDAP_SUCCESS",
-                              0x01 => "LDAP_OPERATIONS_ERROR",
-                              0x02 => "LDAP_PROTOCOL_ERROR",
-                              0x03 => "LDAP_TIMELIMIT_EXCEEDED",
-                              0x04 => "LDAP_SIZELIMIT_EXCEEDED",
-                              0x05 => "LDAP_COMPARE_FALSE",
-                              0x06 => "LDAP_COMPARE_TRUE",
-                              0x07 => "LDAP_AUTH_METHOD_NOT_SUPPORTED",
-                              0x08 => "LDAP_STRONG_AUTH_REQUIRED",
-                              0x09 => "LDAP_PARTIAL_RESULTS",
-                              0x0a => "LDAP_REFERRAL",
-                              0x0b => "LDAP_ADMINLIMIT_EXCEEDED",
-                              0x0c => "LDAP_UNAVAILABLE_CRITICAL_EXTENSION",
-                              0x0d => "LDAP_CONFIDENTIALITY_REQUIRED",
-                              0x0e => "LDAP_SASL_BIND_INPROGRESS",
-                              0x10 => "LDAP_NO_SUCH_ATTRIBUTE",
-                              0x11 => "LDAP_UNDEFINED_TYPE",
-                              0x12 => "LDAP_INAPPROPRIATE_MATCHING",
-                              0x13 => "LDAP_CONSTRAINT_VIOLATION",
-                              0x14 => "LDAP_TYPE_OR_VALUE_EXISTS",
-                              0x15 => "LDAP_INVALID_SYNTAX",
-                              0x20 => "LDAP_NO_SUCH_OBJECT",
-                              0x21 => "LDAP_ALIAS_PROBLEM",
-                              0x22 => "LDAP_INVALID_DN_SYNTAX",
-                              0x23 => "LDAP_IS_LEAF",
-                              0x24 => "LDAP_ALIAS_DEREF_PROBLEM",
-                              0x30 => "LDAP_INAPPROPRIATE_AUTH",
-                              0x31 => "LDAP_INVALID_CREDENTIALS",
-                              0x32 => "LDAP_INSUFFICIENT_ACCESS",
-                              0x33 => "LDAP_BUSY",
-                              0x34 => "LDAP_UNAVAILABLE",
-                              0x35 => "LDAP_UNWILLING_TO_PERFORM",
-                              0x36 => "LDAP_LOOP_DETECT",
-                              0x3C => "LDAP_SORT_CONTROL_MISSING",
-                              0x3D => "LDAP_INDEX_RANGE_ERROR",
-                              0x40 => "LDAP_NAMING_VIOLATION",
-                              0x41 => "LDAP_OBJECT_CLASS_VIOLATION",
-                              0x42 => "LDAP_NOT_ALLOWED_ON_NONLEAF",
-                              0x43 => "LDAP_NOT_ALLOWED_ON_RDN",
-                              0x44 => "LDAP_ALREADY_EXISTS",
-                              0x45 => "LDAP_NO_OBJECT_CLASS_MODS",
-                              0x46 => "LDAP_RESULTS_TOO_LARGE",
-                              0x47 => "LDAP_AFFECTS_MULTIPLE_DSAS",
-                              0x50 => "LDAP_OTHER",
-                              0x51 => "LDAP_SERVER_DOWN",
-                              0x52 => "LDAP_LOCAL_ERROR",
-                              0x53 => "LDAP_ENCODING_ERROR",
-                              0x54 => "LDAP_DECODING_ERROR",
-                              0x55 => "LDAP_TIMEOUT",
-                              0x56 => "LDAP_AUTH_UNKNOWN",
-                              0x57 => "LDAP_FILTER_ERROR",
-                              0x58 => "LDAP_USER_CANCELLED",
-                              0x59 => "LDAP_PARAM_ERROR",
-                              0x5a => "LDAP_NO_MEMORY",
-                              0x5b => "LDAP_CONNECT_ERROR",
-                              0x5c => "LDAP_NOT_SUPPORTED",
-                              0x5d => "LDAP_CONTROL_NOT_FOUND",
-                              0x5e => "LDAP_NO_RESULTS_RETURNED",
-                              0x5f => "LDAP_MORE_RESULTS_TO_RETURN",
-                              0x60 => "LDAP_CLIENT_LOOP",
-                              0x61 => "LDAP_REFERRAL_LIMIT_EXCEEDED",
-                              1000 => "Unknown Net_LDAP2 Error"
-                              );
-
-         return isset($errorMessages[$errorcode]) ?
-            $errorMessages[$errorcode] :
-            $errorMessages[NET_LDAP2_ERROR] . ' (' . $errorcode . ')';
-    }
-
-    /**
-    * Gets a rootDSE object
-    *
-    * This either fetches a fresh rootDSE object or returns it from
-    * the internal cache for performance reasons, if possible.
-    *
-    * @param array $attrs Array of attributes to search for
-    *
-    * @access public
-    * @return Net_LDAP2_Error|Net_LDAP2_RootDSE Net_LDAP2_Error or Net_LDAP2_RootDSE object
-    */
-    public function &rootDse($attrs = null)
-    {
-        if ($attrs !== null && !is_array($attrs)) {
-            return PEAR::raiseError('Parameter $attr is expected to be an array!');
-        }
-
-        $attrs_signature = serialize($attrs);
-
-        // see if we need to fetch a fresh object, or if we already
-        // requested this object with the same attributes
-        if (true || !array_key_exists($attrs_signature, $this->_rootDSE_cache)) {
-            $rootdse =& Net_LDAP2_RootDSE::fetch($this, $attrs);
-            if ($rootdse instanceof Net_LDAP2_Error) {
-                return $rootdse;
-            }
-
-            // search was ok, store rootDSE in cache
-            $this->_rootDSE_cache[$attrs_signature] = $rootdse;
-        }
-        return $this->_rootDSE_cache[$attrs_signature];
-    }
-
-    /**
-    * Alias function of rootDse() for perl-ldap interface
-    *
-    * @access public
-    * @see rootDse()
-    * @return Net_LDAP2_Error|Net_LDAP2_RootDSE
-    */
-    public function &root_dse()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array(&$this, 'rootDse'), $args);
-    }
-
-    /**
-    * Get a schema object
-    *
-    * @param string $dn (optional) Subschema entry dn
-    *
-    * @access public
-    * @return Net_LDAP2_Schema|Net_LDAP2_Error  Net_LDAP2_Schema or Net_LDAP2_Error object
-    */
-    public function &schema($dn = null)
-    {
-        // Schema caching by Knut-Olav Hoven
-        // If a schema caching object is registered, we use that to fetch
-        // a schema object.
-        // See registerSchemaCache() for more info on this.
-        if ($this->_schema === null) {
-            if ($this->_schema_cache) {
-               $cached_schema = $this->_schema_cache->loadSchema();
-               if ($cached_schema instanceof Net_LDAP2_Error) {
-                   return $cached_schema; // route error to client
-               } else {
-                   if ($cached_schema instanceof Net_LDAP2_Schema) {
-                       $this->_schema = $cached_schema;
-                   }
-               }
-            }
-        }
-
-        // Fetch schema, if not tried before and no cached version available.
-        // If we are already fetching the schema, we will skip fetching.
-        if ($this->_schema === null) {
-            // store a temporary error message so subsequent calls to schema() can
-            // detect, that we are fetching the schema already.
-            // Otherwise we will get an infinite loop at Net_LDAP2_Schema::fetch()
-            $this->_schema = new Net_LDAP2_Error('Schema not initialized');
-            $this->_schema = Net_LDAP2_Schema::fetch($this, $dn);
-
-            // If schema caching is active, advise the cache to store the schema
-            if ($this->_schema_cache) {
-                $caching_result = $this->_schema_cache->storeSchema($this->_schema);
-                if ($caching_result instanceof Net_LDAP2_Error) {
-                    return $caching_result; // route error to client
-                }
-            }
-        }
-        return $this->_schema;
-    }
-
-    /**
-    * Enable/disable persistent schema caching
-    *
-    * Sometimes it might be useful to allow your scripts to cache
-    * the schema information on disk, so the schema is not fetched
-    * every time the script runs which could make your scripts run
-    * faster.
-    *
-    * This method allows you to register a custom object that
-    * implements your schema cache. Please see the SchemaCache interface
-    * (SchemaCache.interface.php) for informations on how to implement this.
-    * To unregister the cache, pass null as $cache parameter.
-    *
-    * For ease of use, Net_LDAP2 provides a simple file based cache
-    * which is used in the example below. You may use this, for example,
-    * to store the schema in a linux tmpfs which results in the schema
-    * beeing cached inside the RAM which allows nearly instant access.
-    * <code>
-    *    // Create the simple file cache object that comes along with Net_LDAP2
-    *    $mySchemaCache_cfg = array(
-    *      'path'    =>  '/tmp/Net_LDAP2_Schema.cache',
-    *      'max_age' =>  86400   // max age is 24 hours (in seconds)
-    *    );
-    *    $mySchemaCache = new Net_LDAP2_SimpleFileSchemaCache($mySchemaCache_cfg);
-    *    $ldap = new Net_LDAP2::connect(...);
-    *    $ldap->registerSchemaCache($mySchemaCache); // enable caching
-    *    // now each call to $ldap->schema() will get the schema from disk!
-    * </code>
-    *
-    * @param Net_LDAP2_SchemaCache|null $cache Object implementing the Net_LDAP2_SchemaCache interface
-    *
-    * @return true|Net_LDAP2_Error
-    */
-    public function registerSchemaCache($cache) {
-        if (is_null($cache)
-        || (is_object($cache) && in_array('Net_LDAP2_SchemaCache', class_implements($cache))) ) {
-            $this->_schema_cache = $cache;
-            return true;
-        } else {
-            return new Net_LDAP2_Error('Custom schema caching object is either no '.
-                'valid object or does not implement the Net_LDAP2_SchemaCache interface!');
-        }
-    }
-
-
-    /**
-    * Checks if phps ldap-extension is loaded
-    *
-    * If it is not loaded, it tries to load it manually using PHPs dl().
-    * It knows both windows-dll and *nix-so.
-    *
-    * @static
-    * @return Net_LDAP2_Error|true
-    */
-    public static function checkLDAPExtension()
-    {
-        if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) {
-            return new Net_LDAP2_Error("It seems that you do not have the ldap-extension installed. Please install it before using the Net_LDAP2 package.");
-        } else {
-            return true;
-        }
-    }
-
-    /**
-    * Encodes given attributes to UTF8 if needed by schema
-    *
-    * This function takes attributes in an array and then checks against the schema if they need
-    * UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and
-    * can be used for adding or modifying.
-    *
-    * $attributes is expected to be an array with keys describing
-    * the attribute names and the values as the value of this attribute:
-    * <code>$attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2'));</code>
-    *
-    * @param array $attributes Array of attributes
-    *
-    * @access public
-    * @return array|Net_LDAP2_Error Array of UTF8 encoded attributes or Error
-    */
-    public function utf8Encode($attributes)
-    {
-        return $this->utf8($attributes, 'utf8_encode');
-    }
-
-    /**
-    * Decodes the given attribute values if needed by schema
-    *
-    * $attributes is expected to be an array with keys describing
-    * the attribute names and the values as the value of this attribute:
-    * <code>$attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2'));</code>
-    *
-    * @param array $attributes Array of attributes
-    *
-    * @access public
-    * @see utf8Encode()
-    * @return array|Net_LDAP2_Error Array with decoded attribute values or Error
-    */
-    public function utf8Decode($attributes)
-    {
-        return $this->utf8($attributes, 'utf8_decode');
-    }
-
-    /**
-    * Encodes or decodes attribute values if needed
-    *
-    * @param array $attributes Array of attributes
-    * @param array $function   Function to apply to attribute values
-    *
-    * @access protected
-    * @return array|Net_LDAP2_Error Array of attributes with function applied to values or Error
-    */
-    protected function utf8($attributes, $function)
-    {
-        if (!is_array($attributes) || array_key_exists(0, $attributes)) {
-            return PEAR::raiseError('Parameter $attributes is expected to be an associative array');
-        }
-
-        if (!$this->_schema) {
-            $this->_schema = $this->schema();
-        }
-
-        if (!$this->_link || self::isError($this->_schema) || !function_exists($function)) {
-            return $attributes;
-        }
-
-        if (is_array($attributes) && count($attributes) > 0) {
-
-            foreach ($attributes as $k => $v) {
-
-                if (!isset($this->_schemaAttrs[$k])) {
-
-                    $attr = $this->_schema->get('attribute', $k);
-                    if (self::isError($attr)) {
-                        continue;
-                    }
-
-                    if (false !== strpos($attr['syntax'], '1.3.6.1.4.1.1466.115.121.1.15')) {
-                        $encode = true;
-                    } else {
-                        $encode = false;
-                    }
-                    $this->_schemaAttrs[$k] = $encode;
-
-                } else {
-                    $encode = $this->_schemaAttrs[$k];
-                }
-
-                if ($encode) {
-                    if (is_array($v)) {
-                        foreach ($v as $ak => $av) {
-                            $v[$ak] = call_user_func($function, $av);
-                        }
-                    } else {
-                        $v = call_user_func($function, $v);
-                    }
-                }
-                $attributes[$k] = $v;
-            }
-        }
-        return $attributes;
-    }
-
-    /**
-    * Get the LDAP link resource.  It will loop attempting to
-    * re-establish the connection if the connection attempt fails and
-    * auto_reconnect has been turned on (see the _config array documentation).
-    *
-    * @access public
-    * @return resource LDAP link
-    */
-    public function &getLink()
-    {
-        if ($this->_config['auto_reconnect']) {
-            while (true) {
-                //
-                // Return the link handle if we are already connected.  Otherwise
-                // try to reconnect.
-                //
-                if ($this->_link !== false) {
-                    return $this->_link;
-                } else {
-                    $this->performReconnect();
-                }
-            }
-        }
-        return $this->_link;
-    }
-}
-
-/**
-* Net_LDAP2_Error implements a class for reporting portable LDAP error messages.
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Tarjej Huse <tarjei@bergfald.no>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP22/
-*/
-class Net_LDAP2_Error extends PEAR_Error
-{
-    /**
-     * Net_LDAP2_Error constructor.
-     *
-     * @param string  $message   String with error message.
-     * @param integer $code      Net_LDAP2 error code
-     * @param integer $mode      what "error mode" to operate in
-     * @param mixed   $level     what error level to use for $mode & PEAR_ERROR_TRIGGER
-     * @param mixed   $debuginfo additional debug info, such as the last query
-     *
-     * @access public
-     * @see PEAR_Error
-     */
-    public function __construct($message = 'Net_LDAP2_Error', $code = NET_LDAP2_ERROR, $mode = PEAR_ERROR_RETURN,
-                         $level = E_USER_NOTICE, $debuginfo = null)
-    {
-        if (is_int($code)) {
-            $this->PEAR_Error($message . ': ' . Net_LDAP2::errorMessage($code), $code, $mode, $level, $debuginfo);
-        } else {
-            $this->PEAR_Error("$message: $code", NET_LDAP2_ERROR, $mode, $level, $debuginfo);
-        }
-    }
-}
-
-?>
diff --git a/extlib/Net/LDAP2/Entry.php b/extlib/Net/LDAP2/Entry.php
deleted file mode 100644 (file)
index 66de966..0000000
+++ /dev/null
@@ -1,1055 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_Entry interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Jan Wagner <wagner@netsols.de>
-* @author    Tarjej Huse <tarjei@bergfald.no>
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Tarjej Huse, Jan Wagner, Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: Entry.php 286787 2009-08-04 06:03:12Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Includes
-*/
-require_once 'PEAR.php';
-require_once 'Util.php';
-
-/**
-* Object representation of a directory entry
-*
-* This class represents a directory entry. You can add, delete, replace
-* attributes and their values, rename the entry, delete the entry.
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Jan Wagner <wagner@netsols.de>
-* @author   Tarjej Huse <tarjei@bergfald.no>
-* @author   Benedikt Hallinger <beni@php.net>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP2/
-*/
-class Net_LDAP2_Entry extends PEAR
-{
-    /**
-    * Entry ressource identifier
-    *
-    * @access protected
-    * @var ressource
-    */
-    protected $_entry = null;
-
-    /**
-    * LDAP ressource identifier
-    *
-    * @access protected
-    * @var ressource
-    */
-    protected $_link = null;
-
-    /**
-    * Net_LDAP2 object
-    *
-    * This object will be used for updating and schema checking
-    *
-    * @access protected
-    * @var object Net_LDAP2
-    */
-    protected $_ldap = null;
-
-    /**
-    * Distinguished name of the entry
-    *
-    * @access protected
-    * @var string
-    */
-    protected $_dn = null;
-
-    /**
-    * Attributes
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_attributes = array();
-
-    /**
-    * Original attributes before any modification
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_original = array();
-
-
-    /**
-    * Map of attribute names
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_map = array();
-
-
-    /**
-    * Is this a new entry?
-    *
-    * @access protected
-    * @var boolean
-    */
-    protected $_new = true;
-
-    /**
-    * New distinguished name
-    *
-    * @access protected
-    * @var string
-    */
-    protected $_newdn = null;
-
-    /**
-    * Shall the entry be deleted?
-    *
-    * @access protected
-    * @var boolean
-    */
-    protected $_delete = false;
-
-    /**
-    * Map with changes to the entry
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_changes = array("add"     => array(),
-                                "delete"  => array(),
-                                "replace" => array()
-                               );
-    /**
-    * Internal Constructor
-    *
-    * Constructor of the entry. Sets up the distinguished name and the entries
-    * attributes.
-    * You should not call this method manually! Use {@link Net_LDAP2_Entry::createFresh()}
-    * or {@link Net_LDAP2_Entry::createConnected()} instead!
-    *
-    * @param Net_LDAP2|ressource|array &$ldap Net_LDAP2 object, ldap-link ressource or array of attributes
-    * @param string|ressource          $entry Either a DN or a LDAP-Entry ressource
-    *
-    * @access protected
-    * @return none
-    */
-    protected function __construct(&$ldap, $entry = null)
-    {
-        $this->PEAR('Net_LDAP2_Error');
-
-        // set up entry resource or DN
-        if (is_resource($entry)) {
-            $this->_entry = &$entry;
-        } else {
-            $this->_dn = $entry;
-        }
-
-        // set up LDAP link
-        if ($ldap instanceof Net_LDAP2) {
-            $this->_ldap = &$ldap;
-            $this->_link = $ldap->getLink();
-        } elseif (is_resource($ldap)) {
-            $this->_link = $ldap;
-        } elseif (is_array($ldap)) {
-            // Special case: here $ldap is an array of attributes,
-            // this means, we have no link. This is a "virtual" entry.
-            // We just set up the attributes so one can work with the object
-            // as expected, but an update() fails unless setLDAP() is called.
-            $this->setAttributes($ldap);
-        }
-
-        // if this is an entry existing in the directory,
-        // then set up as old and fetch attrs
-        if (is_resource($this->_entry) && is_resource($this->_link)) {
-            $this->_new = false;
-            $this->_dn  = @ldap_get_dn($this->_link, $this->_entry);
-            $this->setAttributes();  // fetch attributes from server
-        }
-    }
-
-    /**
-    * Creates a fresh entry that may be added to the directory later on
-    *
-    * Use this method, if you want to initialize a fresh entry.
-    *
-    * The method should be called statically: $entry = Net_LDAP2_Entry::createFresh();
-    * You should put a 'objectClass' attribute into the $attrs so the directory server
-    * knows which object you want to create. However, you may omit this in case you
-    * don't want to add this entry to a directory server.
-    *
-    * The attributes parameter is as following:
-    * <code>
-    * $attrs = array( 'attribute1' => array('value1', 'value2'),
-    *                 'attribute2' => 'single value'
-    *          );
-    * </code>
-    *
-    * @param string $dn    DN of the Entry
-    * @param array  $attrs Attributes of the entry
-    *
-    * @static
-    * @return Net_LDAP2_Entry|Net_LDAP2_Error
-    */
-    public static function createFresh($dn, $attrs = array())
-    {
-        if (!is_array($attrs)) {
-            return PEAR::raiseError("Unable to create fresh entry: Parameter \$attrs needs to be an array!");
-        }
-
-        $entry = new Net_LDAP2_Entry($attrs, $dn);
-        return $entry;
-    }
-
-    /**
-    * Creates a Net_LDAP2_Entry object out of an ldap entry resource
-    *
-    * Use this method, if you want to initialize an entry object that is
-    * already present in some directory and that you have read manually.
-    *
-    * Please note, that if you want to create an entry object that represents
-    * some already existing entry, you should use {@link createExisting()}.
-    *
-    * The method should be called statically: $entry = Net_LDAP2_Entry::createConnected();
-    *
-    * @param Net_LDAP2 $ldap  Net_LDA2 object
-    * @param resource  $entry PHP LDAP entry resource
-    *
-    * @static
-    * @return Net_LDAP2_Entry|Net_LDAP2_Error
-    */
-    public static function createConnected($ldap, $entry)
-    {
-        if (!$ldap instanceof Net_LDAP2) {
-            return PEAR::raiseError("Unable to create connected entry: Parameter \$ldap needs to be a Net_LDAP2 object!");
-        }
-        if (!is_resource($entry)) {
-            return PEAR::raiseError("Unable to create connected entry: Parameter \$entry needs to be a ldap entry resource!");
-        }
-
-        $entry = new Net_LDAP2_Entry($ldap, $entry);
-        return $entry;
-    }
-
-    /**
-    * Creates an Net_LDAP2_Entry object that is considered already existing
-    *
-    * Use this method, if you want to modify an already existing entry
-    * without fetching it first.
-    * In most cases however, it is better to fetch the entry via Net_LDAP2->getEntry()!
-    *
-    * Please note that you should take care if you construct entries manually with this
-    * because you may get weird synchronisation problems.
-    * The attributes and values as well as the entry itself are considered existent
-    * which may produce errors if you try to modify an entry which doesn't really exist
-    * or if you try to overwrite some attribute with an value already present.
-    *
-    * This method is equal to calling createFresh() and after that markAsNew(FALSE).
-    *
-    * The method should be called statically: $entry = Net_LDAP2_Entry::createExisting();
-    *
-    * The attributes parameter is as following:
-    * <code>
-    * $attrs = array( 'attribute1' => array('value1', 'value2'),
-    *                 'attribute2' => 'single value'
-    *          );
-    * </code>
-    *
-    * @param string $dn    DN of the Entry
-    * @param array  $attrs Attributes of the entry
-    *
-    * @static
-    * @return Net_LDAP2_Entry|Net_LDAP2_Error
-    */
-    public static function createExisting($dn, $attrs = array())
-    {
-        if (!is_array($attrs)) {
-            return PEAR::raiseError("Unable to create entry object: Parameter \$attrs needs to be an array!");
-        }
-
-        $entry = Net_LDAP2_Entry::createFresh($dn, $attrs);
-        if ($entry instanceof Net_LDAP2_Error) {
-            return $entry;
-        } else {
-            $entry->markAsNew(false);
-            return $entry;
-        }
-    }
-
-    /**
-    * Get or set the distinguished name of the entry
-    *
-    * If called without an argument the current (or the new DN if set) DN gets returned.
-    * If you provide an DN, this entry is moved to the new location specified if a DN existed.
-    * If the DN was not set, the DN gets initialized. Call {@link update()} to actually create
-    * the new Entry in the directory.
-    * To fetch the current active DN after setting a new DN but before an update(), you can use
-    * {@link currentDN()} to retrieve the DN that is currently active.
-    *
-    * Please note that special characters (eg german umlauts) should be encoded using utf8_encode().
-    * You may use {@link Net_LDAP2_Util::canonical_dn()} for properly encoding of the DN.
-    *
-    * @param string $dn New distinguished name
-    *
-    * @access public
-    * @return string|true Distinguished name (or true if a new DN was provided)
-    */
-    public function dn($dn = null)
-    {
-        if (false == is_null($dn)) {
-            if (is_null($this->_dn)) {
-                $this->_dn = $dn;
-            } else {
-                $this->_newdn = $dn;
-            }
-            return true;
-        }
-        return (isset($this->_newdn) ? $this->_newdn : $this->currentDN());
-    }
-
-    /**
-    * Renames or moves the entry
-    *
-    * This is just a convinience alias to {@link dn()}
-    * to make your code more meaningful.
-    *
-    * @param string $newdn The new DN
-    *
-    * @return true
-    */
-    public function move($newdn)
-    {
-        return $this->dn($newdn);
-    }
-
-    /**
-    * Sets the internal attributes array
-    *
-    * This fetches the values for the attributes from the server.
-    * The attribute Syntax will be checked so binary attributes will be returned
-    * as binary values.
-    *
-    * Attributes may be passed directly via the $attributes parameter to setup this
-    * entry manually. This overrides attribute fetching from the server.
-    *
-    * @param array $attributes Attributes to set for this entry
-    *
-    * @access protected
-    * @return void
-    */
-    protected function setAttributes($attributes = null)
-    {
-        /*
-        * fetch attributes from the server
-        */
-        if (is_null($attributes) && is_resource($this->_entry) && is_resource($this->_link)) {
-            // fetch schema
-            if ($this->_ldap instanceof Net_LDAP2) {
-                $schema =& $this->_ldap->schema();
-            }
-            // fetch attributes
-            $attributes = array();
-            do {
-                if (empty($attr)) {
-                    $ber  = null;
-                    $attr = @ldap_first_attribute($this->_link, $this->_entry, $ber);
-                } else {
-                    $attr = @ldap_next_attribute($this->_link, $this->_entry, $ber);
-                }
-                if ($attr) {
-                    $func = 'ldap_get_values'; // standard function to fetch value
-
-                    // Try to get binary values as binary data
-                    if ($schema instanceof Net_LDAP2_Schema) {
-                        if ($schema->isBinary($attr)) {
-                             $func = 'ldap_get_values_len';
-                        }
-                    }
-                    // fetch attribute value (needs error checking?)
-                    $attributes[$attr] = $func($this->_link, $this->_entry, $attr);
-                }
-            } while ($attr);
-        }
-
-        /*
-        * set attribute data directly, if passed
-        */
-        if (is_array($attributes) && count($attributes) > 0) {
-            if (isset($attributes["count"]) && is_numeric($attributes["count"])) {
-                unset($attributes["count"]);
-            }
-            foreach ($attributes as $k => $v) {
-                // attribute names should not be numeric
-                if (is_numeric($k)) {
-                    continue;
-                }
-                // map generic attribute name to real one
-                $this->_map[strtolower($k)] = $k;
-                // attribute values should be in an array
-                if (false == is_array($v)) {
-                    $v = array($v);
-                }
-                // remove the value count (comes from ldap server)
-                if (isset($v["count"])) {
-                    unset($v["count"]);
-                }
-                $this->_attributes[$k] = $v;
-            }
-        }
-
-        // save a copy for later use
-        $this->_original = $this->_attributes;
-    }
-
-    /**
-    * Get the values of all attributes in a hash
-    *
-    * The returned hash has the form
-    * <code>array('attributename' => 'single value',
-    *       'attributename' => array('value1', value2', value3'))</code>
-    *
-    * @access public
-    * @return array Hash of all attributes with their values
-    */
-    public function getValues()
-    {
-        $attrs = array();
-        foreach ($this->_attributes as $attr => $value) {
-            $attrs[$attr] = $this->getValue($attr);
-        }
-        return $attrs;
-    }
-
-    /**
-    * Get the value of a specific attribute
-    *
-    * The first parameter is the name of the attribute
-    * The second parameter influences the way the value is returned:
-    * 'single': only the first value is returned as string
-    * 'all': all values including the value count are returned in an
-    *               array
-    * 'default': in all other cases an attribute value with a single value is
-    *            returned as string, if it has multiple values it is returned
-    *            as an array (without value count)
-    *
-    * @param string $attr   Attribute name
-    * @param string $option Option
-    *
-    * @access public
-    * @return string|array|PEAR_Error string, array or PEAR_Error
-    */
-    public function getValue($attr, $option = null)
-    {
-        $attr = $this->getAttrName($attr);
-
-        if (false == array_key_exists($attr, $this->_attributes)) {
-            return PEAR::raiseError("Unknown attribute ($attr) requested");
-        }
-
-        $value = $this->_attributes[$attr];
-
-        if ($option == "single" || (count($value) == 1 && $option != 'all')) {
-            $value = array_shift($value);
-        }
-
-        return $value;
-    }
-
-    /**
-    * Alias function of getValue for perl-ldap interface
-    *
-    * @see getValue()
-    * @return string|array|PEAR_Error
-    */
-    public function get_value()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array( &$this, 'getValue' ), $args);
-    }
-
-    /**
-    * Returns an array of attributes names
-    *
-    * @access public
-    * @return array Array of attribute names
-    */
-    public function attributes()
-    {
-        return array_keys($this->_attributes);
-    }
-
-    /**
-    * Returns whether an attribute exists or not
-    *
-    * @param string $attr Attribute name
-    *
-    * @access public
-    * @return boolean
-    */
-    public function exists($attr)
-    {
-        $attr = $this->getAttrName($attr);
-        return array_key_exists($attr, $this->_attributes);
-    }
-
-    /**
-    * Adds a new attribute or a new value to an existing attribute
-    *
-    * The paramter has to be an array of the form:
-    * array('attributename' => 'single value',
-    *       'attributename' => array('value1', 'value2))
-    * When the attribute already exists the values will be added, else the
-    * attribute will be created. These changes are local to the entry and do
-    * not affect the entry on the server until update() is called.
-    *
-    * Note, that you can add values of attributes that you haven't selected, but if
-    * you do so, {@link getValue()} and {@link getValues()} will only return the
-    * values you added, _NOT_ all values present on the server. To avoid this, just refetch
-    * the entry after calling {@link update()} or select the attribute.
-    *
-    * @param array $attr Attributes to add
-    *
-    * @access public
-    * @return true|Net_LDAP2_Error
-    */
-    public function add($attr = array())
-    {
-        if (false == is_array($attr)) {
-            return PEAR::raiseError("Parameter must be an array");
-        }
-        foreach ($attr as $k => $v) {
-            $k = $this->getAttrName($k);
-            if (false == is_array($v)) {
-                // Do not add empty values
-                if ($v == null) {
-                    continue;
-                } else {
-                    $v = array($v);
-                }
-            }
-            // add new values to existing attribute or add new attribute
-            if ($this->exists($k)) {
-                $this->_attributes[$k] = array_unique(array_merge($this->_attributes[$k], $v));
-            } else {
-                $this->_map[strtolower($k)] = $k;
-                $this->_attributes[$k]      = $v;
-            }
-            // save changes for update()
-            if (empty($this->_changes["add"][$k])) {
-                $this->_changes["add"][$k] = array();
-            }
-            $this->_changes["add"][$k] = array_unique(array_merge($this->_changes["add"][$k], $v));
-        }
-        $return = true;
-        return $return;
-    }
-
-    /**
-    * Deletes an whole attribute or a value or the whole entry
-    *
-    * The parameter can be one of the following:
-    *
-    * "attributename" - The attribute as a whole will be deleted
-    * array("attributename1", "attributename2) - All given attributes will be
-    *                                            deleted
-    * array("attributename" => "value") - The value will be deleted
-    * array("attributename" => array("value1", "value2") - The given values
-    *                                                      will be deleted
-    * If $attr is null or omitted , then the whole Entry will be deleted!
-    *
-    * These changes are local to the entry and do
-    * not affect the entry on the server until {@link update()} is called.
-    *
-    * Please note that you must select the attribute (at $ldap->search() for example)
-    * to be able to delete values of it, Otherwise {@link update()} will silently fail
-    * and remove nothing.
-    *
-    * @param string|array $attr Attributes to delete (NULL or missing to delete whole entry)
-    *
-    * @access public
-    * @return true
-    */
-    public function delete($attr = null)
-    {
-        if (is_null($attr)) {
-            $this->_delete = true;
-            return true;
-        }
-        if (is_string($attr)) {
-            $attr = array($attr);
-        }
-        // Make the assumption that attribute names cannot be numeric,
-        // therefore this has to be a simple list of attribute names to delete
-        if (is_numeric(key($attr))) {
-            foreach ($attr as $name) {
-                if (is_array($name)) {
-                    // someone mixed modes (list mode but specific values given!)
-                    $del_attr_name = array_search($name, $attr);
-                    $this->delete(array($del_attr_name => $name));
-                } else {
-                    // mark for update() if this attr was not marked before
-                    $name = $this->getAttrName($name);
-                    if ($this->exists($name)) {
-                        $this->_changes["delete"][$name] = null;
-                        unset($this->_attributes[$name]);
-                    }
-                }
-            }
-        } else {
-            // Here we have a hash with "attributename" => "value to delete"
-            foreach ($attr as $name => $values) {
-                if (is_int($name)) {
-                    // someone mixed modes and gave us just an attribute name
-                    $this->delete($values);
-                } else {
-                    // mark for update() if this attr was not marked before;
-                    // this time it must consider the selected values also
-                    $name = $this->getAttrName($name);
-                    if ($this->exists($name)) {
-                        if (false == is_array($values)) {
-                            $values = array($values);
-                        }
-                        // save values to be deleted
-                        if (empty($this->_changes["delete"][$name])) {
-                            $this->_changes["delete"][$name] = array();
-                        }
-                        $this->_changes["delete"][$name] =
-                            array_unique(array_merge($this->_changes["delete"][$name], $values));
-                        foreach ($values as $value) {
-                            // find the key for the value that should be deleted
-                            $key = array_search($value, $this->_attributes[$name]);
-                            if (false !== $key) {
-                                // delete the value
-                                unset($this->_attributes[$name][$key]);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        $return = true;
-        return $return;
-    }
-
-    /**
-    * Replaces attributes or its values
-    *
-    * The parameter has to an array of the following form:
-    * array("attributename" => "single value",
-    *       "attribute2name" => array("value1", "value2"),
-    *       "deleteme1" => null,
-    *       "deleteme2" => "")
-    * If the attribute does not yet exist it will be added instead (see also $force).
-    * If the attribue value is null, the attribute will de deleted.
-    *
-    * These changes are local to the entry and do
-    * not affect the entry on the server until {@link update()} is called.
-    *
-    * In some cases you are not allowed to read the attributes value (for
-    * example the ActiveDirectory attribute unicodePwd) but are allowed to
-    * replace the value. In this case replace() would assume that the attribute
-    * is not in the directory yet and tries to add it which will result in an
-    * LDAP_TYPE_OR_VALUE_EXISTS error.
-    * To force replace mode instead of add, you can set $force to true.
-    *
-    * @param array $attr  Attributes to replace
-    * @param bool  $force Force replacing mode in case we can't read the attr value but are allowed to replace it
-    *
-    * @access public
-    * @return true|Net_LDAP2_Error
-    */
-    public function replace($attr = array(), $force = false)
-    {
-        if (false == is_array($attr)) {
-            return PEAR::raiseError("Parameter must be an array");
-        }
-        foreach ($attr as $k => $v) {
-            $k = $this->getAttrName($k);
-            if (false == is_array($v)) {
-                // delete attributes with empty values; treat ints as string
-                if (is_int($v)) {
-                    $v = "$v";
-                }
-                if ($v == null) {
-                    $this->delete($k);
-                    continue;
-                } else {
-                    $v = array($v);
-                }
-            }
-            // existing attributes will get replaced
-            if ($this->exists($k) || $force) {
-                $this->_changes["replace"][$k] = $v;
-                $this->_attributes[$k]         = $v;
-            } else {
-                // new ones just get added
-                $this->add(array($k => $v));
-            }
-        }
-        $return = true;
-        return $return;
-    }
-
-    /**
-    * Update the entry on the directory server
-    *
-    * This will evaluate all changes made so far and send them
-    * to the directory server.
-    * Please note, that if you make changes to objectclasses wich
-    * have mandatory attributes set, update() will currently fail.
-    * Remove the entry from the server and readd it as new in such cases.
-    * This also will deal with problems with setting structural object classes.
-    *
-    * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance
-    *
-    * @access public
-    * @return true|Net_LDAP2_Error
-    * @todo Entry rename with a DN containing special characters needs testing!
-    */
-    public function update($ldap = null)
-    {
-        if ($ldap) {
-            $msg = $this->setLDAP($ldap);
-            if (Net_LDAP2::isError($msg)) {
-                return PEAR::raiseError('You passed an invalid $ldap variable to update()');
-            }
-        }
-
-        // ensure we have a valid LDAP object
-        $ldap =& $this->getLDAP();
-        if (!$ldap instanceof Net_LDAP2) {
-            return PEAR::raiseError("The entries LDAP object is not valid");
-        }
-
-        // Get and check link
-        $link = $ldap->getLink();
-        if (!is_resource($link)) {
-            return PEAR::raiseError("Could not update entry: internal LDAP link is invalid");
-        }
-
-        /*
-        * Delete the entry
-        */
-        if (true === $this->_delete) {
-            return $ldap->delete($this);
-        }
-
-        /*
-        * New entry
-        */
-        if (true === $this->_new) {
-            $msg = $ldap->add($this);
-            if (Net_LDAP2::isError($msg)) {
-                return $msg;
-            }
-            $this->_new                = false;
-            $this->_changes['add']     = array();
-            $this->_changes['delete']  = array();
-            $this->_changes['replace'] = array();
-            $this->_original           = $this->_attributes;
-
-            $return = true;
-            return $return;
-        }
-
-        /*
-        * Rename/move entry
-        */
-        if (false == is_null($this->_newdn)) {
-            if ($ldap->getLDAPVersion() !== 3) {
-                return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3");
-            }
-            // make dn relative to parent (needed for ldap rename)
-            $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false));
-            if (Net_LDAP2::isError($parent)) {
-                return $parent;
-            }
-            $child = array_shift($parent);
-            // maybe the dn consist of a multivalued RDN, we must build the dn in this case
-            // because the $child-RDN is an array!
-            if (is_array($child)) {
-                $child = Net_LDAP2_Util::canonical_dn($child);
-            }
-            $parent = Net_LDAP2_Util::canonical_dn($parent);
-
-            // rename/move
-            if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) {
-                return PEAR::raiseError("Entry not renamed: " .
-                                        @ldap_error($link), @ldap_errno($link));
-            }
-            // reflect changes to local copy
-            $this->_dn    = $this->_newdn;
-            $this->_newdn = null;
-        }
-
-        /*
-        * Carry out modifications to the entry
-        */
-        // ADD
-        foreach ($this->_changes["add"] as $attr => $value) {
-            // if attribute exists, add new values
-            if ($this->exists($attr)) {
-                if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) {
-                    return PEAR::raiseError("Could not add new values to attribute $attr: " .
-                                            @ldap_error($link), @ldap_errno($link));
-                }
-            } else {
-                // new attribute
-                if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
-                    return PEAR::raiseError("Could not add new attribute $attr: " .
-                                            @ldap_error($link), @ldap_errno($link));
-                }
-            }
-            // all went well here, I guess
-            unset($this->_changes["add"][$attr]);
-        }
-
-        // DELETE
-        foreach ($this->_changes["delete"] as $attr => $value) {
-            // In LDAPv3 you need to specify the old values for deleting
-            if (is_null($value) && $ldap->getLDAPVersion() === 3) {
-                $value = $this->_original[$attr];
-            }
-            if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) {
-                return PEAR::raiseError("Could not delete attribute $attr: " .
-                                        @ldap_error($link), @ldap_errno($link));
-            }
-            unset($this->_changes["delete"][$attr]);
-        }
-
-        // REPLACE
-        foreach ($this->_changes["replace"] as $attr => $value) {
-            if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
-                return PEAR::raiseError("Could not replace attribute $attr values: " .
-                                        @ldap_error($link), @ldap_errno($link));
-            }
-            unset($this->_changes["replace"][$attr]);
-        }
-
-        // all went well, so _original (server) becomes _attributes (local copy)
-        $this->_original = $this->_attributes;
-
-        $return = true;
-        return $return;
-    }
-
-    /**
-    * Returns the right attribute name
-    *
-    * @param string $attr Name of attribute
-    *
-    * @access protected
-    * @return string The right name of the attribute
-    */
-    protected function getAttrName($attr)
-    {
-        $name = strtolower($attr);
-        if (array_key_exists($name, $this->_map)) {
-            $attr = $this->_map[$name];
-        }
-        return $attr;
-    }
-
-    /**
-    * Returns a reference to the LDAP-Object of this entry
-    *
-    * @access public
-    * @return Net_LDAP2|Net_LDAP2_Error   Reference to the Net_LDAP2 Object (the connection) or Net_LDAP2_Error
-    */
-    public function &getLDAP()
-    {
-        if (!$this->_ldap instanceof Net_LDAP2) {
-            $err = new PEAR_Error('LDAP is not a valid Net_LDAP2 object');
-            return $err;
-        } else {
-            return $this->_ldap;
-        }
-    }
-
-    /**
-    * Sets a reference to the LDAP-Object of this entry
-    *
-    * After setting a Net_LDAP2 object, calling update() will use that object for
-    * updating directory contents. Use this to dynamicly switch directorys.
-    *
-    * @param Net_LDAP2 &$ldap Net_LDAP2 object that this entry should be connected to
-    *
-    * @access public
-    * @return true|Net_LDAP2_Error
-    */
-    public function setLDAP(&$ldap)
-    {
-        if (!$ldap instanceof Net_LDAP2) {
-            return PEAR::raiseError("LDAP is not a valid Net_LDAP2 object");
-        } else {
-            $this->_ldap =& $ldap;
-            return true;
-        }
-    }
-
-    /**
-    * Marks the entry as new/existing.
-    *
-    * If an Entry is marked as new, it will be added to the directory
-    * when calling {@link update()}.
-    * If the entry is marked as old ($mark = false), then the entry is
-    * assumed to be present in the directory server wich results in
-    * modification when calling {@link update()}.
-    *
-    * @param boolean $mark Value to set, defaults to "true"
-    *
-    * @return void
-    */
-    public function markAsNew($mark = true)
-    {
-        $this->_new = ($mark)? true : false;
-    }
-
-    /**
-    * Applies a regular expression onto a single- or multivalued attribute (like preg_match())
-    *
-    * This method behaves like PHPs preg_match() but with some exceptions.
-    * If you want to retrieve match information, then you MUST pass the
-    * $matches parameter via reference! otherwise you will get no matches.
-    * Since it is possible to have multi valued attributes the $matches
-    * array will have a additionally numerical dimension (one for each value):
-    * <code>
-    * $matches = array(
-    *         0 => array (usual preg_match() returnarray),
-    *         1 => array (usual preg_match() returnarray)
-    *     )
-    * </code>
-    * Please note, that $matches will be initialized to an empty array inside.
-    *
-    * Usage example:
-    * <code>
-    * $result = $entry->preg_match('/089(\d+)/', 'telephoneNumber', &$matches);
-    * if ( $result === true ){
-    *     echo "First match: ".$matches[0][1];   // Match of value 1, content of first bracket
-    * } else {
-    *     if ( Net_LDAP2::isError($result) ) {
-    *         echo "Error: ".$result->getMessage();
-    *     } else {
-    *         echo "No match found.";
-    *     }
-    * }
-    * </code>
-    *
-    * Please note that it is important to test for an Net_LDAP2_Error, because objects are
-    * evaluating to true by default, thus if an error occured, and you only check using "==" then
-    * you get misleading results. Use the "identical" (===) operator to test for matches to
-    * avoid this as shown above.
-    *
-    * @param string $regex     The regular expression
-    * @param string $attr_name The attribute to search in
-    * @param array  $matches   (optional, PASS BY REFERENCE!) Array to store matches in
-    *
-    * @return boolean|Net_LDAP2_Error  TRUE, if we had a match in one of the values, otherwise false. Net_LDAP2_Error in case something went wrong
-    */
-    public function pregMatch($regex, $attr_name, $matches = array())
-    {
-        $matches = array();
-
-        // fetch attribute values
-        $attr = $this->getValue($attr_name, 'all');
-        if (Net_LDAP2::isError($attr)) {
-            return $attr;
-        } else {
-            unset($attr['count']);
-        }
-
-        // perform preg_match() on all values
-        $match = false;
-        foreach ($attr as $thisvalue) {
-            $matches_int = array();
-            if (preg_match($regex, $thisvalue, $matches_int)) {
-                $match = true;
-                array_push($matches, $matches_int); // store matches in reference
-            }
-        }
-        return $match;
-    }
-
-    /**
-    * Alias of {@link pregMatch()} for compatibility to Net_LDAP 1
-    *
-    * @see pregMatch()
-    * @return boolean|Net_LDAP2_Error
-    */
-    public function preg_match()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array( &$this, 'pregMatch' ), $args);
-    }
-
-    /**
-    * Tells if the entry is consiedered as new (not present in the server)
-    *
-    * Please note, that this doesn't tell you if the entry is present on the server.
-    * Use {@link Net_LDAP2::dnExists()} to see if an entry is already there.
-    *
-    * @return boolean
-    */
-    public function isNew()
-    {
-        return $this->_new;
-    }
-
-
-    /**
-    * Is this entry going to be deleted once update() is called?
-    *
-    * @return boolean
-    */
-    public function willBeDeleted()
-    {
-        return $this->_delete;
-    }
-
-    /**
-    * Is this entry going to be moved once update() is called?
-    *
-    * @return boolean
-    */
-    public function willBeMoved()
-    {
-        return ($this->dn() !== $this->currentDN());
-    }
-
-    /**
-    * Returns always the original DN
-    *
-    * If an entry will be moved but {@link update()} was not called,
-    * {@link dn()} will return the new DN. This method however, returns
-    * always the current active DN.
-    *
-    * @return string
-    */
-    public function currentDN()
-    {
-        return $this->_dn;
-    }
-
-    /**
-    * Returns the attribute changes to be carried out once update() is called
-    *
-    * @return array
-    */
-    public function getChanges()
-    {
-        return $this->_changes;
-    }
-}
-?>
diff --git a/extlib/Net/LDAP2/Filter.php b/extlib/Net/LDAP2/Filter.php
deleted file mode 100644 (file)
index 0723eda..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_Filter interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: Filter.php 289978 2009-10-27 09:56:41Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Includes
-*/
-require_once 'PEAR.php';
-require_once 'Util.php';
-
-/**
-* Object representation of a part of a LDAP filter.
-*
-* This Class is not completely compatible to the PERL interface!
-*
-* The purpose of this class is, that users can easily build LDAP filters
-* without having to worry about right escaping etc.
-* A Filter is built using several independent filter objects
-* which are combined afterwards. This object works in two
-* modes, depending how the object is created.
-* If the object is created using the {@link create()} method, then this is a leaf-object.
-* If the object is created using the {@link combine()} method, then this is a container object.
-*
-* LDAP filters are defined in RFC-2254 and can be found under
-* {@link http://www.ietf.org/rfc/rfc2254.txt}
-*
-* Here a quick copy&paste example:
-* <code>
-* $filter0 = Net_LDAP2_Filter::create('stars', 'equals', '***');
-* $filter_not0 = Net_LDAP2_Filter::combine('not', $filter0);
-*
-* $filter1 = Net_LDAP2_Filter::create('gn', 'begins', 'bar');
-* $filter2 = Net_LDAP2_Filter::create('gn', 'ends', 'baz');
-* $filter_comp = Net_LDAP2_Filter::combine('or',array($filter_not0, $filter1, $filter2));
-*
-* echo $filter_comp->asString();
-* // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz))
-* // The stars in $filter0 are treaten as real stars unless you disable escaping.
-* </code>
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Benedikt Hallinger <beni@php.net>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP2/
-*/
-class Net_LDAP2_Filter extends PEAR
-{
-    /**
-    * Storage for combination of filters
-    *
-    * This variable holds a array of filter objects
-    * that should be combined by this filter object.
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_subfilters = array();
-
-    /**
-    * Match of this filter
-    *
-    * If this is a leaf filter, then a matching rule is stored,
-    * if it is a container, then it is a logical operator
-    *
-    * @access protected
-    * @var string
-    */
-    protected $_match;
-
-    /**
-    * Single filter
-    *
-    * If we operate in leaf filter mode,
-    * then the constructing method stores
-    * the filter representation here
-    *
-    * @acces private
-    * @var string
-    */
-    protected $_filter;
-
-    /**
-    * Create a new Net_LDAP2_Filter object and parse $filter.
-    *
-    * This is for PERL Net::LDAP interface.
-    * Construction of Net_LDAP2_Filter objects should happen through either
-    * {@link create()} or {@link combine()} which give you more control.
-    * However, you may use the perl iterface if you already have generated filters.
-    *
-    * @param string $filter LDAP filter string
-    *
-    * @see parse()
-    */
-    public function __construct($filter = false)
-    {
-        // The optional parameter must remain here, because otherwise create() crashes
-        if (false !== $filter) {
-            $filter_o = self::parse($filter);
-            if (PEAR::isError($filter_o)) {
-                $this->_filter = $filter_o; // assign error, so asString() can report it
-            } else {
-                $this->_filter = $filter_o->asString();
-            }
-        }
-    }
-
-    /**
-    * Constructor of a new part of a LDAP filter.
-    *
-    * The following matching rules exists:
-    *    - equals:         One of the attributes values is exactly $value
-    *                      Please note that case sensitiviness is depends on the
-    *                      attributes syntax configured in the server.
-    *    - begins:         One of the attributes values must begin with $value
-    *    - ends:           One of the attributes values must end with $value
-    *    - contains:       One of the attributes values must contain $value
-    *    - present | any:  The attribute can contain any value but must be existent
-    *    - greater:        The attributes value is greater than $value
-    *    - less:           The attributes value is less than $value
-    *    - greaterOrEqual: The attributes value is greater or equal than $value
-    *    - lessOrEqual:    The attributes value is less or equal than $value
-    *    - approx:         One of the attributes values is similar to $value
-    *
-    * If $escape is set to true (default) then $value will be escaped
-    * properly. If it is set to false then $value will be treaten as raw filter value string.
-    * You should escape yourself using {@link Net_LDAP2_Util::escape_filter_value()}!
-    *
-    * Examples:
-    * <code>
-    *   // This will find entries that contain an attribute "sn" that ends with "foobar":
-    *   $filter = new Net_LDAP2_Filter('sn', 'ends', 'foobar');
-    *
-    *   // This will find entries that contain an attribute "sn" that has any value set:
-    *   $filter = new Net_LDAP2_Filter('sn', 'any');
-    * </code>
-    *
-    * @param string  $attr_name Name of the attribute the filter should apply to
-    * @param string  $match     Matching rule (equals, begins, ends, contains, greater, less, greaterOrEqual, lessOrEqual, approx, any)
-    * @param string  $value     (optional) if given, then this is used as a filter
-    * @param boolean $escape    Should $value be escaped? (default: yes, see {@link Net_LDAP2_Util::escape_filter_value()} for detailed information)
-    *
-    * @return Net_LDAP2_Filter|Net_LDAP2_Error
-    */
-    public static function &create($attr_name, $match, $value = '', $escape = true)
-    {
-        $leaf_filter = new Net_LDAP2_Filter();
-        if ($escape) {
-            $array = Net_LDAP2_Util::escape_filter_value(array($value));
-            $value = $array[0];
-        }
-        switch (strtolower($match)) {
-        case 'equals':
-            $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')';
-            break;
-        case 'begins':
-            $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)';
-            break;
-        case 'ends':
-            $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')';
-            break;
-        case 'contains':
-            $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)';
-            break;
-        case 'greater':
-            $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')';
-            break;
-        case 'less':
-            $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')';
-            break;
-        case 'greaterorequal':
-        case '>=':
-            $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')';
-            break;
-        case 'lessorequal':
-        case '<=':
-            $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')';
-            break;
-        case 'approx':
-        case '~=':
-            $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')';
-            break;
-        case 'any':
-        case 'present': // alias that may improve user code readability
-            $leaf_filter->_filter = '(' . $attr_name . '=*)';
-            break;
-        default:
-            return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!');
-        }
-        return $leaf_filter;
-    }
-
-    /**
-    * Combine two or more filter objects using a logical operator
-    *
-    * This static method combines two or more filter objects and returns one single
-    * filter object that contains all the others.
-    * Call this method statically: $filter = Net_LDAP2_Filter('or', array($filter1, $filter2))
-    * If the array contains filter strings instead of filter objects, we will try to parse them.
-    *
-    * @param string                 $log_op  The locicall operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!"
-    * @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects
-    *
-    * @return Net_LDAP2_Filter|Net_LDAP2_Error
-    * @static
-    */
-    public static function &combine($log_op, $filters)
-    {
-        if (PEAR::isError($filters)) {
-            return $filters;
-        }
-
-        // substitude named operators to logical operators
-        if ($log_op == 'and') $log_op = '&';
-        if ($log_op == 'or')  $log_op = '|';
-        if ($log_op == 'not') $log_op = '!';
-
-        // tests for sane operation
-        if ($log_op == '!') {
-            // Not-combination, here we only accept one filter object or filter string
-            if ($filters instanceof Net_LDAP2_Filter) {
-                $filters = array($filters); // force array
-            } elseif (is_string($filters)) {
-                $filter_o = self::parse($filters);
-                if (PEAR::isError($filter_o)) {
-                    $err = PEAR::raiseError('Net_LDAP2_Filter combine error: '.$filter_o->getMessage());
-                    return $err;
-                } else {
-                    $filters = array($filter_o);
-                }
-            } elseif (is_array($filters)) {
-                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!');
-                return $err;
-            } else {
-                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!');
-                return $err;
-            }
-        } elseif ($log_op == '&' || $log_op == '|') {
-            if (!is_array($filters) || count($filters) < 2) {
-                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: parameter $filters is not an array or contains less than two Net_LDAP2_Filter objects!');
-                return $err;
-            }
-        } else {
-            $err = PEAR::raiseError('Net_LDAP2_Filter combine error: logical operator is not known!');
-            return $err;
-        }
-
-        $combined_filter = new Net_LDAP2_Filter();
-        foreach ($filters as $key => $testfilter) {     // check for errors
-            if (PEAR::isError($testfilter)) {
-                return $testfilter;
-            } elseif (is_string($testfilter)) {
-                // string found, try to parse into an filter object
-                $filter_o = self::parse($testfilter);
-                if (PEAR::isError($filter_o)) {
-                    return $filter_o;
-                } else {
-                    $filters[$key] = $filter_o;
-                }
-            } elseif (!$testfilter instanceof Net_LDAP2_Filter) {
-                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: invalid object passed in array $filters!');
-                return $err;
-            }
-        }
-
-        $combined_filter->_subfilters = $filters;
-        $combined_filter->_match      = $log_op;
-        return $combined_filter;
-    }
-
-    /**
-    * Parse FILTER into a Net_LDAP2_Filter object
-    *
-    * This parses an filter string into Net_LDAP2_Filter objects.
-    *
-    * @param string $FILTER The filter string
-    *
-    * @access static
-    * @return Net_LDAP2_Filter|Net_LDAP2_Error
-    * @todo Leaf-mode: Do we need to escape at all? what about *-chars?check for the need of encoding values, tackle problems (see code comments)
-    */
-    public static function parse($FILTER)
-    {
-        if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) {
-            if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) {
-                // Subfilter processing: pass subfilters to parse() and combine
-                // the objects using the logical operator detected
-                // we have now something like "&(...)(...)(...)" but at least one part ("!(...)").
-                // Each subfilter could be an arbitary complex subfilter.
-
-                // extract logical operator and filter arguments
-                $log_op              = substr($matches[1], 0, 1);
-                $remaining_component = substr($matches[1], 1);
-
-                // split $remaining_component into individual subfilters
-                // we cannot use split() for this, because we do not know the
-                // complexiness of the subfilter. Thus, we look trough the filter
-                // string and just recognize ending filters at the first level.
-                // We record the index number of the char and use that information
-                // later to split the string.
-                $sub_index_pos = array();
-                $prev_char     = ''; // previous character looked at
-                $level         = 0;  // denotes the current bracket level we are,
-                                     //   >1 is too deep, 1 is ok, 0 is outside any
-                                     //   subcomponent
-                for ($curpos = 0; $curpos < strlen($remaining_component); $curpos++) {
-                    $cur_char = substr($remaining_component, $curpos, 1);
-
-                    // rise/lower bracket level
-                    if ($cur_char == '(' && $prev_char != '\\') {
-                        $level++;
-                    } elseif  ($cur_char == ')' && $prev_char != '\\') {
-                        $level--;
-                    }
-
-                    if ($cur_char == '(' && $prev_char == ')' && $level == 1) {
-                        array_push($sub_index_pos, $curpos); // mark the position for splitting
-                    }
-                    $prev_char = $cur_char;
-                }
-
-                // now perform the splits. To get also the last part, we
-                // need to add the "END" index to the split array
-                array_push($sub_index_pos, strlen($remaining_component));
-                $subfilters = array();
-                $oldpos = 0;
-                foreach ($sub_index_pos as $s_pos) {
-                    $str_part = substr($remaining_component, $oldpos, $s_pos - $oldpos);
-                    array_push($subfilters, $str_part);
-                    $oldpos = $s_pos;
-                }
-
-                // some error checking...
-                if (count($subfilters) == 1) {
-                    // only one subfilter found
-                } elseif (count($subfilters) > 1) {
-                    // several subfilters found
-                    if ($log_op == "!") {
-                        return PEAR::raiseError("Filter parsing error: invalid filter syntax - NOT operator detected but several arguments given!");
-                    }
-                } else {
-                    // this should not happen unless the user specified a wrong filter
-                    return PEAR::raiseError("Filter parsing error: invalid filter syntax - got operator '$log_op' but no argument!");
-                }
-
-                // Now parse the subfilters into objects and combine them using the operator
-                $subfilters_o = array();
-                foreach ($subfilters as $s_s) {
-                    $o = self::parse($s_s);
-                    if (PEAR::isError($o)) {
-                        return $o;
-                    } else {
-                        array_push($subfilters_o, self::parse($s_s));
-                    }
-                }
-
-                $filter_o = self::combine($log_op, $subfilters_o);
-                return $filter_o;
-
-            } else {
-                // This is one leaf filter component, do some syntax checks, then escape and build filter_o
-                // $matches[1] should be now something like "foo=bar"
-
-                // detect multiple leaf components
-                // [TODO] Maybe this will make problems with filters containing brackets inside the value
-                if (stristr($matches[1], ')(')) {
-                    return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!");
-                } else {
-                    $filter_parts = preg_split('/(?<!\\\\)(=|=~|>|<|>=|<=)/', $matches[1], 2, PREG_SPLIT_DELIM_CAPTURE);
-                    if (count($filter_parts) != 3) {
-                        return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used");
-                    } else {
-                        $filter_o          = new Net_LDAP2_Filter();
-                        // [TODO]: Do we need to escape at all? what about *-chars user provide and that should remain special?
-                        //         I think, those prevent escaping! We need to check against PERL Net::LDAP!
-                        // $value_arr         = Net_LDAP2_Util::escape_filter_value(array($filter_parts[2]));
-                        // $value             = $value_arr[0];
-                        $value             = $filter_parts[2];
-                        $filter_o->_filter = '('.$filter_parts[0].$filter_parts[1].$value.')';
-                        return $filter_o;
-                    }
-                }
-            }
-        } else {
-               // ERROR: Filter components must be enclosed in round brackets
-               return PEAR::raiseError("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets");
-        }
-    }
-
-    /**
-    * Get the string representation of this filter
-    *
-    * This method runs through all filter objects and creates
-    * the string representation of the filter. If this
-    * filter object is a leaf filter, then it will return
-    * the string representation of this filter.
-    *
-    * @return string|Net_LDAP2_Error
-    */
-    public function asString()
-    {
-        if ($this->isLeaf()) {
-            $return = $this->_filter;
-        } else {
-            $return = '';
-            foreach ($this->_subfilters as $filter) {
-                $return = $return.$filter->asString();
-            }
-            $return = '(' . $this->_match . $return . ')';
-        }
-        return $return;
-    }
-
-    /**
-    * Alias for perl interface as_string()
-    *
-    * @see asString()
-    * @return string|Net_LDAP2_Error
-    */
-    public function as_string()
-    {
-        return $this->asString();
-    }
-
-    /**
-    * Print the text representation of the filter to FH, or the currently selected output handle if FH is not given
-    *
-    * This method is only for compatibility to the perl interface.
-    * However, the original method was called "print" but due to PHP language restrictions,
-    * we can't have a print() method.
-    *
-    * @param resource $FH (optional) A filehandle resource
-    *
-    * @return true|Net_LDAP2_Error
-    */
-    public function printMe($FH = false)
-    {
-        if (!is_resource($FH)) {
-            if (PEAR::isError($FH)) {
-                return $FH;
-            }
-            $filter_str = $this->asString();
-            if (PEAR::isError($filter_str)) {
-                return $filter_str;
-            } else {
-                print($filter_str);
-            }
-        } else {
-            $filter_str = $this->asString();
-            if (PEAR::isError($filter_str)) {
-                return $filter_str;
-            } else {
-                $res = @fwrite($FH, $this->asString());
-                if ($res == false) {
-                    return PEAR::raiseError("Unable to write filter string to filehandle \$FH!");
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-    * This can be used to escape a string to provide a valid LDAP-Filter.
-    *
-    * LDAP will only recognise certain characters as the
-    * character istself if they are properly escaped. This is
-    * what this method does.
-    * The method can be called statically, so you can use it outside
-    * for your own purposes (eg for escaping only parts of strings)
-    *
-    * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}.
-    * For upward compatibiliy reasons you are strongly encouraged to use the escape
-    * methods provided by the Net_LDAP2_Util class.
-    *
-    * @param string $value Any string who should be escaped
-    *
-    * @static
-    * @return string         The string $string, but escaped
-    * @deprecated  Do not use this method anymore, instead use Net_LDAP2_Util::escape_filter_value() directly
-    */
-    public static function escape($value)
-    {
-        $return = Net_LDAP2_Util::escape_filter_value(array($value));
-        return $return[0];
-    }
-
-    /**
-    * Is this a container or a leaf filter object?
-    *
-    * @access protected
-    * @return boolean
-    */
-    protected function isLeaf()
-    {
-        if (count($this->_subfilters) > 0) {
-            return false; // Container!
-        } else {
-            return true; // Leaf!
-        }
-    }
-}
-?>
diff --git a/extlib/Net/LDAP2/LDIF.php b/extlib/Net/LDAP2/LDIF.php
deleted file mode 100644 (file)
index 34f3e75..0000000
+++ /dev/null
@@ -1,922 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_LDIF interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: LDIF.php 286718 2009-08-03 07:30:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Includes
-*/
-require_once 'PEAR.php';
-require_once 'Net/LDAP2.php';
-require_once 'Net/LDAP2/Entry.php';
-require_once 'Net/LDAP2/Util.php';
-
-/**
-* LDIF capabilitys for Net_LDAP2, closely taken from PERLs Net::LDAP
-*
-* It provides a means to convert between Net_LDAP2_Entry objects and LDAP entries
-* represented in LDIF format files. Reading and writing are supported and may
-* manipulate single entries or lists of entries.
-*
-* Usage example:
-* <code>
-* // Read and parse an ldif-file into Net_LDAP2_Entry objects
-* // and print out the DNs. Store the entries for later use.
-* require 'Net/LDAP2/LDIF.php';
-* $options = array(
-*       'onerror' => 'die'
-* );
-* $entries = array();
-* $ldif = new Net_LDAP2_LDIF('test.ldif', 'r', $options);
-* do {
-*       $entry = $ldif->read_entry();
-*       $dn    = $entry->dn();
-*       echo " done building entry: $dn\n";
-*       array_push($entries, $entry);
-* } while (!$ldif->eof());
-* $ldif->done();
-*
-*
-* // write those entries to another file
-* $ldif = new Net_LDAP2_LDIF('test.out.ldif', 'w', $options);
-* $ldif->write_entry($entries);
-* $ldif->done();
-* </code>
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Benedikt Hallinger <beni@php.net>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP22/
-* @see      http://www.ietf.org/rfc/rfc2849.txt
-* @todo     Error handling should be PEARified
-* @todo     LDAPv3 controls are not implemented yet
-*/
-class Net_LDAP2_LDIF extends PEAR
-{
-    /**
-    * Options
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_options = array('encode'    => 'base64',
-                                'onerror'   => null,
-                                'change'    => 0,
-                                'lowercase' => 0,
-                                'sort'      => 0,
-                                'version'   => null,
-                                'wrap'      => 78,
-                                'raw'       => ''
-                               );
-
-    /**
-    * Errorcache
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_error = array('error' => null,
-                              'line'  => 0
-                             );
-
-    /**
-    * Filehandle for read/write
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_FH = null;
-
-    /**
-    * Says, if we opened the filehandle ourselves
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_FH_opened = false;
-
-    /**
-    * Linecounter for input file handle
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_input_line = 0;
-
-    /**
-    * counter for processed entries
-    *
-    * @access protected
-    * @var int
-    */
-    protected $_entrynum = 0;
-
-    /**
-    * Mode we are working in
-    *
-    * Either 'r', 'a' or 'w'
-    *
-    * @access protected
-    * @var string
-    */
-    protected $_mode = false;
-
-    /**
-    * Tells, if the LDIF version string was already written
-    *
-    * @access protected
-    * @var boolean
-    */
-    protected $_version_written = false;
-
-    /**
-    * Cache for lines that have build the current entry
-    *
-    * @access protected
-    * @var boolean
-    */
-    protected $_lines_cur = array();
-
-    /**
-    * Cache for lines that will build the next entry
-    *
-    * @access protected
-    * @var boolean
-    */
-    protected $_lines_next = array();
-
-    /**
-    * Open LDIF file for reading or for writing
-    *
-    * new (FILE):
-    * Open the file read-only. FILE may be the name of a file
-    * or an already open filehandle.
-    * If the file doesn't exist, it will be created if in write mode.
-    *
-    * new (FILE, MODE, OPTIONS):
-    *     Open the file with the given MODE (see PHPs fopen()), eg "w" or "a".
-    *     FILE may be the name of a file or an already open filehandle.
-    *     PERLs Net_LDAP2 "FILE|" mode does not work curently.
-    *
-    *     OPTIONS is an associative array and may contain:
-    *       encode => 'none' | 'canonical' | 'base64'
-    *         Some DN values in LDIF cannot be written verbatim and have to be encoded in some way:
-    *         'none'       No encoding.
-    *         'canonical'  See "canonical_dn()" in Net::LDAP::Util.
-    *         'base64'     Use base64. (default, this differs from the Perl interface.
-    *                                   The perl default is "none"!)
-    *
-    *       onerror => 'die' | 'warn' | NULL
-    *         Specify what happens when an error is detected.
-    *         'die'  Net_LDAP2_LDIF will croak with an appropriate message.
-    *         'warn' Net_LDAP2_LDIF will warn (echo) with an appropriate message.
-    *         NULL   Net_LDAP2_LDIF will not warn (default), use error().
-    *
-    *       change => 1
-    *         Write entry changes to the LDIF file instead of the entries itself. I.e. write LDAP
-    *         operations acting on the entries to the file instead of the entries contents.
-    *         This writes the changes usually carried out by an update() to the LDIF file.
-    *
-    *       lowercase => 1
-    *         Convert attribute names to lowercase when writing.
-    *
-    *       sort => 1
-    *         Sort attribute names when writing entries according to the rule:
-    *         objectclass first then all other attributes alphabetically sorted by attribute name
-    *
-    *       version => '1'
-    *         Set the LDIF version to write to the resulting LDIF file.
-    *         According to RFC 2849 currently the only legal value for this option is 1.
-    *         When this option is set Net_LDAP2_LDIF tries to adhere more strictly to
-    *         the LDIF specification in RFC2489 in a few places.
-    *         The default is NULL meaning no version information is written to the LDIF file.
-    *
-    *       wrap => 78
-    *         Number of columns where output line wrapping shall occur.
-    *         Default is 78. Setting it to 40 or lower inhibits wrapping.
-    *
-    *       raw => REGEX
-    *         Use REGEX to denote the names of attributes that are to be
-    *         considered binary in search results if writing entries.
-    *         Example: raw => "/(?i:^jpegPhoto|;binary)/i"
-    *
-    * @param string|ressource $file    Filename or filehandle
-    * @param string           $mode    Mode to open filename
-    * @param array            $options Options like described above
-    */
-    public function __construct($file, $mode = 'r', $options = array())
-    {
-        $this->PEAR('Net_LDAP2_Error'); // default error class
-
-        // First, parse options
-        // todo: maybe implement further checks on possible values
-        foreach ($options as $option => $value) {
-            if (!array_key_exists($option, $this->_options)) {
-                $this->dropError('Net_LDAP2_LDIF error: option '.$option.' not known!');
-                return;
-            } else {
-                $this->_options[$option] = strtolower($value);
-            }
-        }
-
-        // setup LDIF class
-        $this->version($this->_options['version']);
-
-        // setup file mode
-        if (!preg_match('/^[rwa]\+?$/', $mode)) {
-            $this->dropError('Net_LDAP2_LDIF error: file mode '.$mode.' not supported!');
-        } else {
-            $this->_mode = $mode;
-
-            // setup filehandle
-            if (is_resource($file)) {
-                // TODO: checks on mode possible?
-                $this->_FH =& $file;
-            } else {
-                $imode = substr($this->_mode, 0, 1);
-                if ($imode == 'r') {
-                    if (!file_exists($file)) {
-                        $this->dropError('Unable to open '.$file.' for read: file not found');
-                        $this->_mode = false;
-                    }
-                    if (!is_readable($file)) {
-                        $this->dropError('Unable to open '.$file.' for read: permission denied');
-                        $this->_mode = false;
-                    }
-                }
-
-                if (($imode == 'w' || $imode == 'a')) {
-                    if (file_exists($file)) {
-                        if (!is_writable($file)) {
-                            $this->dropError('Unable to open '.$file.' for write: permission denied');
-                            $this->_mode = false;
-                        }
-                    } else {
-                        if (!@touch($file)) {
-                            $this->dropError('Unable to create '.$file.' for write: permission denied');
-                            $this->_mode = false;
-                        }
-                    }
-                }
-
-                if ($this->_mode) {
-                    $this->_FH = @fopen($file, $this->_mode);
-                    if (false === $this->_FH) {
-                        // Fallback; should never be reached if tests above are good enough!
-                        $this->dropError('Net_LDAP2_LDIF error: Could not open file '.$file);
-                    } else {
-                        $this->_FH_opened = true;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-    * Read one entry from the file and return it as a Net::LDAP::Entry object.
-    *
-    * @return Net_LDAP2_Entry
-    */
-    public function read_entry()
-    {
-        // read fresh lines, set them as current lines and create the entry
-        $attrs = $this->next_lines(true);
-        if (count($attrs) > 0) {
-            $this->_lines_cur = $attrs;
-        }
-        return $this->current_entry();
-    }
-
-    /**
-    * Returns true when the end of the file is reached.
-    *
-    * @return boolean
-    */
-    public function eof()
-    {
-        return feof($this->_FH);
-    }
-
-    /**
-    * Write the entry or entries to the LDIF file.
-    *
-    * If you want to build an LDIF file containing several entries AND
-    * you want to call write_entry() several times, you must open the filehandle
-    * in append mode ("a"), otherwise you will always get the last entry only.
-    *
-    * @param Net_LDAP2_Entry|array $entries Entry or array of entries
-    *
-    * @return void
-    * @todo implement operations on whole entries (adding a whole entry)
-    */
-    public function write_entry($entries)
-    {
-        if (!is_array($entries)) {
-            $entries = array($entries);
-        }
-
-        foreach ($entries as $entry) {
-            $this->_entrynum++;
-            if (!$entry instanceof Net_LDAP2_Entry) {
-                $this->dropError('Net_LDAP2_LDIF error: entry '.$this->_entrynum.' is not an Net_LDAP2_Entry object');
-            } else {
-                if ($this->_options['change']) {
-                    // LDIF change mode
-                    // fetch change information from entry
-                    $entry_attrs_changes = $entry->getChanges();
-                    $num_of_changes      = count($entry_attrs_changes['add'])
-                                           + count($entry_attrs_changes['replace'])
-                                           + count($entry_attrs_changes['delete']);
-
-                    $is_changed = ($num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved());
-
-                    // write version if not done yet
-                    // also write DN of entry
-                    if ($is_changed) {
-                        if (!$this->_version_written) {
-                            $this->write_version();
-                        }
-                        $this->writeDN($entry->currentDN());
-                    }
-
-                    // process changes
-                    // TODO: consider DN add!
-                    if ($entry->willBeDeleted()) {
-                        $this->writeLine("changetype: delete".PHP_EOL);
-                    } elseif ($entry->willBeMoved()) {
-                        $this->writeLine("changetype: modrdn".PHP_EOL);
-                        $olddn     = Net_LDAP2_Util::ldap_explode_dn($entry->currentDN(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs
-                        $oldrdn    = array_shift($olddn);
-                        $oldparent = implode(',', $olddn);
-                        $newdn     = Net_LDAP2_Util::ldap_explode_dn($entry->dn(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs
-                        $rdn       = array_shift($newdn);
-                        $parent    = implode(',', $newdn);
-                        $this->writeLine("newrdn: ".$rdn.PHP_EOL);
-                        $this->writeLine("deleteoldrdn: 1".PHP_EOL);
-                        if ($parent !== $oldparent) {
-                            $this->writeLine("newsuperior: ".$parent.PHP_EOL);
-                        }
-                        // TODO: What if the entry has attribute changes as well?
-                        //       I think we should check for that and make a dummy
-                        //       entry with the changes that is written to the LDIF file
-                    } elseif ($num_of_changes > 0) {
-                        // write attribute change data
-                        $this->writeLine("changetype: modify".PHP_EOL);
-                        foreach ($entry_attrs_changes as $changetype => $entry_attrs) {
-                            foreach ($entry_attrs as $attr_name => $attr_values) {
-                                $this->writeLine("$changetype: $attr_name".PHP_EOL);
-                                if ($attr_values !== null) $this->writeAttribute($attr_name, $attr_values, $changetype);
-                                $this->writeLine("-".PHP_EOL);
-                            }
-                        }
-                    }
-
-                    // finish this entrys data if we had changes
-                    if ($is_changed) {
-                        $this->finishEntry();
-                    }
-                } else {
-                    // LDIF-content mode
-                    // fetch attributes for further processing
-                    $entry_attrs = $entry->getValues();
-
-                    // sort and put objectclass-attrs to first position
-                    if ($this->_options['sort']) {
-                        ksort($entry_attrs);
-                        if (array_key_exists('objectclass', $entry_attrs)) {
-                            $oc = $entry_attrs['objectclass'];
-                            unset($entry_attrs['objectclass']);
-                            $entry_attrs = array_merge(array('objectclass' => $oc), $entry_attrs);
-                        }
-                    }
-
-                    // write data
-                    if (!$this->_version_written) {
-                        $this->write_version();
-                    }
-                    $this->writeDN($entry->dn());
-                    foreach ($entry_attrs as $attr_name => $attr_values) {
-                        $this->writeAttribute($attr_name, $attr_values);
-                    }
-                    $this->finishEntry();
-                }
-            }
-        }
-    }
-
-    /**
-    * Write version to LDIF
-    *
-    * If the object's version is defined, this method allows to explicitely write the version before an entry is written.
-    * If not called explicitely, it gets called automatically when writing the first entry.
-    *
-    * @return void
-    */
-    public function write_version()
-    {
-        $this->_version_written = true;
-        if (!is_null($this->version())) {
-            return $this->writeLine('version: '.$this->version().PHP_EOL, 'Net_LDAP2_LDIF error: unable to write version');
-        }
-    }
-
-    /**
-    * Get or set LDIF version
-    *
-    * If called without arguments it returns the version of the LDIF file or NULL if no version has been set.
-    * If called with an argument it sets the LDIF version to VERSION.
-    * According to RFC 2849 currently the only legal value for VERSION is 1.
-    *
-    * @param int $version (optional) LDIF version to set
-    *
-    * @return int
-    */
-    public function version($version = null)
-    {
-        if ($version !== null) {
-            if ($version != 1) {
-                $this->dropError('Net_LDAP2_LDIF error: illegal LDIF version set');
-            } else {
-                $this->_options['version'] = $version;
-            }
-        }
-        return $this->_options['version'];
-    }
-
-    /**
-    * Returns the file handle the Net_LDAP2_LDIF object reads from or writes to.
-    *
-    * You can, for example, use this to fetch the content of the LDIF file yourself
-    *
-    * @return null|resource
-    */
-    public function &handle()
-    {
-        if (!is_resource($this->_FH)) {
-            $this->dropError('Net_LDAP2_LDIF error: invalid file resource');
-            $null = null;
-            return $null;
-        } else {
-            return $this->_FH;
-        }
-    }
-
-    /**
-    * Clean up
-    *
-    * This method signals that the LDIF object is no longer needed.
-    * You can use this to free up some memory and close the file handle.
-    * The file handle is only closed, if it was opened from Net_LDAP2_LDIF.
-    *
-    * @return void
-    */
-    public function done()
-    {
-        // close FH if we opened it
-        if ($this->_FH_opened) {
-            fclose($this->handle());
-        }
-
-        // free variables
-        foreach (get_object_vars($this) as $name => $value) {
-            unset($this->$name);
-        }
-    }
-
-    /**
-    * Returns last error message if error was found.
-    *
-    * Example:
-    * <code>
-    *  $ldif->someAction();
-    *  if ($ldif->error()) {
-    *     echo "Error: ".$ldif->error()." at input line: ".$ldif->error_lines();
-    *  }
-    * </code>
-    *
-    * @param boolean $as_string If set to true, only the message is returned
-    *
-    * @return false|Net_LDAP2_Error
-    */
-    public function error($as_string = false)
-    {
-        if (Net_LDAP2::isError($this->_error['error'])) {
-            return ($as_string)? $this->_error['error']->getMessage() : $this->_error['error'];
-        } else {
-            return false;
-        }
-    }
-
-    /**
-    * Returns lines that resulted in error.
-    *
-    * Perl returns an array of faulty lines in list context,
-    * but we always just return an int because of PHPs language.
-    *
-    * @return int
-    */
-    public function error_lines()
-    {
-        return $this->_error['line'];
-    }
-
-    /**
-    * Returns the current Net::LDAP::Entry object.
-    *
-    * @return Net_LDAP2_Entry|false
-    */
-    public function current_entry()
-    {
-        return $this->parseLines($this->current_lines());
-    }
-
-    /**
-    * Parse LDIF lines of one entry into an Net_LDAP2_Entry object
-    *
-    * @param array $lines LDIF lines for one entry
-    *
-    * @return Net_LDAP2_Entry|false Net_LDAP2_Entry object for those lines
-    * @todo what about file inclusions and urls? "jpegphoto:< file:///usr/local/directory/photos/fiona.jpg"
-    */
-    public function parseLines($lines)
-    {
-        // parse lines into an array of attributes and build the entry
-        $attributes = array();
-        $dn = false;
-        foreach ($lines as $line) {
-            if (preg_match('/^(\w+)(:|::|:<)\s(.+)$/', $line, $matches)) {
-                $attr  =& $matches[1];
-                $delim =& $matches[2];
-                $data  =& $matches[3];
-
-                if ($delim == ':') {
-                    // normal data
-                    $attributes[$attr][] = $data;
-                } elseif ($delim == '::') {
-                    // base64 data
-                    $attributes[$attr][] = base64_decode($data);
-                } elseif ($delim == ':<') {
-                    // file inclusion
-                    // TODO: Is this the job of the LDAP-client or the server?
-                    $this->dropError('File inclusions are currently not supported');
-                    //$attributes[$attr][] = ...;
-                } else {
-                    // since the pattern above, the delimeter cannot be something else.
-                    $this->dropError('Net_LDAP2_LDIF parsing error: invalid syntax at parsing entry line: '.$line);
-                    continue;
-                }
-
-                if (strtolower($attr) == 'dn') {
-                    // DN line detected
-                    $dn = $attributes[$attr][0];  // save possibly decoded DN
-                    unset($attributes[$attr]);    // remove wrongly added "dn: " attribute
-                }
-            } else {
-                // line not in "attr: value" format -> ignore
-                // maybe we should rise an error here, but this should be covered by
-                // next_lines() already. A problem arises, if users try to feed data of
-                // several entries to this method - the resulting entry will
-                // get wrong attributes. However, this is already mentioned in the
-                // methods documentation above.
-            }
-        }
-
-        if (false === $dn) {
-            $this->dropError('Net_LDAP2_LDIF parsing error: unable to detect DN for entry');
-            return false;
-        } else {
-            $newentry = Net_LDAP2_Entry::createFresh($dn, $attributes);
-            return $newentry;
-        }
-    }
-
-    /**
-    * Returns the lines that generated the current Net::LDAP::Entry object.
-    *
-    * Note that this returns an empty array if no lines have been read so far.
-    *
-    * @return array Array of lines
-    */
-    public function current_lines()
-    {
-        return $this->_lines_cur;
-    }
-
-    /**
-    * Returns the lines that will generate the next Net::LDAP::Entry object.
-    *
-    * If you set $force to TRUE then you can iterate over the lines that build
-    * up entries manually. Otherwise, iterating is done using {@link read_entry()}.
-    * Force will move the file pointer forward, thus returning the next entries lines.
-    *
-    * Wrapped lines will be unwrapped. Comments are stripped.
-    *
-    * @param boolean $force Set this to true if you want to iterate over the lines manually
-    *
-    * @return array
-    */
-    public function next_lines($force = false)
-    {
-        // if we already have those lines, just return them, otherwise read
-        if (count($this->_lines_next) == 0 || $force) {
-            $this->_lines_next = array(); // empty in case something was left (if used $force)
-            $entry_done        = false;
-            $fh                = &$this->handle();
-            $commentmode       = false; // if we are in an comment, for wrapping purposes
-            $datalines_read    = 0;     // how many lines with data we have read
-
-            while (!$entry_done && !$this->eof()) {
-                $this->_input_line++;
-                // Read line. Remove line endings, we want only data;
-                // this is okay since ending spaces should be encoded
-                $data = rtrim(fgets($fh));
-                if ($data === false) {
-                    // error only, if EOF not reached after fgets() call
-                    if (!$this->eof()) {
-                        $this->dropError('Net_LDAP2_LDIF error: error reading from file at input line '.$this->_input_line, $this->_input_line);
-                    }
-                    break;
-                } else {
-                    if (count($this->_lines_next) > 0 && preg_match('/^$/', $data)) {
-                        // Entry is finished if we have an empty line after we had data
-                        $entry_done = true;
-
-                        // Look ahead if the next EOF is nearby. Comments and empty
-                        // lines at the file end may cause problems otherwise
-                        $current_pos = ftell($fh);
-                        $data        = fgets($fh);
-                        while (!feof($fh)) {
-                            if (preg_match('/^\s*$/', $data) || preg_match('/^#/', $data)) {
-                                // only empty lines or comments, continue to seek
-                                // TODO: Known bug: Wrappings for comments are okay but are treaten as
-                                //       error, since we do not honor comment mode here.
-                                //       This should be a very theoretically case, however
-                                //       i am willing to fix this if really necessary.
-                                $this->_input_line++;
-                                $current_pos = ftell($fh);
-                                $data        = fgets($fh);
-                            } else {
-                                // Data found if non emtpy line and not a comment!!
-                                // Rewind to position prior last read and stop lookahead
-                                fseek($fh, $current_pos);
-                                break;
-                            }
-                        }
-                        // now we have either the file pointer at the beginning of
-                        // a new data position or at the end of file causing feof() to return true
-
-                    } else {
-                        // build lines
-                        if (preg_match('/^version:\s(.+)$/', $data, $match)) {
-                            // version statement, set version
-                            $this->version($match[1]);
-                        } elseif (preg_match('/^\w+::?\s.+$/', $data)) {
-                            // normal attribute: add line
-                            $commentmode         = false;
-                            $this->_lines_next[] = trim($data);
-                            $datalines_read++;
-                        } elseif (preg_match('/^\s(.+)$/', $data, $matches)) {
-                            // wrapped data: unwrap if not in comment mode
-                            if (!$commentmode) {
-                                if ($datalines_read == 0) {
-                                    // first line of entry: wrapped data is illegal
-                                    $this->dropError('Net_LDAP2_LDIF error: illegal wrapping at input line '.$this->_input_line, $this->_input_line);
-                                } else {
-                                    $last                = array_pop($this->_lines_next);
-                                    $last                = $last.trim($matches[1]);
-                                    $this->_lines_next[] = $last;
-                                    $datalines_read++;
-                                }
-                            }
-                        } elseif (preg_match('/^#/', $data)) {
-                            // LDIF comments
-                            $commentmode = true;
-                        } elseif (preg_match('/^\s*$/', $data)) {
-                            // empty line but we had no data for this
-                            // entry, so just ignore this line
-                            $commentmode = false;
-                        } else {
-                            $this->dropError('Net_LDAP2_LDIF error: invalid syntax at input line '.$this->_input_line, $this->_input_line);
-                            continue;
-                        }
-
-                    }
-                }
-            }
-        }
-        return $this->_lines_next;
-    }
-
-    /**
-    * Convert an attribute and value to LDIF string representation
-    *
-    * It honors correct encoding of values according to RFC 2849.
-    * Line wrapping will occur at the configured maximum but only if
-    * the value is greater than 40 chars.
-    *
-    * @param string $attr_name  Name of the attribute
-    * @param string $attr_value Value of the attribute
-    *
-    * @access protected
-    * @return string LDIF string for that attribute and value
-    */
-    protected function convertAttribute($attr_name, $attr_value)
-    {
-        // Handle empty attribute or process
-        if (strlen($attr_value) == 0) {
-            $attr_value = " ";
-        } else {
-            $base64 = false;
-            // ASCII-chars that are NOT safe for the
-            // start and for being inside the value.
-            // These are the int values of those chars.
-            $unsafe_init = array(0, 10, 13, 32, 58, 60);
-            $unsafe      = array(0, 10, 13);
-
-            // Test for illegal init char
-            $init_ord = ord(substr($attr_value, 0, 1));
-            if ($init_ord > 127 || in_array($init_ord, $unsafe_init)) {
-                $base64 = true;
-            }
-
-            // Test for illegal content char
-            for ($i = 0; $i < strlen($attr_value); $i++) {
-                $char_ord = ord(substr($attr_value, $i, 1));
-                if ($char_ord > 127 || in_array($char_ord, $unsafe)) {
-                    $base64 = true;
-                }
-            }
-
-            // Test for ending space
-            if (substr($attr_value, -1) == ' ') {
-                $base64 = true;
-            }
-
-            // If converting is needed, do it
-            // Either we have some special chars or a matching "raw" regex
-            if ($base64 || ($this->_options['raw'] && preg_match($this->_options['raw'], $attr_name))) {
-                $attr_name .= ':';
-                $attr_value = base64_encode($attr_value);
-            }
-
-            // Lowercase attr names if requested
-            if ($this->_options['lowercase']) $attr_name = strtolower($attr_name);
-
-            // Handle line wrapping
-            if ($this->_options['wrap'] > 40 && strlen($attr_value) > $this->_options['wrap']) {
-                $attr_value = wordwrap($attr_value, $this->_options['wrap'], PHP_EOL." ", true);
-            }
-        }
-
-        return $attr_name.': '.$attr_value;
-    }
-
-    /**
-    * Convert an entries DN to LDIF string representation
-    *
-    * It honors correct encoding of values according to RFC 2849.
-    *
-    * @param string $dn UTF8-Encoded DN
-    *
-    * @access protected
-    * @return string LDIF string for that DN
-    * @todo I am not sure, if the UTF8 stuff is correctly handled right now
-    */
-    protected function convertDN($dn)
-    {
-        $base64 = false;
-        // ASCII-chars that are NOT safe for the
-        // start and for being inside the dn.
-        // These are the int values of those chars.
-        $unsafe_init = array(0, 10, 13, 32, 58, 60);
-        $unsafe      = array(0, 10, 13);
-
-        // Test for illegal init char
-        $init_ord = ord(substr($dn, 0, 1));
-        if ($init_ord >= 127 || in_array($init_ord, $unsafe_init)) {
-            $base64 = true;
-        }
-
-        // Test for illegal content char
-        for ($i = 0; $i < strlen($dn); $i++) {
-            $char = substr($dn, $i, 1);
-            if (ord($char) >= 127 || in_array($init_ord, $unsafe)) {
-                $base64 = true;
-            }
-        }
-
-        // Test for ending space
-        if (substr($dn, -1) == ' ') {
-            $base64 = true;
-        }
-
-        // if converting is needed, do it
-        return ($base64)? 'dn:: '.base64_encode($dn) : 'dn: '.$dn;
-    }
-
-    /**
-    * Writes an attribute to the filehandle
-    *
-    * @param string       $attr_name   Name of the attribute
-    * @param string|array $attr_values Single attribute value or array with attribute values
-    *
-    * @access protected
-    * @return void
-    */
-    protected function writeAttribute($attr_name, $attr_values)
-    {
-        // write out attribute content
-        if (!is_array($attr_values)) {
-            $attr_values = array($attr_values);
-        }
-        foreach ($attr_values as $attr_val) {
-            $line = $this->convertAttribute($attr_name, $attr_val).PHP_EOL;
-            $this->writeLine($line, 'Net_LDAP2_LDIF error: unable to write attribute '.$attr_name.' of entry '.$this->_entrynum);
-        }
-    }
-
-    /**
-    * Writes a DN to the filehandle
-    *
-    * @param string $dn DN to write
-    *
-    * @access protected
-    * @return void
-    */
-    protected function writeDN($dn)
-    {
-        // prepare DN
-        if ($this->_options['encode'] == 'base64') {
-            $dn = $this->convertDN($dn).PHP_EOL;
-        } elseif ($this->_options['encode'] == 'canonical') {
-            $dn = Net_LDAP2_Util::canonical_dn($dn, array('casefold' => 'none')).PHP_EOL;
-        } else {
-            $dn = $dn.PHP_EOL;
-        }
-        $this->writeLine($dn, 'Net_LDAP2_LDIF error: unable to write DN of entry '.$this->_entrynum);
-    }
-
-    /**
-    * Finishes an LDIF entry
-    *
-    * @access protected
-    * @return void
-    */
-    protected function finishEntry()
-    {
-        $this->writeLine(PHP_EOL, 'Net_LDAP2_LDIF error: unable to close entry '.$this->_entrynum);
-    }
-
-    /**
-    * Just write an arbitary line to the filehandle
-    *
-    * @param string $line  Content to write
-    * @param string $error If error occurs, drop this message
-    *
-    * @access protected
-    * @return true|false
-    */
-    protected function writeLine($line, $error = 'Net_LDAP2_LDIF error: unable to write to filehandle')
-    {
-        if (is_resource($this->handle()) && fwrite($this->handle(), $line, strlen($line)) === false) {
-            $this->dropError($error);
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    /**
-    * Optionally raises an error and pushes the error on the error cache
-    *
-    * @param string $msg  Errortext
-    * @param int    $line Line in the LDIF that caused the error
-    *
-    * @access protected
-    * @return void
-    */
-    protected function dropError($msg, $line = null)
-    {
-        $this->_error['error'] = new Net_LDAP2_Error($msg);
-        if ($line !== null) $this->_error['line'] = $line;
-
-        if ($this->_options['onerror'] == 'die') {
-            die($msg.PHP_EOL);
-        } elseif ($this->_options['onerror'] == 'warn') {
-            echo $msg.PHP_EOL;
-        }
-    }
-}
-?>
diff --git a/extlib/Net/LDAP2/RootDSE.php b/extlib/Net/LDAP2/RootDSE.php
deleted file mode 100644 (file)
index 8dc81fd..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_RootDSE interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Jan Wagner <wagner@netsols.de>
-* @copyright 2009 Jan Wagner
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: RootDSE.php 286718 2009-08-03 07:30:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Includes
-*/
-require_once 'PEAR.php';
-
-/**
-* Getting the rootDSE entry of a LDAP server
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Jan Wagner <wagner@netsols.de>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP22/
-*/
-class Net_LDAP2_RootDSE extends PEAR
-{
-    /**
-    * @access protected
-    * @var object Net_LDAP2_Entry
-    **/
-    protected $_entry;
-
-    /**
-    * Class constructor
-    *
-    * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry object of the RootDSE
-    */
-    protected function __construct(&$entry)
-    {
-        $this->_entry = $entry;
-    }
-
-    /**
-    * Fetches a RootDSE object from an LDAP connection
-    *
-    * @param Net_LDAP2 $ldap  Directory from which the RootDSE should be fetched
-    * @param array     $attrs Array of attributes to search for
-    *
-    * @access static
-    * @return Net_LDAP2_RootDSE|Net_LDAP2_Error
-    */
-    public static function fetch($ldap, $attrs = null)
-    {
-        if (!$ldap instanceof Net_LDAP2) {
-            return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!");
-        }
-
-        if (is_array($attrs) && count($attrs) > 0 ) {
-            $attributes = $attrs;
-        } else {
-            $attributes = array('vendorName',
-                                'vendorVersion',
-                                'namingContexts',
-                                'altServer',
-                                'supportedExtension',
-                                'supportedControl',
-                                'supportedSASLMechanisms',
-                                'supportedLDAPVersion',
-                                'subschemaSubentry' );
-        }
-        $result = $ldap->search('', '(objectClass=*)', array('attributes' => $attributes, 'scope' => 'base'));
-        if (self::isError($result)) {
-            return $result;
-        }
-        $entry = $result->shiftEntry();
-        if (false === $entry) {
-            return PEAR::raiseError('Could not fetch RootDSE entry');
-        }
-        $ret = new Net_LDAP2_RootDSE($entry);
-        return $ret;
-    }
-
-    /**
-    * Gets the requested attribute value
-    *
-    * Same usuage as {@link Net_LDAP2_Entry::getValue()}
-    *
-    * @param string $attr    Attribute name
-    * @param array  $options Array of options
-    *
-    * @access public
-    * @return mixed Net_LDAP2_Error object or attribute values
-    * @see Net_LDAP2_Entry::get_value()
-    */
-    public function getValue($attr = '', $options = '')
-    {
-        return $this->_entry->get_value($attr, $options);
-    }
-
-    /**
-    * Alias function of getValue() for perl-ldap interface
-    *
-    * @see getValue()
-    * @return mixed
-    */
-    public function get_value()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array( &$this, 'getValue' ), $args);
-    }
-
-    /**
-    * Determines if the extension is supported
-    *
-    * @param array $oids Array of oids to check
-    *
-    * @access public
-    * @return boolean
-    */
-    public function supportedExtension($oids)
-    {
-        return $this->checkAttr($oids, 'supportedExtension');
-    }
-
-    /**
-    * Alias function of supportedExtension() for perl-ldap interface
-    *
-    * @see supportedExtension()
-    * @return boolean
-    */
-    public function supported_extension()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array( &$this, 'supportedExtension'), $args);
-    }
-
-    /**
-    * Determines if the version is supported
-    *
-    * @param array $versions Versions to check
-    *
-    * @access public
-    * @return boolean
-    */
-    public function supportedVersion($versions)
-    {
-        return $this->checkAttr($versions, 'supportedLDAPVersion');
-    }
-
-    /**
-    * Alias function of supportedVersion() for perl-ldap interface
-    *
-    * @see supportedVersion()
-    * @return boolean
-    */
-    public function supported_version()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array(&$this, 'supportedVersion'), $args);
-    }
-
-    /**
-    * Determines if the control is supported
-    *
-    * @param array $oids Control oids to check
-    *
-    * @access public
-    * @return boolean
-    */
-    public function supportedControl($oids)
-    {
-        return $this->checkAttr($oids, 'supportedControl');
-    }
-
-    /**
-    * Alias function of supportedControl() for perl-ldap interface
-    *
-    * @see supportedControl()
-    * @return boolean
-    */
-    public function supported_control()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array(&$this, 'supportedControl' ), $args);
-    }
-
-    /**
-    * Determines if the sasl mechanism is supported
-    *
-    * @param array $mechlist SASL mechanisms to check
-    *
-    * @access public
-    * @return boolean
-    */
-    public function supportedSASLMechanism($mechlist)
-    {
-        return $this->checkAttr($mechlist, 'supportedSASLMechanisms');
-    }
-
-    /**
-    * Alias function of supportedSASLMechanism() for perl-ldap interface
-    *
-    * @see supportedSASLMechanism()
-    * @return boolean
-    */
-    public function supported_sasl_mechanism()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array(&$this, 'supportedSASLMechanism'), $args);
-    }
-
-    /**
-    * Checks for existance of value in attribute
-    *
-    * @param array  $values values to check
-    * @param string $attr   attribute name
-    *
-    * @access protected
-    * @return boolean
-    */
-    protected function checkAttr($values, $attr)
-    {
-        if (!is_array($values)) $values = array($values);
-
-        foreach ($values as $value) {
-            if (!@in_array($value, $this->get_value($attr, 'all'))) {
-                return false;
-            }
-        }
-        return true;
-    }
-}
-
-?>
diff --git a/extlib/Net/LDAP2/Schema.php b/extlib/Net/LDAP2/Schema.php
deleted file mode 100644 (file)
index b590eab..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_Schema interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Jan Wagner <wagner@netsols.de>
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Jan Wagner, Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: Schema.php 286718 2009-08-03 07:30:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-* @todo see the comment at the end of the file
-*/
-
-/**
-* Includes
-*/
-require_once 'PEAR.php';
-
-/**
-* Syntax definitions
-*
-* Please don't forget to add binary attributes to isBinary() below
-* to support proper value fetching from Net_LDAP2_Entry
-*/
-define('NET_LDAP2_SYNTAX_BOOLEAN',            '1.3.6.1.4.1.1466.115.121.1.7');
-define('NET_LDAP2_SYNTAX_DIRECTORY_STRING',   '1.3.6.1.4.1.1466.115.121.1.15');
-define('NET_LDAP2_SYNTAX_DISTINGUISHED_NAME', '1.3.6.1.4.1.1466.115.121.1.12');
-define('NET_LDAP2_SYNTAX_INTEGER',            '1.3.6.1.4.1.1466.115.121.1.27');
-define('NET_LDAP2_SYNTAX_JPEG',               '1.3.6.1.4.1.1466.115.121.1.28');
-define('NET_LDAP2_SYNTAX_NUMERIC_STRING',     '1.3.6.1.4.1.1466.115.121.1.36');
-define('NET_LDAP2_SYNTAX_OID',                '1.3.6.1.4.1.1466.115.121.1.38');
-define('NET_LDAP2_SYNTAX_OCTET_STRING',       '1.3.6.1.4.1.1466.115.121.1.40');
-
-/**
-* Load an LDAP Schema and provide information
-*
-* This class takes a Subschema entry, parses this information
-* and makes it available in an array. Most of the code has been
-* inspired by perl-ldap( http://perl-ldap.sourceforge.net).
-* You will find portions of their implementation in here.
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Jan Wagner <wagner@netsols.de>
-* @author   Benedikt Hallinger <beni@php.net>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP22/
-*/
-class Net_LDAP2_Schema extends PEAR
-{
-    /**
-    * Map of entry types to ldap attributes of subschema entry
-    *
-    * @access public
-    * @var array
-    */
-    public $types = array(
-            'attribute'        => 'attributeTypes',
-            'ditcontentrule'   => 'dITContentRules',
-            'ditstructurerule' => 'dITStructureRules',
-            'matchingrule'     => 'matchingRules',
-            'matchingruleuse'  => 'matchingRuleUse',
-            'nameform'         => 'nameForms',
-            'objectclass'      => 'objectClasses',
-            'syntax'           => 'ldapSyntaxes'
-        );
-
-    /**
-    * Array of entries belonging to this type
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_attributeTypes    = array();
-    protected $_matchingRules     = array();
-    protected $_matchingRuleUse   = array();
-    protected $_ldapSyntaxes      = array();
-    protected $_objectClasses     = array();
-    protected $_dITContentRules   = array();
-    protected $_dITStructureRules = array();
-    protected $_nameForms         = array();
-
-
-    /**
-    * hash of all fetched oids
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_oids = array();
-
-    /**
-    * Tells if the schema is initialized
-    *
-    * @access protected
-    * @var boolean
-    * @see parse(), get()
-    */
-    protected $_initialized = false;
-
-
-    /**
-    * Constructor of the class
-    *
-    * @access protected
-    */
-    protected function __construct()
-    {
-        $this->PEAR('Net_LDAP2_Error'); // default error class
-    }
-
-    /**
-    * Fetch the Schema from an LDAP connection
-    *
-    * @param Net_LDAP2 $ldap LDAP connection
-    * @param string    $dn   (optional) Subschema entry dn
-    *
-    * @access public
-    * @return Net_LDAP2_Schema|NET_LDAP2_Error
-    */
-    public function fetch($ldap, $dn = null)
-    {
-        if (!$ldap instanceof Net_LDAP2) {
-            return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!");
-        }
-
-        $schema_o = new Net_LDAP2_Schema();
-
-        if (is_null($dn)) {
-            // get the subschema entry via root dse
-            $dse = $ldap->rootDSE(array('subschemaSubentry'));
-            if (false == Net_LDAP2::isError($dse)) {
-                $base = $dse->getValue('subschemaSubentry', 'single');
-                if (!Net_LDAP2::isError($base)) {
-                    $dn = $base;
-                }
-            }
-        }
-
-        // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that incorrectly
-        // call this entry subSchemaSubentry instead of subschemaSubentry.
-        // Note the correct case/spelling as per RFC 2251.
-        if (is_null($dn)) {
-            // get the subschema entry via root dse
-            $dse = $ldap->rootDSE(array('subSchemaSubentry'));
-            if (false == Net_LDAP2::isError($dse)) {
-                $base = $dse->getValue('subSchemaSubentry', 'single');
-                if (!Net_LDAP2::isError($base)) {
-                    $dn = $base;
-                }
-            }
-        }
-
-        // Final fallback case where there is no subschemaSubentry attribute
-        // in the root DSE (this is a bug for an LDAP v3 server so report this
-        // to your LDAP vendor if you get this far).
-        if (is_null($dn)) {
-            $dn = 'cn=Subschema';
-        }
-
-        // fetch the subschema entry
-        $result = $ldap->search($dn, '(objectClass=*)',
-                                array('attributes' => array_values($schema_o->types),
-                                        'scope' => 'base'));
-        if (Net_LDAP2::isError($result)) {
-            return $result;
-        }
-
-        $entry = $result->shiftEntry();
-        if (!$entry instanceof Net_LDAP2_Entry) {
-            return PEAR::raiseError('Could not fetch Subschema entry');
-        }
-
-        $schema_o->parse($entry);
-        return $schema_o;
-    }
-
-    /**
-    * Return a hash of entries for the given type
-    *
-    * Returns a hash of entry for th givene type. Types may be:
-    * objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules,
-    * matchingruleuses, nameforms, syntaxes
-    *
-    * @param string $type Type to fetch
-    *
-    * @access public
-    * @return array|Net_LDAP2_Error Array or Net_LDAP2_Error
-    */
-    public function &getAll($type)
-    {
-        $map = array('objectclasses'     => &$this->_objectClasses,
-                     'attributes'        => &$this->_attributeTypes,
-                     'ditcontentrules'   => &$this->_dITContentRules,
-                     'ditstructurerules' => &$this->_dITStructureRules,
-                     'matchingrules'     => &$this->_matchingRules,
-                     'matchingruleuses'  => &$this->_matchingRuleUse,
-                     'nameforms'         => &$this->_nameForms,
-                     'syntaxes'          => &$this->_ldapSyntaxes );
-
-        $key = strtolower($type);
-        $ret = ((key_exists($key, $map)) ? $map[$key] : PEAR::raiseError("Unknown type $type"));
-        return $ret;
-    }
-
-    /**
-    * Return a specific entry
-    *
-    * @param string $type Type of name
-    * @param string $name Name or OID to fetch
-    *
-    * @access public
-    * @return mixed Entry or Net_LDAP2_Error
-    */
-    public function &get($type, $name)
-    {
-        if ($this->_initialized) {
-            $type = strtolower($type);
-            if (false == key_exists($type, $this->types)) {
-                return PEAR::raiseError("No such type $type");
-            }
-
-            $name     = strtolower($name);
-            $type_var = &$this->{'_' . $this->types[$type]};
-
-            if (key_exists($name, $type_var)) {
-                return $type_var[$name];
-            } elseif (key_exists($name, $this->_oids) && $this->_oids[$name]['type'] == $type) {
-                return $this->_oids[$name];
-            } else {
-                return PEAR::raiseError("Could not find $type $name");
-            }
-        } else {
-            $return = null;
-            return $return;
-        }
-    }
-
-
-    /**
-    * Fetches attributes that MAY be present in the given objectclass
-    *
-    * @param string $oc Name or OID of objectclass
-    *
-    * @access public
-    * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error
-    */
-    public function may($oc)
-    {
-        return $this->_getAttr($oc, 'may');
-    }
-
-    /**
-    * Fetches attributes that MUST be present in the given objectclass
-    *
-    * @param string $oc Name or OID of objectclass
-    *
-    * @access public
-    * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error
-    */
-    public function must($oc)
-    {
-        return $this->_getAttr($oc, 'must');
-    }
-
-    /**
-    * Fetches the given attribute from the given objectclass
-    *
-    * @param string $oc   Name or OID of objectclass
-    * @param string $attr Name of attribute to fetch
-    *
-    * @access protected
-    * @return array|Net_LDAP2_Error The attribute or Net_LDAP2_Error
-    */
-    protected function _getAttr($oc, $attr)
-    {
-        $oc = strtolower($oc);
-        if (key_exists($oc, $this->_objectClasses) && key_exists($attr, $this->_objectClasses[$oc])) {
-            return $this->_objectClasses[$oc][$attr];
-        } elseif (key_exists($oc, $this->_oids) &&
-                $this->_oids[$oc]['type'] == 'objectclass' &&
-                key_exists($attr, $this->_oids[$oc])) {
-            return $this->_oids[$oc][$attr];
-        } else {
-            return PEAR::raiseError("Could not find $attr attributes for $oc ");
-        }
-    }
-
-    /**
-    * Returns the name(s) of the immediate superclass(es)
-    *
-    * @param string $oc Name or OID of objectclass
-    *
-    * @access public
-    * @return array|Net_LDAP2_Error  Array of names or Net_LDAP2_Error
-    */
-    public function superclass($oc)
-    {
-        $o = $this->get('objectclass', $oc);
-        if (Net_LDAP2::isError($o)) {
-            return $o;
-        }
-        return (key_exists('sup', $o) ? $o['sup'] : array());
-    }
-
-    /**
-    * Parses the schema of the given Subschema entry
-    *
-    * @param Net_LDAP2_Entry &$entry Subschema entry
-    *
-    * @access public
-    * @return void
-    */
-    public function parse(&$entry)
-    {
-        foreach ($this->types as $type => $attr) {
-            // initialize map type to entry
-            $type_var          = '_' . $attr;
-            $this->{$type_var} = array();
-
-            // get values for this type
-            if ($entry->exists($attr)) {
-                $values = $entry->getValue($attr);
-                if (is_array($values)) {
-                    foreach ($values as $value) {
-
-                        unset($schema_entry); // this was a real mess without it
-
-                        // get the schema entry
-                        $schema_entry = $this->_parse_entry($value);
-
-                        // set the type
-                        $schema_entry['type'] = $type;
-
-                        // save a ref in $_oids
-                        $this->_oids[$schema_entry['oid']] = &$schema_entry;
-
-                        // save refs for all names in type map
-                        $names = $schema_entry['aliases'];
-                        array_push($names, $schema_entry['name']);
-                        foreach ($names as $name) {
-                            $this->{$type_var}[strtolower($name)] = &$schema_entry;
-                        }
-                    }
-                }
-            }
-        }
-        $this->_initialized = true;
-    }
-
-    /**
-    * Parses an attribute value into a schema entry
-    *
-    * @param string $value Attribute value
-    *
-    * @access protected
-    * @return array|false Schema entry array or false
-    */
-    protected function &_parse_entry($value)
-    {
-        // tokens that have no value associated
-        $noValue = array('single-value',
-                         'obsolete',
-                         'collective',
-                         'no-user-modification',
-                         'abstract',
-                         'structural',
-                         'auxiliary');
-
-        // tokens that can have multiple values
-        $multiValue = array('must', 'may', 'sup');
-
-        $schema_entry = array('aliases' => array()); // initilization
-
-        $tokens = $this->_tokenize($value); // get an array of tokens
-
-        // remove surrounding brackets
-        if ($tokens[0] == '(') array_shift($tokens);
-        if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); // -1 doesnt work on arrays :-(
-
-        $schema_entry['oid'] = array_shift($tokens); // first token is the oid
-
-        // cycle over the tokens until none are left
-        while (count($tokens) > 0) {
-            $token = strtolower(array_shift($tokens));
-            if (in_array($token, $noValue)) {
-                $schema_entry[$token] = 1; // single value token
-            } else {
-                // this one follows a string or a list if it is multivalued
-                if (($schema_entry[$token] = array_shift($tokens)) == '(') {
-                    // this creates the list of values and cycles through the tokens
-                    // until the end of the list is reached ')'
-                    $schema_entry[$token] = array();
-                    while ($tmp = array_shift($tokens)) {
-                        if ($tmp == ')') break;
-                        if ($tmp != '$') array_push($schema_entry[$token], $tmp);
-                    }
-                }
-                // create a array if the value should be multivalued but was not
-                if (in_array($token, $multiValue) && !is_array($schema_entry[$token])) {
-                    $schema_entry[$token] = array($schema_entry[$token]);
-                }
-            }
-        }
-        // get max length from syntax
-        if (key_exists('syntax', $schema_entry)) {
-            if (preg_match('/{(\d+)}/', $schema_entry['syntax'], $matches)) {
-                $schema_entry['max_length'] = $matches[1];
-            }
-        }
-        // force a name
-        if (empty($schema_entry['name'])) {
-            $schema_entry['name'] = $schema_entry['oid'];
-        }
-        // make one name the default and put the other ones into aliases
-        if (is_array($schema_entry['name'])) {
-            $aliases                 = $schema_entry['name'];
-            $schema_entry['name']    = array_shift($aliases);
-            $schema_entry['aliases'] = $aliases;
-        }
-        return $schema_entry;
-    }
-
-    /**
-    * Tokenizes the given value into an array of tokens
-    *
-    * @param string $value String to parse
-    *
-    * @access protected
-    * @return array Array of tokens
-    */
-    protected function _tokenize($value)
-    {
-        $tokens  = array();       // array of tokens
-        $matches = array();       // matches[0] full pattern match, [1,2,3] subpatterns
-
-        // this one is taken from perl-ldap, modified for php
-        $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x";
-
-        /**
-         * This one matches one big pattern wherin only one of the three subpatterns matched
-         * We are interested in the subpatterns that matched. If it matched its value will be
-         * non-empty and so it is a token. Tokens may be round brackets, a string, or a string
-         * enclosed by '
-         */
-        preg_match_all($pattern, $value, $matches);
-
-        for ($i = 0; $i < count($matches[0]); $i++) {     // number of tokens (full pattern match)
-            for ($j = 1; $j < 4; $j++) {                  // each subpattern
-                if (null != trim($matches[$j][$i])) {     // pattern match in this subpattern
-                    $tokens[$i] = trim($matches[$j][$i]); // this is the token
-                }
-            }
-        }
-        return $tokens;
-    }
-
-    /**
-    * Returns wether a attribute syntax is binary or not
-    *
-    * This method gets used by Net_LDAP2_Entry to decide which
-    * PHP function needs to be used to fetch the value in the
-    * proper format (e.g. binary or string)
-    *
-    * @param string $attribute The name of the attribute (eg.: 'sn')
-    *
-    * @access public
-    * @return boolean
-    */
-    public function isBinary($attribute)
-    {
-        $return = false; // default to false
-
-        // This list contains all syntax that should be treaten as
-        // containing binary values
-        // The Syntax Definitons go into constants at the top of this page
-        $syntax_binary = array(
-                           NET_LDAP2_SYNTAX_OCTET_STRING,
-                           NET_LDAP2_SYNTAX_JPEG
-                         );
-
-        // Check Syntax
-        $attr_s = $this->get('attribute', $attribute);
-        if (Net_LDAP2::isError($attr_s)) {
-            // Attribute not found in schema
-            $return = false; // consider attr not binary
-        } elseif (isset($attr_s['syntax']) && in_array($attr_s['syntax'], $syntax_binary)) {
-            // Syntax is defined as binary in schema
-            $return = true;
-        } else {
-            // Syntax not defined as binary, or not found
-            // if attribute is a subtype, check superior attribute syntaxes
-            if (isset($attr_s['sup'])) {
-                foreach ($attr_s['sup'] as $superattr) {
-                    $return = $this->isBinary($superattr);
-                    if ($return) {
-                        break; // stop checking parents since we are binary
-                    }
-                }
-            }
-        }
-
-        return $return;
-    }
-
-    // [TODO] add method that allows us to see to which objectclasses a certain attribute belongs to
-    // it should return the result structured, e.g. sorted in "may" and "must". Optionally it should
-    // be able to return it just "flat", e.g. array_merge()d.
-    // We could use get_all() to achieve this easily, i think
-}
-?>
diff --git a/extlib/Net/LDAP2/SchemaCache.interface.php b/extlib/Net/LDAP2/SchemaCache.interface.php
deleted file mode 100644 (file)
index e0c3094..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_SchemaCache interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: SchemaCache.interface.php 286718 2009-08-03 07:30:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Interface describing a custom schema cache object
-*
-* To implement a custom schema cache, one must implement this interface and
-* pass the instanciated object to Net_LDAP2s registerSchemaCache() method.
-*/
-interface Net_LDAP2_SchemaCache
-{
-    /**
-    * Return the schema object from the cache
-    *
-    * Net_LDAP2 will consider anything returned invalid, except
-    * a valid Net_LDAP2_Schema object.
-    * In case you return a Net_LDAP2_Error, this error will be routed
-    * to the return of the $ldap->schema() call.
-    * If you return something else, Net_LDAP2 will
-    * fetch a fresh Schema object from the LDAP server.
-    *
-    * You may want to implement a cache aging mechanism here too.
-    *
-    * @return Net_LDAP2_Schema|Net_LDAP2_Error|false
-    */
-    public function loadSchema();
-
-    /**
-    * Store a schema object in the cache
-    *
-    * This method will be called, if Net_LDAP2 has fetched a fresh
-    * schema object from LDAP and wants to init or refresh the cache.
-    *
-    * In case of errors you may return a Net_LDAP2_Error which will
-    * be routet to the client.
-    * Note that doing this prevents, that the schema object fetched from LDAP
-    * will be given back to the client, so only return errors if storing
-    * of the cache is something crucial (e.g. for doing something else with it).
-    * Normaly you dont want to give back errors in which case Net_LDAP2 needs to
-    * fetch the schema once per script run and instead use the error
-    * returned from loadSchema().
-    *
-    * @return true|Net_LDAP2_Error
-    */
-    public function storeSchema($schema);
-}
diff --git a/extlib/Net/LDAP2/Search.php b/extlib/Net/LDAP2/Search.php
deleted file mode 100644 (file)
index de4fde1..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_Search interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Tarjej Huse <tarjei@bergfald.no>
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Tarjej Huse, Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: Search.php 286718 2009-08-03 07:30:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Includes
-*/
-require_once 'PEAR.php';
-
-/**
-* Result set of an LDAP search
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Tarjej Huse <tarjei@bergfald.no>
-* @author   Benedikt Hallinger <beni@php.net>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP22/
-*/
-class Net_LDAP2_Search extends PEAR implements Iterator
-{
-    /**
-    * Search result identifier
-    *
-    * @access protected
-    * @var resource
-    */
-    protected $_search;
-
-    /**
-    * LDAP resource link
-    *
-    * @access protected
-    * @var resource
-    */
-    protected $_link;
-
-    /**
-    * Net_LDAP2 object
-    *
-    * A reference of the Net_LDAP2 object for passing to Net_LDAP2_Entry
-    *
-    * @access protected
-    * @var object Net_LDAP2
-    */
-    protected $_ldap;
-
-    /**
-    * Result entry identifier
-    *
-    * @access protected
-    * @var resource
-    */
-    protected $_entry = null;
-
-    /**
-    * The errorcode the search got
-    *
-    * Some errorcodes might be of interest, but might not be best handled as errors.
-    * examples: 4 - LDAP_SIZELIMIT_EXCEEDED - indicates a huge search.
-    *               Incomplete results are returned. If you just want to check if there's anything in the search.
-    *               than this is a point to handle.
-    *           32 - no such object - search here returns a count of 0.
-    *
-    * @access protected
-    * @var int
-    */
-    protected $_errorCode = 0; // if not set - sucess!
-
-    /**
-    * Cache for all entries already fetched from iterator interface
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_iteratorCache = array();
-
-    /**
-    * What attributes we searched for
-    *
-    * The $attributes array contains the names of the searched attributes and gets
-    * passed from $Net_LDAP2->search() so the Net_LDAP2_Search object can tell
-    * what attributes was searched for ({@link searchedAttrs())
-    *
-    * This variable gets set from the constructor and returned
-    * from {@link searchedAttrs()}
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_searchedAttrs = array();
-
-    /**
-    * Cache variable for storing entries fetched internally
-    *
-    * This currently is only used by {@link pop_entry()}
-    *
-    * @access protected
-    * @var array
-    */
-    protected $_entry_cache = false;
-
-    /**
-    * Constructor
-    *
-    * @param resource           &$search    Search result identifier
-    * @param Net_LDAP2|resource &$ldap      Net_LDAP2 object or just a LDAP-Link resource
-    * @param array              $attributes (optional) Array with searched attribute names. (see {@link $_searchedAttrs})
-    *
-    * @access public
-    */
-    public function __construct(&$search, &$ldap, $attributes = array())
-    {
-        $this->PEAR('Net_LDAP2_Error');
-
-        $this->setSearch($search);
-
-        if ($ldap instanceof Net_LDAP2) {
-            $this->_ldap =& $ldap;
-            $this->setLink($this->_ldap->getLink());
-        } else {
-            $this->setLink($ldap);
-        }
-
-        $this->_errorCode = @ldap_errno($this->_link);
-
-        if (is_array($attributes) && !empty($attributes)) {
-            $this->_searchedAttrs = $attributes;
-        }
-    }
-
-    /**
-    * Returns an array of entry objects
-    *
-    * @return array Array of entry objects.
-    */
-    public function entries()
-    {
-        $entries = array();
-
-        while ($entry = $this->shiftEntry()) {
-            $entries[] = $entry;
-        }
-
-        return $entries;
-    }
-
-    /**
-    * Get the next entry in the searchresult.
-    *
-    * This will return a valid Net_LDAP2_Entry object or false, so
-    * you can use this method to easily iterate over the entries inside
-    * a while loop.
-    *
-    * @return Net_LDAP2_Entry|false  Reference to Net_LDAP2_Entry object or false
-    */
-    public function &shiftEntry()
-    {
-        if ($this->count() == 0 ) {
-            $false = false;
-            return $false;
-        }
-
-        if (is_null($this->_entry)) {
-            $this->_entry = @ldap_first_entry($this->_link, $this->_search);
-            $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
-            if ($entry instanceof Net_LDAP2_Error) $entry = false;
-        } else {
-            if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) {
-                $false = false;
-                return $false;
-            }
-            $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
-            if ($entry instanceof Net_LDAP2_Error) $entry = false;
-        }
-        return $entry;
-    }
-
-    /**
-    * Alias function of shiftEntry() for perl-ldap interface
-    *
-    * @see shiftEntry()
-    * @return Net_LDAP2_Entry|false
-    */
-    public function shift_entry()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array( &$this, 'shiftEntry' ), $args);
-    }
-
-    /**
-    * Retrieve the next entry in the searchresult, but starting from last entry
-    *
-    * This is the opposite to {@link shiftEntry()} and is also very useful
-    * to be used inside a while loop.
-    *
-    * @return Net_LDAP2_Entry|false
-    */
-    public function popEntry()
-    {
-        if (false === $this->_entry_cache) {
-            // fetch entries into cache if not done so far
-            $this->_entry_cache = $this->entries();
-        }
-
-        $return = array_pop($this->_entry_cache);
-        return (null === $return)? false : $return;
-    }
-
-    /**
-    * Alias function of popEntry() for perl-ldap interface
-    *
-    * @see popEntry()
-    * @return Net_LDAP2_Entry|false
-    */
-    public function pop_entry()
-    {
-        $args = func_get_args();
-        return call_user_func_array(array( &$this, 'popEntry' ), $args);
-    }
-
-    /**
-    * Return entries sorted as array
-    *
-    * This returns a array with sorted entries and the values.
-    * Sorting is done with PHPs {@link array_multisort()}.
-    * This method relies on {@link as_struct()} to fetch the raw data of the entries.
-    *
-    * Please note that attribute names are case sensitive!
-    *
-    * Usage example:
-    * <code>
-    *   // to sort entries first by location, then by surename, but descending:
-    *   $entries = $search->sorted_as_struct(array('locality','sn'), SORT_DESC);
-    * </code>
-    *
-    * @param array $attrs Array of attribute names to sort; order from left to right.
-    * @param int   $order Ordering direction, either constant SORT_ASC or SORT_DESC
-    *
-    * @return array|Net_LDAP2_Error   Array with sorted entries or error
-    * @todo what about server side sorting as specified in http://www.ietf.org/rfc/rfc2891.txt?
-    */
-    public function sorted_as_struct($attrs = array('cn'), $order = SORT_ASC)
-    {
-        /*
-        * Old Code, suitable and fast for single valued sorting
-        * This code should be used if we know that single valued sorting is desired,
-        * but we need some method to get that knowledge...
-        */
-        /*
-        $attrs = array_reverse($attrs);
-        foreach ($attrs as $attribute) {
-            if (!ldap_sort($this->_link, $this->_search, $attribute)){
-                $this->raiseError("Sorting failed for Attribute " . $attribute);
-            }
-        }
-
-        $results = ldap_get_entries($this->_link, $this->_search);
-
-        unset($results['count']); //for tidier output
-        if ($order) {
-            return array_reverse($results);
-        } else {
-            return $results;
-        }*/
-
-        /*
-        * New code: complete "client side" sorting
-        */
-        // first some parameterchecks
-        if (!is_array($attrs)) {
-            return PEAR::raiseError("Sorting failed: Parameterlist must be an array!");
-        }
-        if ($order != SORT_ASC && $order != SORT_DESC) {
-            return PEAR::raiseError("Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)");
-        }
-
-        // fetch the entries data
-        $entries = $this->as_struct();
-
-        // now sort each entries attribute values
-        // this is neccessary because later we can only sort by one value,
-        // so we need the highest or lowest attribute now, depending on the
-        // selected ordering for that specific attribute
-        foreach ($entries as $dn => $entry) {
-            foreach ($entry as $attr_name => $attr_values) {
-                sort($entries[$dn][$attr_name]);
-                if ($order == SORT_DESC) {
-                    array_reverse($entries[$dn][$attr_name]);
-                }
-            }
-        }
-
-        // reformat entrys array for later use with array_multisort()
-        $to_sort = array(); // <- will be a numeric array similar to ldap_get_entries
-        foreach ($entries as $dn => $entry_attr) {
-            $row       = array();
-            $row['dn'] = $dn;
-            foreach ($entry_attr as $attr_name => $attr_values) {
-                $row[$attr_name] = $attr_values;
-            }
-            $to_sort[] = $row;
-        }
-
-        // Build columns for array_multisort()
-        // each requested attribute is one row
-        $columns = array();
-        foreach ($attrs as $attr_name) {
-            foreach ($to_sort as $key => $row) {
-                $columns[$attr_name][$key] =& $to_sort[$key][$attr_name][0];
-            }
-        }
-
-        // sort the colums with array_multisort, if there is something
-        // to sort and if we have requested sort columns
-        if (!empty($to_sort) && !empty($columns)) {
-            $sort_params = '';
-            foreach ($attrs as $attr_name) {
-                $sort_params .= '$columns[\''.$attr_name.'\'], '.$order.', ';
-            }
-            eval("array_multisort($sort_params \$to_sort);"); // perform sorting
-        }
-
-        return $to_sort;
-    }
-
-    /**
-    * Return entries sorted as objects
-    *
-    * This returns a array with sorted Net_LDAP2_Entry objects.
-    * The sorting is actually done with {@link sorted_as_struct()}.
-    *
-    * Please note that attribute names are case sensitive!
-    * Also note, that it is (depending on server capabilitys) possible to let
-    * the server sort your results. This happens through search controls
-    * and is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt}
-    *
-    * Usage example:
-    * <code>
-    *   // to sort entries first by location, then by surename, but descending:
-    *   $entries = $search->sorted(array('locality','sn'), SORT_DESC);
-    * </code>
-    *
-    * @param array $attrs Array of sort attributes to sort; order from left to right.
-    * @param int   $order Ordering direction, either constant SORT_ASC or SORT_DESC
-    *
-    * @return array|Net_LDAP2_Error   Array with sorted Net_LDAP2_Entries or error
-    * @todo Entry object construction could be faster. Maybe we could use one of the factorys instead of fetching the entry again
-    */
-    public function sorted($attrs = array('cn'), $order = SORT_ASC)
-    {
-        $return = array();
-        $sorted = $this->sorted_as_struct($attrs, $order);
-        if (PEAR::isError($sorted)) {
-            return $sorted;
-        }
-        foreach ($sorted as $key => $row) {
-            $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttrs());
-            if (!PEAR::isError($entry)) {
-                array_push($return, $entry);
-            } else {
-                return $entry;
-            }
-        }
-        return $return;
-    }
-
-    /**
-    * Return entries as array
-    *
-    * This method returns the entries and the selected attributes values as
-    * array.
-    * The first array level contains all found entries where the keys are the
-    * DNs of the entries. The second level arrays contian the entries attributes
-    * such that the keys is the lowercased name of the attribute and the values
-    * are stored in another indexed array. Note that the attribute values are stored
-    * in an array even if there is no or just one value.
-    *
-    * The array has the following structure:
-    * <code>
-    * $return = array(
-    *           'cn=foo,dc=example,dc=com' => array(
-    *                                                'sn'       => array('foo'),
-    *                                                'multival' => array('val1', 'val2', 'valN')
-    *                                             )
-    *           'cn=bar,dc=example,dc=com' => array(
-    *                                                'sn'       => array('bar'),
-    *                                                'multival' => array('val1', 'valN')
-    *                                             )
-    *           )
-    * </code>
-    *
-    * @return array      associative result array as described above
-    */
-    public function as_struct()
-    {
-        $return  = array();
-        $entries = $this->entries();
-        foreach ($entries as $entry) {
-            $attrs            = array();
-            $entry_attributes = $entry->attributes();
-            foreach ($entry_attributes as $attr_name) {
-                $attr_values = $entry->getValue($attr_name, 'all');
-                if (!is_array($attr_values)) {
-                    $attr_values = array($attr_values);
-                }
-                $attrs[$attr_name] = $attr_values;
-            }
-            $return[$entry->dn()] = $attrs;
-        }
-        return $return;
-    }
-
-    /**
-    * Set the search objects resource link
-    *
-    * @param resource &$search Search result identifier
-    *
-    * @access public
-    * @return void
-    */
-    public function setSearch(&$search)
-    {
-        $this->_search = $search;
-    }
-
-    /**
-    * Set the ldap ressource link
-    *
-    * @param resource &$link Link identifier
-    *
-    * @access public
-    * @return void
-    */
-    public function setLink(&$link)
-    {
-        $this->_link = $link;
-    }
-
-    /**
-    * Returns the number of entries in the searchresult
-    *
-    * @return int Number of entries in search.
-    */
-    public function count()
-    {
-        // this catches the situation where OL returned errno 32 = no such object!
-        if (!$this->_search) {
-            return 0;
-        }
-        return @ldap_count_entries($this->_link, $this->_search);
-    }
-
-    /**
-    * Get the errorcode the object got in its search.
-    *
-    * @return int The ldap error number.
-    */
-    public function getErrorCode()
-    {
-        return $this->_errorCode;
-    }
-
-    /**
-    * Destructor
-    *
-    * @access protected
-    */
-    public function _Net_LDAP2_Search()
-    {
-        @ldap_free_result($this->_search);
-    }
-
-    /**
-    * Closes search result
-    *
-    * @return void
-    */
-    public function done()
-    {
-        $this->_Net_LDAP2_Search();
-    }
-
-    /**
-    * Return the attribute names this search selected
-    *
-    * @return array
-    * @see $_searchedAttrs
-    * @access protected
-    */
-    protected function searchedAttrs()
-    {
-        return $this->_searchedAttrs;
-    }
-
-    /**
-    * Tells if this search exceeds a sizelimit
-    *
-    * @return boolean
-    */
-    public function sizeLimitExceeded()
-    {
-        return ($this->getErrorCode() == 4);
-    }
-
-
-    /*
-    * SPL Iterator interface methods.
-    * This interface allows to use Net_LDAP2_Search
-    * objects directly inside a foreach loop!
-    */
-    /**
-    * SPL Iterator interface: Return the current element.
-    *
-    * The SPL Iterator interface allows you to fetch entries inside
-    * a foreach() loop: <code>foreach ($search as $dn => $entry) { ...</code>
-    *
-    * Of course, you may call {@link current()}, {@link key()}, {@link next()},
-    * {@link rewind()} and {@link valid()} yourself.
-    *
-    * If the search throwed an error, it returns false.
-    * False is also returned, if the end is reached
-    * In case no call to next() was made, we will issue one,
-    * thus returning the first entry.
-    *
-    * @return Net_LDAP2_Entry|false
-    */
-    public function current()
-    {
-        if (count($this->_iteratorCache) == 0) {
-            $this->next();
-            reset($this->_iteratorCache);
-        }
-        $entry = current($this->_iteratorCache);
-        return ($entry instanceof Net_LDAP2_Entry)? $entry : false;
-    }
-
-    /**
-    * SPL Iterator interface: Return the identifying key (DN) of the current entry.
-    *
-    * @see current()
-    * @return string|false DN of the current entry; false in case no entry is returned by current()
-    */
-    public function key()
-    {
-        $entry = $this->current();
-        return ($entry instanceof Net_LDAP2_Entry)? $entry->dn() :false;
-    }
-
-    /**
-    * SPL Iterator interface: Move forward to next entry.
-    *
-    * After a call to {@link next()}, {@link current()} will return
-    * the next entry in the result set.
-    *
-    * @see current()
-    * @return void
-    */
-    public function next()
-    {
-        // fetch next entry.
-        // if we have no entrys anymore, we add false (which is
-        // returned by shiftEntry()) so current() will complain.
-        if (count($this->_iteratorCache) - 1 <= $this->count()) {
-            $this->_iteratorCache[] = $this->shiftEntry();
-        }
-
-        // move on array pointer to current element.
-        // even if we have added all entries, this will
-        // ensure proper operation in case we rewind()
-        next($this->_iteratorCache);
-    }
-
-    /**
-    * SPL Iterator interface:  Check if there is a current element after calls to {@link rewind()} or {@link next()}.
-    *
-    * Used to check if we've iterated to the end of the collection.
-    *
-    * @see current()
-    * @return boolean FALSE if there's nothing more to iterate over
-    */
-    public function valid()
-    {
-        return ($this->current() instanceof Net_LDAP2_Entry);
-    }
-
-    /**
-    * SPL Iterator interface: Rewind the Iterator to the first element.
-    *
-    * After rewinding, {@link current()} will return the first entry in the result set.
-    *
-    * @see current()
-    * @return void
-    */
-    public function rewind()
-    {
-        reset($this->_iteratorCache);
-    }
-}
-
-?>
diff --git a/extlib/Net/LDAP2/SimpleFileSchemaCache.php b/extlib/Net/LDAP2/SimpleFileSchemaCache.php
deleted file mode 100644 (file)
index 8019654..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the example simple file based Schema Caching class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: SimpleFileSchemaCache.php 286718 2009-08-03 07:30:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* A simple file based schema cacher with cache aging.
-*
-* Once the cache is too old, the loadSchema() method will return false, so
-* Net_LDAP2 will fetch a fresh object from the LDAP server that will
-* overwrite the current (outdated) old cache.
-*/
-class Net_LDAP2_SimpleFileSchemaCache implements Net_LDAP2_SchemaCache
-{
-    /**
-    * Internal config of this cache
-    *
-    * @see Net_LDAP2_SimpleFileSchemaCache()
-    * @var array
-    */
-    protected $config = array(
-        'path'    => '/tmp/Net_LDAP_Schema.cache',
-        'max_age' => 1200
-    );
-
-    /**
-    * Initialize the simple cache
-    *
-    * Config is as following:
-    *  path     Complete path to the cache file.
-    *  max_age  Maximum age of cache in seconds, 0 means "endlessly".
-    *
-    * @param array $cfg Config array
-    */
-    public function Net_LDAP2_SimpleFileSchemaCache($cfg)
-    {
-       foreach ($cfg as $key => $value) {
-                       if (array_key_exists($key, $this->config)) {
-                               if (gettype($this->config[$key]) != gettype($value)) {
-                                       $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key does not match type ".gettype($this->config[$key])."!");
-                               }
-                               $this->config[$key] = $value;
-                       } else {
-                               $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key is not defined!");
-                       }
-               }
-    }
-
-    /**
-    * Return the schema object from the cache
-    *
-    * If file is existent and cache has not expired yet,
-    * then the cache is deserialized and returned.
-    *
-    * @return Net_LDAP2_Schema|Net_LDAP2_Error|false
-    */
-    public function loadSchema()
-    {
-         $return = false; // Net_LDAP2 will load schema from LDAP
-         if (file_exists($this->config['path'])) {
-             $cache_maxage = filemtime($this->config['path']) + $this->config['max_age'];
-             if (time() <= $cache_maxage || $this->config['max_age'] == 0) {
-                 $return = unserialize(file_get_contents($this->config['path']));
-             }
-         }
-         return $return;
-    }
-
-    /**
-    * Store a schema object in the cache
-    *
-    * This method will be called, if Net_LDAP2 has fetched a fresh
-    * schema object from LDAP and wants to init or refresh the cache.
-    *
-    * To invalidate the cache and cause Net_LDAP2 to refresh the cache,
-    * you can call this method with null or false as value.
-    * The next call to $ldap->schema() will then refresh the caches object.
-    *
-    * @param mixed $schema The object that should be cached
-    * @return true|Net_LDAP2_Error|false
-    */
-    public function storeSchema($schema) {
-        file_put_contents($this->config['path'], serialize($schema));
-        return true;
-    }
-}
diff --git a/extlib/Net/LDAP2/Util.php b/extlib/Net/LDAP2/Util.php
deleted file mode 100644 (file)
index 48b03f9..0000000
+++ /dev/null
@@ -1,572 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-/**
-* File containing the Net_LDAP2_Util interface class.
-*
-* PHP version 5
-*
-* @category  Net
-* @package   Net_LDAP2
-* @author    Benedikt Hallinger <beni@php.net>
-* @copyright 2009 Benedikt Hallinger
-* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
-* @version   SVN: $Id: Util.php 286718 2009-08-03 07:30:49Z beni $
-* @link      http://pear.php.net/package/Net_LDAP2/
-*/
-
-/**
-* Includes
-*/
-require_once 'PEAR.php';
-
-/**
-* Utility Class for Net_LDAP2
-*
-* This class servers some functionality to the other classes of Net_LDAP2 but most of
-* the methods can be used separately as well.
-*
-* @category Net
-* @package  Net_LDAP2
-* @author   Benedikt Hallinger <beni@php.net>
-* @license  http://www.gnu.org/copyleft/lesser.html LGPL
-* @link     http://pear.php.net/package/Net_LDAP22/
-*/
-class Net_LDAP2_Util extends PEAR
-{
-    /**
-     * Constructor
-     *
-     * @access public
-     */
-    public function __construct()
-    {
-         // We do nothing here, since all methods can be called statically.
-         // In Net_LDAP <= 0.7, we needed a instance of Util, because
-         // it was possible to do utf8 encoding and decoding, but this
-         // has been moved to the LDAP class. The constructor remains only
-         // here to document the downward compatibility of creating an instance.
-    }
-
-    /**
-    * Explodes the given DN into its elements
-    *
-    * {@link http://www.ietf.org/rfc/rfc2253.txt RFC 2253} says, a Distinguished Name is a sequence
-    * of Relative Distinguished Names (RDNs), which themselves
-    * are sets of Attributes. For each RDN a array is constructed where the RDN part is stored.
-    *
-    * For example, the DN 'OU=Sales+CN=J. Smith,DC=example,DC=net' is exploded to:
-    * <kbd>array( [0] => array([0] => 'OU=Sales', [1] => 'CN=J. Smith'), [2] => 'DC=example', [3] => 'DC=net' )</kbd>
-    *
-    * [NOT IMPLEMENTED] DNs might also contain values, which are the bytes of the BER encoding of
-    * the X.500 AttributeValue rather than some LDAP string syntax. These values are hex-encoded
-    * and prefixed with a #. To distinguish such BER values, ldap_explode_dn uses references to
-    * the actual values, e.g. '1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com' is exploded to:
-    * [ { '1.3.6.1.4.1.1466.0' => "\004\002Hi" }, { 'DC' => 'example' }, { 'DC' => 'com' } ];
-    * See {@link http://www.vijaymukhi.com/vmis/berldap.htm} for more information on BER.
-    *
-    *  It also performs the following operations on the given DN:
-    *   - Unescape "\" followed by ",", "+", """, "\", "<", ">", ";", "#", "=", " ", or a hexpair
-    *     and strings beginning with "#".
-    *   - Removes the leading 'OID.' characters if the type is an OID instead of a name.
-    *   - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order.
-    *
-    * OPTIONS is a list of name/value pairs, valid options are:
-    *   casefold    Controls case folding of attribute types names.
-    *               Attribute values are not affected by this option.
-    *               The default is to uppercase. Valid values are:
-    *               lower        Lowercase attribute types names.
-    *               upper        Uppercase attribute type names. This is the default.
-    *               none         Do not change attribute type names.
-    *   reverse     If TRUE, the RDN sequence is reversed.
-    *   onlyvalues  If TRUE, then only attributes values are returned ('foo' instead of 'cn=foo')
-    *
-
-    * @param string $dn      The DN that should be exploded
-    * @param array  $options Options to use
-    *
-    * @static
-    * @return array   Parts of the exploded DN
-    * @todo implement BER
-    */
-    public static function ldap_explode_dn($dn, $options = array('casefold' => 'upper'))
-    {
-        if (!isset($options['onlyvalues'])) $options['onlyvalues']  = false;
-        if (!isset($options['reverse']))    $options['reverse']     = false;
-        if (!isset($options['casefold']))   $options['casefold']    = 'upper';
-
-        // Escaping of DN and stripping of "OID."
-        $dn = self::canonical_dn($dn, array('casefold' => $options['casefold']));
-
-        // splitting the DN
-        $dn_array = preg_split('/(?<=[^\\\\]),/', $dn);
-
-        // clear wrong splitting (possibly we have split too much)
-        // /!\ Not clear, if this is neccessary here
-        //$dn_array = self::correct_dn_splitting($dn_array, ',');
-
-        // construct subarrays for multivalued RDNs and unescape DN value
-        // also convert to output format and apply casefolding
-        foreach ($dn_array as $key => $value) {
-            $value_u = self::unescape_dn_value($value);
-            $rdns    = self::split_rdn_multival($value_u[0]);
-            if (count($rdns) > 1) {
-                // MV RDN!
-                foreach ($rdns as $subrdn_k => $subrdn_v) {
-                    // Casefolding
-                    if ($options['casefold'] == 'upper') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $subrdn_v);
-                    if ($options['casefold'] == 'lower') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $subrdn_v);
-
-                    if ($options['onlyvalues']) {
-                        preg_match('/(.+?)(?<!\\\\)=(.+)/', $subrdn_v, $matches);
-                        $rdn_ocl         = $matches[1];
-                        $rdn_val         = $matches[2];
-                        $unescaped       = self::unescape_dn_value($rdn_val);
-                        $rdns[$subrdn_k] = $unescaped[0];
-                    } else {
-                        $unescaped = self::unescape_dn_value($subrdn_v);
-                        $rdns[$subrdn_k] = $unescaped[0];
-                    }
-                }
-
-                $dn_array[$key] = $rdns;
-            } else {
-                // normal RDN
-
-                // Casefolding
-                if ($options['casefold'] == 'upper') $value = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $value);
-                if ($options['casefold'] == 'lower') $value = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $value);
-
-                if ($options['onlyvalues']) {
-                    preg_match('/(.+?)(?<!\\\\)=(.+)/', $value, $matches);
-                    $dn_ocl         = $matches[1];
-                    $dn_val         = $matches[2];
-                    $unescaped      = self::unescape_dn_value($dn_val);
-                    $dn_array[$key] = $unescaped[0];
-                } else {
-                    $unescaped = self::unescape_dn_value($value);
-                    $dn_array[$key] = $unescaped[0];
-                }
-            }
-        }
-
-        if ($options['reverse']) {
-            return array_reverse($dn_array);
-        } else {
-            return $dn_array;
-        }
-    }
-
-    /**
-    * Escapes a DN value according to RFC 2253
-    *
-    * Escapes the given VALUES according to RFC 2253 so that they can be safely used in LDAP DNs.
-    * The characters ",", "+", """, "\", "<", ">", ";", "#", "=" with a special meaning in RFC 2252
-    * are preceeded by ba backslash. Control characters with an ASCII code < 32 are represented as \hexpair.
-    * Finally all leading and trailing spaces are converted to sequences of \20.
-    *
-    * @param array $values An array containing the DN values that should be escaped
-    *
-    * @static
-    * @return array The array $values, but escaped
-    */
-    public static function escape_dn_value($values = array())
-    {
-        // Parameter validation
-        if (!is_array($values)) {
-            $values = array($values);
-        }
-
-        foreach ($values as $key => $val) {
-            // Escaping of filter meta characters
-            $val = str_replace('\\', '\\\\', $val);
-            $val = str_replace(',',    '\,', $val);
-            $val = str_replace('+',    '\+', $val);
-            $val = str_replace('"',    '\"', $val);
-            $val = str_replace('<',    '\<', $val);
-            $val = str_replace('>',    '\>', $val);
-            $val = str_replace(';',    '\;', $val);
-            $val = str_replace('#',    '\#', $val);
-            $val = str_replace('=',    '\=', $val);
-
-            // ASCII < 32 escaping
-            $val = self::asc2hex32($val);
-
-            // Convert all leading and trailing spaces to sequences of \20.
-            if (preg_match('/^(\s*)(.+?)(\s*)$/', $val, $matches)) {
-                $val = $matches[2];
-                for ($i = 0; $i < strlen($matches[1]); $i++) {
-                    $val = '\20'.$val;
-                }
-                for ($i = 0; $i < strlen($matches[3]); $i++) {
-                    $val = $val.'\20';
-                }
-            }
-
-            if (null === $val) $val = '\0';  // apply escaped "null" if string is empty
-
-            $values[$key] = $val;
-        }
-
-        return $values;
-    }
-
-    /**
-    * Undoes the conversion done by escape_dn_value().
-    *
-    * Any escape sequence starting with a baskslash - hexpair or special character -
-    * will be transformed back to the corresponding character.
-    *
-    * @param array $values Array of DN Values
-    *
-    * @return array Same as $values, but unescaped
-    * @static
-    */
-    public static function unescape_dn_value($values = array())
-    {
-        // Parameter validation
-        if (!is_array($values)) {
-            $values = array($values);
-        }
-
-        foreach ($values as $key => $val) {
-            // strip slashes from special chars
-            $val = str_replace('\\\\', '\\', $val);
-            $val = str_replace('\,',    ',', $val);
-            $val = str_replace('\+',    '+', $val);
-            $val = str_replace('\"',    '"', $val);
-            $val = str_replace('\<',    '<', $val);
-            $val = str_replace('\>',    '>', $val);
-            $val = str_replace('\;',    ';', $val);
-            $val = str_replace('\#',    '#', $val);
-            $val = str_replace('\=',    '=', $val);
-
-            // Translate hex code into ascii
-            $values[$key] = self::hex2asc($val);
-        }
-
-        return $values;
-    }
-
-    /**
-    * Returns the given DN in a canonical form
-    *
-    * Returns false if DN is not a valid Distinguished Name.
-    * DN can either be a string or an array
-    * as returned by ldap_explode_dn, which is useful when constructing a DN.
-    * The DN array may have be indexed (each array value is a OCL=VALUE pair)
-    * or associative (array key is OCL and value is VALUE).
-    *
-    * It performs the following operations on the given DN:
-    *     - Removes the leading 'OID.' characters if the type is an OID instead of a name.
-    *     - Escapes all RFC 2253 special characters (",", "+", """, "\", "<", ">", ";", "#", "="), slashes ("/"), and any other character where the ASCII code is < 32 as \hexpair.
-    *     - Converts all leading and trailing spaces in values to be \20.
-    *     - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order.
-    *
-    * OPTIONS is a list of name/value pairs, valid options are:
-    *     casefold    Controls case folding of attribute type names.
-    *                 Attribute values are not affected by this option. The default is to uppercase.
-    *                 Valid values are:
-    *                 lower        Lowercase attribute type names.
-    *                 upper        Uppercase attribute type names. This is the default.
-    *                 none         Do not change attribute type names.
-    *     [NOT IMPLEMENTED] mbcescape   If TRUE, characters that are encoded as a multi-octet UTF-8 sequence will be escaped as \(hexpair){2,*}.
-    *     reverse     If TRUE, the RDN sequence is reversed.
-    *     separator   Separator to use between RDNs. Defaults to comma (',').
-    *
-    * Note: The empty string "" is a valid DN, so be sure not to do a "$can_dn == false" test,
-    *       because an empty string evaluates to false. Use the "===" operator instead.
-    *
-    * @param array|string $dn      The DN
-    * @param array        $options Options to use
-    *
-    * @static
-    * @return false|string The canonical DN or FALSE
-    * @todo implement option mbcescape
-    */
-    public static function canonical_dn($dn, $options = array('casefold' => 'upper', 'separator' => ','))
-    {
-        if ($dn === '') return $dn;  // empty DN is valid!
-
-        // options check
-        if (!isset($options['reverse'])) {
-            $options['reverse'] = false;
-        } else {
-            $options['reverse'] = true;
-        }
-        if (!isset($options['casefold']))  $options['casefold'] = 'upper';
-        if (!isset($options['separator'])) $options['separator'] = ',';
-
-
-        if (!is_array($dn)) {
-            // It is not clear to me if the perl implementation splits by the user defined
-            // separator or if it just uses this separator to construct the new DN
-            $dn = preg_split('/(?<=[^\\\\])'.$options['separator'].'/', $dn);
-
-            // clear wrong splitting (possibly we have split too much)
-            $dn = self::correct_dn_splitting($dn, $options['separator']);
-        } else {
-            // Is array, check, if the array is indexed or associative
-            $assoc = false;
-            foreach ($dn as $dn_key => $dn_part) {
-                if (!is_int($dn_key)) {
-                    $assoc = true;
-                }
-            }
-            // convert to indexed, if associative array detected
-            if ($assoc) {
-                $newdn = array();
-                foreach ($dn as $dn_key => $dn_part) {
-                    if (is_array($dn_part)) {
-                        ksort($dn_part, SORT_STRING); // we assume here, that the rdn parts are also associative
-                        $newdn[] = $dn_part;  // copy array as-is, so we can resolve it later
-                    } else {
-                        $newdn[] = $dn_key.'='.$dn_part;
-                    }
-                }
-                $dn =& $newdn;
-            }
-        }
-
-        // Escaping and casefolding
-        foreach ($dn as $pos => $dnval) {
-            if (is_array($dnval)) {
-                // subarray detected, this means very surely, that we had
-                // a multivalued dn part, which must be resolved
-                $dnval_new = '';
-                foreach ($dnval as $subkey => $subval) {
-                    // build RDN part
-                    if (!is_int($subkey)) {
-                        $subval = $subkey.'='.$subval;
-                    }
-                    $subval_processed = self::canonical_dn($subval);
-                    if (false === $subval_processed) return false;
-                    $dnval_new .= $subval_processed.'+';
-                }
-                $dn[$pos] = substr($dnval_new, 0, -1); // store RDN part, strip last plus
-            } else {
-                // try to split multivalued RDNS into array
-                $rdns = self::split_rdn_multival($dnval);
-                if (count($rdns) > 1) {
-                    // Multivalued RDN was detected!
-                    // The RDN value is expected to be correctly split by split_rdn_multival().
-                    // It's time to sort the RDN and build the DN!
-                    $rdn_string = '';
-                    sort($rdns, SORT_STRING); // Sort RDN keys alphabetically
-                    foreach ($rdns as $rdn) {
-                        $subval_processed = self::canonical_dn($rdn);
-                        if (false === $subval_processed) return false;
-                        $rdn_string .= $subval_processed.'+';
-                    }
-
-                    $dn[$pos] = substr($rdn_string, 0, -1); // store RDN part, strip last plus
-
-                } else {
-                    // no multivalued RDN!
-                    // split at first unescaped "="
-                    $dn_comp = preg_split('/(?<=[^\\\\])=/', $rdns[0], 2);
-                    $ocl     = ltrim($dn_comp[0]);  // trim left whitespaces 'cause of "cn=foo, l=bar" syntax (whitespace after comma)
-                    $val     = $dn_comp[1];
-
-                    // strip 'OID.', otherwise apply casefolding and escaping
-                    if (substr(strtolower($ocl), 0, 4) == 'oid.') {
-                        $ocl = substr($ocl, 4);
-                    } else {
-                        if ($options['casefold'] == 'upper') $ocl = strtoupper($ocl);
-                        if ($options['casefold'] == 'lower') $ocl = strtolower($ocl);
-                        $ocl = self::escape_dn_value(array($ocl));
-                        $ocl = $ocl[0];
-                    }
-
-                    // escaping of dn-value
-                    $val = self::escape_dn_value(array($val));
-                    $val = str_replace('/', '\/', $val[0]);
-
-                    $dn[$pos] = $ocl.'='.$val;
-                }
-            }
-        }
-
-        if ($options['reverse']) $dn = array_reverse($dn);
-        return implode($options['separator'], $dn);
-    }
-
-    /**
-    * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters.
-    *
-    * Any control characters with an ACII code < 32 as well as the characters with special meaning in
-    * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a
-    * backslash followed by two hex digits representing the hexadecimal value of the character.
-    *
-    * @param array $values Array of values to escape
-    *
-    * @static
-    * @return array Array $values, but escaped
-    */
-    public static function escape_filter_value($values = array())
-    {
-        // Parameter validation
-        if (!is_array($values)) {
-            $values = array($values);
-        }
-
-        foreach ($values as $key => $val) {
-            // Escaping of filter meta characters
-            $val = str_replace('\\', '\5c', $val);
-            $val = str_replace('*',  '\2a', $val);
-            $val = str_replace('(',  '\28', $val);
-            $val = str_replace(')',  '\29', $val);
-
-            // ASCII < 32 escaping
-            $val = self::asc2hex32($val);
-
-            if (null === $val) $val = '\0';  // apply escaped "null" if string is empty
-
-            $values[$key] = $val;
-        }
-
-        return $values;
-    }
-
-    /**
-    * Undoes the conversion done by {@link escape_filter_value()}.
-    *
-    * Converts any sequences of a backslash followed by two hex digits into the corresponding character.
-    *
-    * @param array $values Array of values to escape
-    *
-    * @static
-    * @return array Array $values, but unescaped
-    */
-    public static function unescape_filter_value($values = array())
-    {
-        // Parameter validation
-        if (!is_array($values)) {
-            $values = array($values);
-        }
-
-        foreach ($values as $key => $value) {
-            // Translate hex code into ascii
-            $values[$key] = self::hex2asc($value);
-        }
-
-        return $values;
-    }
-
-    /**
-    * Converts all ASCII chars < 32 to "\HEX"
-    *
-    * @param string $string String to convert
-    *
-    * @static
-    * @return string
-    */
-    public static function asc2hex32($string)
-    {
-        for ($i = 0; $i < strlen($string); $i++) {
-            $char = substr($string, $i, 1);
-            if (ord($char) < 32) {
-                $hex = dechex(ord($char));
-                if (strlen($hex) == 1) $hex = '0'.$hex;
-                $string = str_replace($char, '\\'.$hex, $string);
-            }
-        }
-        return $string;
-    }
-
-    /**
-    * Converts all Hex expressions ("\HEX") to their original ASCII characters
-    *
-    * @param string $string String to convert
-    *
-    * @static
-    * @author beni@php.net, heavily based on work from DavidSmith@byu.net
-    * @return string
-    */
-    public static function hex2asc($string)
-    {
-        $string = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $string);
-        return $string;
-    }
-
-    /**
-    * Split an multivalued RDN value into an Array
-    *
-    * A RDN can contain multiple values, spearated by a plus sign.
-    * This function returns each separate ocl=value pair of the RDN part.
-    *
-    * If no multivalued RDN is detected, an array containing only
-    * the original rdn part is returned.
-    *
-    * For example, the multivalued RDN 'OU=Sales+CN=J. Smith' is exploded to:
-    * <kbd>array([0] => 'OU=Sales', [1] => 'CN=J. Smith')</kbd>
-    *
-    * The method trys to be smart if it encounters unescaped "+" characters, but may fail,
-    * so ensure escaped "+"es in attr names and attr values.
-    *
-    * [BUG] If you have a multivalued RDN with unescaped plus characters
-    *       and there is a unescaped plus sign at the end of an value followed by an
-    *       attribute name containing an unescaped plus, then you will get wrong splitting:
-    *         $rdn = 'OU=Sales+C+N=J. Smith';
-    *       returns:
-    *         array('OU=Sales+C', 'N=J. Smith');
-    *       The "C+" is treaten as value of the first pair instead as attr name of the second pair.
-    *       To prevent this, escape correctly.
-    *
-    * @param string $rdn Part of an (multivalued) escaped RDN (eg. ou=foo OR ou=foo+cn=bar)
-    *
-    * @static
-    * @return array Array with the components of the multivalued RDN or Error
-    */
-    public static function split_rdn_multival($rdn)
-    {
-        $rdns = preg_split('/(?<!\\\\)\+/', $rdn);
-        $rdns = self::correct_dn_splitting($rdns, '+');
-        return array_values($rdns);
-    }
-
-    /**
-    * Splits a attribute=value syntax into an array
-    *
-    * The split will occur at the first unescaped '=' character.
-    *
-    * @param string $attr Attribute and Value Syntax
-    *
-    * @return array Indexed array: 0=attribute name, 1=attribute value
-    */
-    public static function split_attribute_string($attr)
-    {
-        return preg_split('/(?<!\\\\)=/', $attr, 2);
-    }
-
-    /**
-    * Corrects splitting of dn parts
-    *
-    * @param array $dn        Raw DN array
-    * @param array $separator Separator that was used when splitting
-    *
-    * @return array Corrected array
-    * @access protected
-    */
-    protected static function correct_dn_splitting($dn = array(), $separator = ',')
-    {
-        foreach ($dn as $key => $dn_value) {
-            $dn_value = $dn[$key]; // refresh value (foreach caches!)
-            // if the dn_value is not in attr=value format, then we had an
-            // unescaped separator character inside the attr name or the value.
-            // We assume, that it was the attribute value.
-            // [TODO] To solve this, we might ask the schema. Keep in mind, that UTIL class
-            //        must remain independent from the other classes or connections.
-            if (!preg_match('/.+(?<!\\\\)=.+/', $dn_value)) {
-                unset($dn[$key]);
-                if (array_key_exists($key-1, $dn)) {
-                    $dn[$key-1] = $dn[$key-1].$separator.$dn_value; // append to previous attr value
-                } else {
-                    $dn[$key+1] = $dn_value.$separator.$dn[$key+1]; // first element: prepend to next attr name
-                }
-            }
-        }
-        return array_values($dn);
-    }
-}
-
-?>
index 3778ffe42016486f18090257f2bca6b5d8e57920..fa9f67269c29d10f8efdf42afcdd9ec4683e6cb3 100644 (file)
--- a/index.php
+++ b/index.php
@@ -185,7 +185,7 @@ function checkMirror($action_obj, $args)
 
 function isLoginAction($action)
 {
-    static $loginActions =  array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds', 'otp', 'rsd');
+    static $loginActions =  array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds', 'otp', 'opensearch', 'rsd');
 
     $login = null;
 
index c79a1f5d7753317c9f50b3f47916152ae6a46463..57740f8b85cb15417dcfed217d86b5e5f52a87c4 100644 (file)
@@ -105,27 +105,45 @@ class AccountSettingsNav extends Widget
             $user = common_current_user();
 
             if(Event::handle('StartAccountSettingsProfileMenuItem', array($this, &$menu))){
-                $this->showMenuItem('profilesettings',_('Profile'),_('Change your profile settings'));
+                // TRANS: Link title attribute in user account settings menu.
+                $title = _('Change your profile settings');
+                // TRANS: Link description in user account settings menu.
+                $this->showMenuItem('profilesettings',_('Profile'),$title);
                 Event::handle('EndAccountSettingsProfileMenuItem', array($this, &$menu));
             }
             if(Event::handle('StartAccountSettingsAvatarMenuItem', array($this, &$menu))){
-                $this->showMenuItem('avatarsettings',_('Avatar'),_('Upload an avatar'));
+                // TRANS: Link title attribute in user account settings menu.
+                $title = _('Upload an avatar');
+                // TRANS: Link description in user account settings menu.
+                $this->showMenuItem('avatarsettings',_('Avatar'),$title);
                 Event::handle('EndAccountSettingsAvatarMenuItem', array($this, &$menu));
             }
             if(Event::handle('StartAccountSettingsPasswordMenuItem', array($this, &$menu))){
-                $this->showMenuItem('passwordsettings',_('Password'),_('Change your password'));
+                // TRANS: Link title attribute in user account settings menu.
+                $title = _('Change your password');
+                // TRANS: Link description in user account settings menu.
+                $this->showMenuItem('passwordsettings',_('Password'),$title);
                 Event::handle('EndAccountSettingsPasswordMenuItem', array($this, &$menu));
             }
             if(Event::handle('StartAccountSettingsEmailMenuItem', array($this, &$menu))){
-                $this->showMenuItem('emailsettings',_('Email'),_('Change email handling'));
+                // TRANS: Link title attribute in user account settings menu.
+                $title = _('Change email handling');
+                // TRANS: Link description in user account settings menu.
+                $this->showMenuItem('emailsettings',_('Email'),$title);
                 Event::handle('EndAccountSettingsEmailMenuItem', array($this, &$menu));
             }
             if(Event::handle('StartAccountSettingsDesignMenuItem', array($this, &$menu))){
-                $this->showMenuItem('userdesignsettings',_('Design'),_('Design your profile'));
+                // TRANS: Link title attribute in user account settings menu.
+                $title = _('Design your profile');
+                // TRANS: Link description in user account settings menu.
+                $this->showMenuItem('userdesignsettings',_('Design'),$title);
                 Event::handle('EndAccountSettingsDesignMenuItem', array($this, &$menu));
             }
             if(Event::handle('StartAccountSettingsOtherMenuItem', array($this, &$menu))){
-                $this->showMenuItem('othersettings',_('Other'),_('Other options'));
+                // TRANS: Link title attribute in user account settings menu.
+                $title = _('Other options');
+                // TRANS: Link description in user account settings menu.
+                $this->showMenuItem('othersettings',_('Other'),$title);
                 Event::handle('EndAccountSettingsOtherMenuItem', array($this, &$menu));
             }
 
index c4d9fd5cbfec131ecafea08dbe6056c904b7107c..98e5ec2c94e7d89bb0d7472d4d2e0d423ee075f6 100644 (file)
@@ -141,6 +141,7 @@ class Action extends HTMLOutputter // lawsuit
     function showTitle()
     {
         $this->element('title', null,
+                       // TRANS: Page title. %1$s is the title, %2$s is the site name.
                        sprintf(_("%1\$s - %2\$s"),
                                $this->title(),
                                common_config('site', 'name')));
@@ -156,6 +157,7 @@ class Action extends HTMLOutputter // lawsuit
 
     function title()
     {
+        // TRANS: Page title for a page without a title set.
         return _("Untitled page");
     }
 
@@ -420,6 +422,7 @@ class Action extends HTMLOutputter // lawsuit
     {
         $user = common_current_user();
         $this->elementStart('dl', array('id' => 'site_nav_global_primary'));
+        // TRANS: DT element for primary navigation menu. String is hidden in default CSS.
         $this->element('dt', null, _('Primary site navigation'));
         $this->elementStart('dd');
         $this->elementStart('ul', array('class' => 'nav'));
@@ -427,31 +430,31 @@ class Action extends HTMLOutputter // lawsuit
             if ($user) {
                 // TRANS: Tooltip for main menu option "Personal"
                 $tooltip = _m('TOOLTIP', 'Personal profile and friends timeline');
-                // TRANS: Main menu option when logged in for access to personal profile and friends timeline
                 $this->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
+                                // TRANS: Main menu option when logged in for access to personal profile and friends timeline
                                 _m('MENU', 'Personal'), $tooltip, false, 'nav_home');
                 // TRANS: Tooltip for main menu option "Account"
                 $tooltip = _m('TOOLTIP', 'Change your email, avatar, password, profile');
-                // TRANS: Main menu option when logged in for access to user settings
                 $this->menuItem(common_local_url('profilesettings'),
+                                // TRANS: Main menu option when logged in for access to user settings
                                 _('Account'), $tooltip, false, 'nav_account');
                 // TRANS: Tooltip for main menu option "Services"
                 $tooltip = _m('TOOLTIP', 'Connect to services');
-                // TRANS: Main menu option when logged in and connection are possible for access to options to connect to other services
                 $this->menuItem(common_local_url('oauthconnectionssettings'),
+                                // TRANS: Main menu option when logged in and connection are possible for access to options to connect to other services
                                 _('Connect'), $tooltip, false, 'nav_connect');
                 if ($user->hasRight(Right::CONFIGURESITE)) {
                     // TRANS: Tooltip for menu option "Admin"
                     $tooltip = _m('TOOLTIP', 'Change site configuration');
-                    // TRANS: Main menu option when logged in and site admin for access to site configuration
                     $this->menuItem(common_local_url('siteadminpanel'),
+                                    // TRANS: Main menu option when logged in and site admin for access to site configuration
                                     _m('MENU', 'Admin'), $tooltip, false, 'nav_admin');
                 }
                 if (common_config('invite', 'enabled')) {
                     // TRANS: Tooltip for main menu option "Invite"
                     $tooltip = _m('TOOLTIP', 'Invite friends and colleagues to join you on %s');
-                    // TRANS: Main menu option when logged in and invitations are allowed for inviting new users
                     $this->menuItem(common_local_url('invite'),
+                                    // TRANS: Main menu option when logged in and invitations are allowed for inviting new users
                                     _m('MENU', 'Invite'),
                                     sprintf($tooltip,
                                             common_config('site', 'name')),
@@ -459,16 +462,16 @@ class Action extends HTMLOutputter // lawsuit
                 }
                 // TRANS: Tooltip for main menu option "Logout"
                 $tooltip = _m('TOOLTIP', 'Logout from the site');
-                // TRANS: Main menu option when logged in to log out the current user
                 $this->menuItem(common_local_url('logout'),
+                                // TRANS: Main menu option when logged in to log out the current user
                                 _m('MENU', 'Logout'), $tooltip, false, 'nav_logout');
             }
             else {
                 if (!common_config('site', 'closed') && !common_config('site', 'inviteonly')) {
                     // TRANS: Tooltip for main menu option "Register"
                     $tooltip = _m('TOOLTIP', 'Create an account');
-                    // TRANS: Main menu option when not logged in to register a new account
                     $this->menuItem(common_local_url('register'),
+                                    // TRANS: Main menu option when not logged in to register a new account
                                     _m('MENU', 'Register'), $tooltip, false, 'nav_register');
                 }
                 // TRANS: Tooltip for main menu option "Login"
@@ -575,6 +578,7 @@ class Action extends HTMLOutputter // lawsuit
     function showLocalNavBlock()
     {
         $this->elementStart('dl', array('id' => 'site_nav_local_views'));
+        // TRANS: DT element for local views block. String is hidden in default CSS.
         $this->element('dt', null, _('Local views'));
         $this->elementStart('dd');
         $this->showLocalNav();
@@ -641,6 +645,7 @@ class Action extends HTMLOutputter // lawsuit
 
             $this->elementStart('dl', array('id' => 'page_notice',
                                             'class' => 'system_notice'));
+            // TRANS: DT element for page notice. String is hidden in default CSS.
             $this->element('dt', null, _('Page notice'));
             $this->elementStart('dd');
             if (Event::handle('StartShowPageNotice', array($this))) {
@@ -743,28 +748,37 @@ class Action extends HTMLOutputter // lawsuit
     function showSecondaryNav()
     {
         $this->elementStart('dl', array('id' => 'site_nav_global_secondary'));
+        // TRANS: DT element for secondary navigation menu. String is hidden in default CSS.
         $this->element('dt', null, _('Secondary site navigation'));
         $this->elementStart('dd', null);
         $this->elementStart('ul', array('class' => 'nav'));
         if (Event::handle('StartSecondaryNav', array($this))) {
             $this->menuItem(common_local_url('doc', array('title' => 'help')),
+                            // TRANS: Secondary navigation menu option leading to help on StatusNet.
                             _('Help'));
             $this->menuItem(common_local_url('doc', array('title' => 'about')),
+                            // TRANS: Secondary navigation menu option leading to text about StatusNet site.
                             _('About'));
             $this->menuItem(common_local_url('doc', array('title' => 'faq')),
+                            // TRANS: Secondary navigation menu option leading to Frequently Asked Questions.
                             _('FAQ'));
             $bb = common_config('site', 'broughtby');
             if (!empty($bb)) {
                 $this->menuItem(common_local_url('doc', array('title' => 'tos')),
+                                // TRANS: Secondary navigation menu option leading to Terms of Service.
                                 _('TOS'));
             }
             $this->menuItem(common_local_url('doc', array('title' => 'privacy')),
+                            // TRANS: Secondary navigation menu option leading to privacy policy.
                             _('Privacy'));
             $this->menuItem(common_local_url('doc', array('title' => 'source')),
+                            // TRANS: Secondary navigation menu option.
                             _('Source'));
             $this->menuItem(common_local_url('version'),
+                            // TRANS: Secondary navigation menu option leading to version information on the StatusNet site.
                             _('Version'));
             $this->menuItem(common_local_url('doc', array('title' => 'contact')),
+                            // TRANS: Secondary navigation menu option leading to contact information on the StatusNet site.
                             _('Contact'));
             $this->menuItem(common_local_url('doc', array('title' => 'badge')),
                             _('Badge'));
@@ -795,16 +809,18 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showStatusNetLicense()
     {
+        // TRANS: DT element for StatusNet software license.
         $this->element('dt', array('id' => 'site_statusnet_license'), _('StatusNet software license'));
         $this->elementStart('dd', null);
-        // @fixme drop the final spaces in the messages when at good spot
-        // to let translations get updated.
         if (common_config('site', 'broughtby')) {
-            $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%). ');
+            // TRANS: First sentence of the StatusNet site license. Used if 'broughtby' is set.
+            $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%).');
         } else {
-            $instr = _('**%%site.name%%** is a microblogging service. ');
+            // TRANS: First sentence of the StatusNet site license. Used if 'broughtby' is not set.
+            $instr = _('**%%site.name%%** is a microblogging service.');
         }
         $instr .= ' ';
+        // TRANS: Second sentence of the StatusNet site license. Mentions the StatusNet source code license.
         $instr .= sprintf(_('It runs the [StatusNet](http://status.net/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), STATUSNET_VERSION);
         $output = common_markup_to_html($instr);
         $this->raw($output);
@@ -820,19 +836,25 @@ class Action extends HTMLOutputter // lawsuit
     function showContentLicense()
     {
         if (Event::handle('StartShowContentLicense', array($this))) {
+            // TRANS: DT element for StatusNet site content license.
             $this->element('dt', array('id' => 'site_content_license'), _('Site content license'));
             $this->elementStart('dd', array('id' => 'site_content_license_cc'));
 
             switch (common_config('license', 'type')) {
             case 'private':
+                // TRANS: Content license displayed when license is set to 'private'.
+                // TRANS: %1$s is the site name.
                 $this->element('p', null, sprintf(_('Content and data of %1$s are private and confidential.'),
                                                   common_config('site', 'name')));
                 // fall through
             case 'allrightsreserved':
                 if (common_config('license', 'owner')) {
+                    // TRANS: Content license displayed when license is set to 'allrightsreserved'.
+                    // TRANS: %1$s is the copyright owner.
                     $this->element('p', null, sprintf(_('Content and data copyright by %1$s. All rights reserved.'),
                                                       common_config('license', 'owner')));
                 } else {
+                    // TRANS: Content license displayed when license is set to 'allrightsreserved' and no owner is set.
                     $this->element('p', null, _('Content and data copyright by contributors. All rights reserved.'));
                 }
                 break;
@@ -1148,11 +1170,15 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
+    // XXX: The messages in this pagination method only tailor to navigating
+    //      notices. In other lists, "Previous"/"Next" type navigation is
+    //      desirable, but not available.
     function pagination($have_before, $have_after, $page, $action, $args=null)
     {
         // Does a little before-after block for next/prev page
         if ($have_before || $have_after) {
             $this->elementStart('dl', 'pagination');
+            // TRANS: DT element for pagination (previous/next, etc.).
             $this->element('dt', null, _('Pagination'));
             $this->elementStart('dd', null);
             $this->elementStart('ul', array('class' => 'nav'));
@@ -1162,6 +1188,8 @@ class Action extends HTMLOutputter // lawsuit
             $this->elementStart('li', array('class' => 'nav_prev'));
             $this->element('a', array('href' => common_local_url($action, $args, $pargs),
                                       'rel' => 'prev'),
+                           // TRANS: Pagination message to go to a page displaying information more in the
+                           // TRANS: present than the currently displayed information.
                            _('After'));
             $this->elementEnd('li');
         }
@@ -1170,6 +1198,8 @@ class Action extends HTMLOutputter // lawsuit
             $this->elementStart('li', array('class' => 'nav_next'));
             $this->element('a', array('href' => common_local_url($action, $args, $pargs),
                                       'rel' => 'next'),
+                           // TRANS: Pagination message to go to a page displaying information more in the
+                           // TRANS: past than the currently displayed information.
                            _('Before'));
             $this->elementEnd('li');
         }
@@ -1213,6 +1243,8 @@ class Action extends HTMLOutputter // lawsuit
      * @return void
      */
 
+    // XXX: Finding this type of check with the same message about 50 times.
+    //      Possible to refactor?
     function checkSessionToken()
     {
         // CSRF protection
index 27f09ab4d4639d66f37aef672c9be5fb88e1526e..8e2da99bb3afe46cb559a97178bc9e970178b86d 100644 (file)
@@ -118,7 +118,8 @@ class Activity
         // Insist on a feed's root DOMElement; don't allow a DOMDocument
         if ($feed instanceof DOMDocument) {
             throw new ClientException(
-                _("Expecting a root feed element but got a whole XML document.")
+                // TRANS: Client exception thrown when a feed instance is a DOMDocument.
+                _('Expecting a root feed element but got a whole XML document.')
             );
         }
 
index a927e23336f73b80ab78bc0a98aafbf95778e286..e22804fc8214b283f1398a470e2d9ed08f1ec8ef 100644 (file)
@@ -69,7 +69,7 @@ class AdminPanelAction extends Action
         // User must be logged in.
 
         if (!common_logged_in()) {
-            // TRANS: Client error message
+            // TRANS: Client error message thrown when trying to access the admin panel while not logged in.
             $this->clientError(_('Not logged in.'));
             return false;
         }
@@ -94,7 +94,7 @@ class AdminPanelAction extends Action
         // User must have the right to change admin settings
 
         if (!$user->hasRight(Right::CONFIGURESITE)) {
-            // TRANS: Client error message
+            // TRANS: Client error message thrown when a user tries to change admin settings but has no access rights.
             $this->clientError(_('You cannot make changes to this site.'));
             return false;
         }
@@ -106,7 +106,7 @@ class AdminPanelAction extends Action
         $name = mb_substr($name, 0, -10);
 
         if (!self::canAdmin($name)) {
-            // TRANS: Client error message
+            // TRANS: Client error message throw when a certain panel's settings cannot be changed.
             $this->clientError(_('Changes to that panel are not allowed.'), 403);
             return false;
         }
@@ -225,7 +225,7 @@ class AdminPanelAction extends Action
 
     function showForm()
     {
-        // TRANS: Client error message
+        // TRANS: Client error message.
         $this->clientError(_('showForm() not implemented.'));
         return;
     }
@@ -279,7 +279,8 @@ class AdminPanelAction extends Action
             $result = $config->delete();
             if (!$result) {
                 common_log_db_error($config, 'DELETE', __FILE__);
-                // TRANS: Client error message
+                // TRANS: Client error message thrown if design settings could not be deleted in
+                // TRANS: the admin panel Design.
                 $this->clientError(_("Unable to delete design setting."));
                 return null;
             }
index 59dc47c23beee0daa678b1a2fec3d89fe5ed1339..a3c34a91bf607e45a5d59e956620bf698d9ccc62 100644 (file)
  * @link      http://status.net/
  */
 
+/* External API usage documentation. Please update when you change how the API works. */
+
+/*! @mainpage StatusNet REST API
+
+    @section Introduction
+
+    Some explanatory text about the API would be nice.
+
+    @section API Methods
+
+    @subsection timelinesmethods_sec Timeline Methods
+
+    @li @ref publictimeline
+    @li @ref friendstimeline
+
+    @subsection statusmethods_sec Status Methods
+
+    @li @ref statusesupdate
+
+    @subsection usermethods_sec User Methods
+
+    @subsection directmessagemethods_sec Direct Message Methods
+
+    @subsection friendshipmethods_sec Friendship Methods
+
+    @subsection socialgraphmethods_sec Social Graph Methods
+
+    @subsection accountmethods_sec Account Methods
+
+    @subsection favoritesmethods_sec Favorites Methods
+
+    @subsection blockmethods_sec Block Methods
+
+    @subsection oauthmethods_sec OAuth Methods
+
+    @subsection helpmethods_sec Help Methods
+
+    @subsection groupmethods_sec Group Methods
+
+    @page apiroot API Root
+
+    The URLs for methods referred to in this API documentation are
+    relative to the StatusNet API root. The API root is determined by the
+    site's @b server and @b path variables, which are generally specified
+    in config.php. For example:
+
+    @code
+    $config['site']['server'] = 'example.org';
+    $config['site']['path'] = 'statusnet'
+    @endcode
+
+    The pattern for a site's API root is: @c protocol://server/path/api E.g:
+
+    @c http://example.org/statusnet/api
+
+    The @b path can be empty.  In that case the API root would simply be:
+
+    @c http://example.org/api
+
+*/
+
 if (!defined('STATUSNET')) {
     exit(1);
 }
@@ -102,6 +163,7 @@ class ApiAction extends Action
 
     function handle($args)
     {
+        header('Access-Control-Allow-Origin: *');
         parent::handle($args);
     }
 
@@ -1065,6 +1127,7 @@ class ApiAction extends Action
             $this->initTwitterAtom();
             break;
         default:
+            // TRANS: Client error on an API request with an unsupported data format.
             $this->clientError(_('Not a supported data format.'));
             break;
         }
@@ -1093,6 +1156,7 @@ class ApiAction extends Action
             $this->endTwitterRss();
             break;
         default:
+            // TRANS: Client error on an API request with an unsupported data format.
             $this->clientError(_('Not a supported data format.'));
             break;
         }
@@ -1209,6 +1273,7 @@ class ApiAction extends Action
             $this->showJsonObjects($profile_array);
             break;
         default:
+            // TRANS: Client error on an API request with an unsupported data format.
             $this->clientError(_('Not a supported data format.'));
             return;
         }
index e78de618ee2a4eb1713278d2592a54efd828c127..8c39988889d4efb765999b313abae939125d0e53 100644 (file)
  * @link      http://status.net/
  */
 
+/* External API usage documentation. Please update when you change how this method works. */
+
+/*! @page authentication Authentication
+
+    StatusNet supports HTTP Basic Authentication and OAuth for API calls.
+
+    @warning Currently, users who have created accounts without setting a
+    password via OpenID, Facebook Connect, etc., cannot use the API until
+    they set a password with their account settings panel.
+
+    @section HTTP Basic Auth
+
+
+
+    @section OAuth
+
+*/
+
 if (!defined('STATUSNET')) {
     exit(1);
 }
@@ -91,6 +109,7 @@ class ApiAuthAction extends ApiAction
 
         if ($this->isReadOnly($args) == false) {
             if ($this->access != self::READ_WRITE) {
+                // TRANS: Client error 401.
                 $msg = _('API resource requires read-write access, ' .
                          'but you only have read access.');
                 $this->clientError($msg, 401, $this->format);
@@ -273,8 +292,8 @@ class ApiAuthAction extends ApiAction
 
                 list($proxy, $ip) = common_client_ip();
 
-                $msg = sprintf(_('Failed API auth attempt, nickname = %1$s, ' .
-                         'proxy = %2$s, ip = %3$s'),
+                $msg = sprintf( 'Failed API auth attempt, nickname = %1$s, ' .
+                         'proxy = %2$s, ip = %3$s',
                                $this->auth_user_nickname,
                                $proxy,
                                $ip);
index 9b7d0586143304586ab3f103262c4e08766b4e63..81c8fb01816c4b02a1a63a82cf755639cd24f100 100644 (file)
@@ -133,6 +133,7 @@ class ApplicationEditForm extends Form
 
     function formLegend()
     {
+        // TRANS: Form legend.
         $this->out->element('legend', null, _('Edit application'));
     }
 
@@ -177,10 +178,12 @@ class ApplicationEditForm extends Form
         }
 
         $this->out->element('label', array('for' => 'app_icon'),
+                            // TRANS: Form input field label for application icon.
                             _('Icon'));
         $this->out->element('input', array('name' => 'app_icon',
                                            'type' => 'file',
                                            'id' => 'app_icon'));
+        // TRANS: Form guide.
         $this->out->element('p', 'form_guide', _('Icon for this application'));
         $this->out->element('input', array('name' => 'MAX_FILE_SIZE',
                                            'type' => 'hidden',
@@ -192,6 +195,7 @@ class ApplicationEditForm extends Form
 
         $this->out->hidden('application_id', $id);
 
+        // TRANS: Form input field label for application name.
         $this->out->input('name', _('Name'),
                           ($this->out->arg('name')) ? $this->out->arg('name') : $name);
 
@@ -201,11 +205,14 @@ class ApplicationEditForm extends Form
 
         $maxDesc = Oauth_application::maxDesc();
         if ($maxDesc > 0) {
+            // TRANS: Form input field instructions.
             $descInstr = sprintf(_('Describe your application in %d characters'),
                                  $maxDesc);
         } else {
+            // TRANS: Form input field instructions.
             $descInstr = _('Describe your application');
         }
+        // TRANS: Form input field label.
         $this->out->textarea('description', _('Description'),
                         ($this->out->arg('description')) ? $this->out->arg('description') : $description,
                              $descInstr);
@@ -213,27 +220,39 @@ class ApplicationEditForm extends Form
         $this->out->elementEnd('li');
 
         $this->out->elementStart('li');
+        // TRANS: Form input field instructions.
+        $instruction = _('URL of the homepage of this application');
+        // TRANS: Form input field label.
         $this->out->input('source_url', _('Source URL'),
                           ($this->out->arg('source_url')) ? $this->out->arg('source_url') : $source_url,
-                          _('URL of the homepage of this application'));
+                          $instruction);
         $this->out->elementEnd('li');
 
         $this->out->elementStart('li');
+        // TRANS: Form input field instructions.
+        $instruction = _('Organization responsible for this application');
+        // TRANS: Form input field label.
         $this->out->input('organization', _('Organization'),
                           ($this->out->arg('organization')) ? $this->out->arg('organization') : $organization,
-                          _('Organization responsible for this application'));
+                          $instruction);
         $this->out->elementEnd('li');
 
         $this->out->elementStart('li');
+        // TRANS: Form input field instructions.
+        $instruction = _('URL for the homepage of the organization');
+        // TRANS: Form input field label.
         $this->out->input('homepage', _('Homepage'),
                           ($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
-                          _('URL for the homepage of the organization'));
+                          $instruction);
         $this->out->elementEnd('li');
 
         $this->out->elementStart('li');
+        // TRANS: Form input field instructions.
+        $instruction = _('URL to redirect to after authentication');
+        // TRANS: Form input field label.
         $this->out->input('callback_url', ('Callback URL'),
                           ($this->out->arg('callback_url')) ? $this->out->arg('callback_url') : $callback_url,
-                          _('URL to redirect to after authentication'));
+                          $instruction);
         $this->out->elementEnd('li');
 
         $this->out->elementStart('li', array('id' => 'application_types'));
@@ -255,6 +274,7 @@ class ApplicationEditForm extends Form
 
         $this->out->element('label', array('for' => 'app_type-browser',
                                            'class' => 'radio'),
+                            // TRANS: Radio button label for application type
                             _('Browser'));
 
         $attrs = array('name' => 'app_type',
@@ -271,7 +291,9 @@ class ApplicationEditForm extends Form
 
         $this->out->element('label', array('for' => 'app_type-desktop',
                                            'class' => 'radio'),
+                            // TRANS: Radio button label for application type
                             _('Desktop'));
+        // TRANS: Form guide.
         $this->out->element('p', 'form_guide', _('Type of application, browser or desktop'));
         $this->out->elementEnd('li');
 
@@ -294,6 +316,7 @@ class ApplicationEditForm extends Form
 
         $this->out->element('label', array('for' => 'default_access_type-ro',
                                            'class' => 'radio'),
+                            // TRANS: Radio button label for access type.
                             _('Read-only'));
 
         $attrs = array('name' => 'default_access_type',
@@ -312,7 +335,9 @@ class ApplicationEditForm extends Form
 
         $this->out->element('label', array('for' => 'default_access_type-rw',
                                            'class' => 'radio'),
+                            // TRANS: Radio button label for access type.
                             _('Read-write'));
+        // TRANS: Form guide.
         $this->out->element('p', 'form_guide', _('Default access for this application: read-only, or read-write'));
 
         $this->out->elementEnd('li');
@@ -328,9 +353,13 @@ class ApplicationEditForm extends Form
 
     function formActions()
     {
-        $this->out->submit('cancel', _('Cancel'), 'submit form_action-primary',
+        // TRANS: Button label
+        $this->out->submit('cancel', _m('BUTTON','Cancel'), 'submit form_action-primary',
+                           // TRANS: Submit button title
                            'cancel', _('Cancel'));
-        $this->out->submit('save', _('Save'), 'submit form_action-secondary',
+        // TRANS: Button label
+        $this->out->submit('save', _m('BUTTON','Save'), 'submit form_action-secondary',
+                           // TRANS: Submit button title
                            'save', _('Save'));
     }
 }
index 3abb1f8aa7c8fa81abbda9ae97d23ed00c71ca8e..904f8981d1c1d8f22ae0ebfb825505f3fb77be2f 100644 (file)
@@ -88,7 +88,6 @@ class ApplicationList extends Widget
 
     function showApplication()
     {
-
         $user = common_current_user();
 
         $this->out->elementStart('li', array('class' => 'application',
@@ -133,11 +132,16 @@ class ApplicationList extends Widget
 
             $this->out->elementStart('li');
 
-            $access = ($this->application->access_type & Oauth_application::$writeAccess)
-              ? 'read-write' : 'read-only';
+            // TRANS: Application access type
+            $readWriteText = _('read-write');
+            // TRANS: Application access type
+            $readOnlyText = _('read-only');
 
-            $txt = 'Approved ' . common_date_string($appUser->modified) .
-              " - $access access.";
+            $access = ($this->application->access_type & Oauth_application::$writeAccess)
+              ? $readWriteText : $readOnlyText;
+            $modifiedDate = common_date_string($appUser->modified);
+            // TRANS: Used in application list. %1$s is a modified date, %2$s is access type (read-write or read-only)
+            $txt = sprintf(_('Approved %1$s - "%2$s" access.'),$modifiedDate,$access);
 
             $this->out->raw($txt);
             $this->out->elementEnd('li');
@@ -151,7 +155,8 @@ class ApplicationList extends Widget
             $this->out->elementStart('fieldset');
             $this->out->hidden('id', $this->application->id);
             $this->out->hidden('token', common_session_token());
-            $this->out->submit('revoke', _('Revoke'));
+            // TRANS: Button label
+            $this->out->submit('revoke', _m('BUTTON','Revoke'));
             $this->out->elementEnd('fieldset');
             $this->out->elementEnd('form');
             $this->out->elementEnd('li');
index 08c1c707c578091a0d5eb7d67b0795d776b9f013..b4810d04a082630cea2ce2b6b94d68b7944b5693 100644 (file)
@@ -58,11 +58,14 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed
         parent::__construct($indent);
         $this->group = $group;
 
+        // TRANS: Title in atom group notice feed. %s is a group name.
         $title      = sprintf(_("%s timeline"), $group->nickname);
         $this->setTitle($title);
 
         $sitename   = common_config('site', 'name');
         $subtitle   = sprintf(
+            // TRANS: Message is used as a subtitle in atom group notice feed.
+            // TRANS: %1$s is a group name, %2$s is a site name.
             _('Updates from %1$s on %2$s!'),
             $group->nickname,
             $sitename
index 428cc2de2f01192f46a212e97e398f97ba7afd5b..acfcbd75fb9fc25ad8ab5b4a0e23ea732167680b 100644 (file)
@@ -64,11 +64,14 @@ class AtomUserNoticeFeed extends AtomNoticeFeed
             $this->setActivitySubject($profile->asActivityNoun('subject'));
         }
 
+        // TRANS: Title in atom user notice feed. %s is a user name.
         $title      = sprintf(_("%s timeline"), $user->nickname);
         $this->setTitle($title);
 
         $sitename   = common_config('site', 'name');
         $subtitle   = sprintf(
+            // TRANS: Message is used as a subtitle in atom user notice feed.
+            // TRANS: %1$s is a user name, %2$s is a site name.
             _('Updates from %1$s on %2$s!'),
             $user->nickname, $sitename
         );
index 43f836e15089dad0503ccad52e2fe236389d687b..59cab9532c6b7373f0e2a210e0cf8ae3772149df 100644 (file)
@@ -84,6 +84,7 @@ class AttachmentList extends Widget
         if (empty($att)) return 0;
         $this->out->elementStart('dl', array('id' =>'attachments',
                                              'class' => 'entry-content'));
+        // TRANS: DT element label in attachment list.
         $this->out->element('dt', null, _('Attachments'));
         $this->out->elementStart('dd');
         $this->out->elementStart('ol', array('class' => 'attachments'));
@@ -260,6 +261,7 @@ class Attachment extends AttachmentListItem
                                                   'class' => 'entry-content'));
             if (!empty($this->oembed->author_name)) {
                 $this->out->elementStart('dl', 'vcard author');
+                // TRANS: DT element label in attachment list item.
                 $this->out->element('dt', null, _('Author'));
                 $this->out->elementStart('dd', 'fn');
                 if (empty($this->oembed->author_url)) {
@@ -273,6 +275,7 @@ class Attachment extends AttachmentListItem
             }
             if (!empty($this->oembed->provider)) {
                 $this->out->elementStart('dl', 'vcard');
+                // TRANS: DT element label in attachment list item.
                 $this->out->element('dt', null, _('Provider'));
                 $this->out->elementStart('dd', 'fn');
                 if (empty($this->oembed->provider_url)) {
index 07da9b2d12c785d57cf3a903bf7aa766341f1b37..3790bccf4bbd93f2f225bfbb60881a4a415fcb3b 100644 (file)
@@ -67,7 +67,7 @@ abstract class AuthorizationPlugin extends Plugin
 
     //------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\
 
-    function onStartSetUser(&$user) {
+    function onStartSetUser($user) {
         $loginAllowed = $this->loginAllowed($user);
         if($loginAllowed === true){
             return;
@@ -84,7 +84,7 @@ abstract class AuthorizationPlugin extends Plugin
         }
     }
 
-    function onStartSetApiUser(&$user) {
+    function onStartSetApiUser($user) {
         return $this->onStartSetUser($user);
     }
 
index 216f9e649a33af4660bdc4fcaa2965571d0b1d0c..a769dc1fc641275c8dbb45afa899d28d9a9abe72 100644 (file)
@@ -122,6 +122,8 @@ class Command
         }
         Event::handle('EndCommandGetProfile', array($this, $arg, &$profile));
         if (!$profile) {
+            // TRANS: Message given requesting a profile for a non-existing user.
+            // TRANS: %s is the nickname of the user for which the profile could not be found.
             throw new CommandException(sprintf(_('Could not find a user with nickname %s'), $arg));
         }
         return $profile;
@@ -140,6 +142,8 @@ class Command
         }
         Event::handle('EndCommandGetUser', array($this, $arg, &$user));
         if (!$user){
+            // TRANS: Message given getting a non-existing user.
+            // TRANS: %s is the nickname of the user that could not be found.
             throw new CommandException(sprintf(_('Could not find a local user with nickname %s'),
                                $arg));
         }
@@ -225,6 +229,8 @@ class NudgeCommand extends Command
             }
             // XXX: notify by IM
             // XXX: notify by SMS
+            // TRANS: Message given having nudged another user.
+            // TRANS: %s is the nickname of the user that was nudged.
             $channel->output($this->user, sprintf(_('Nudge sent to %s'),
                            $recipient->nickname));
         }
@@ -328,12 +334,16 @@ class JoinCommand extends Command
                 Event::handle('EndJoinGroup', array($group, $cur));
             }
         } catch (Exception $e) {
-            $channel->error($cur, sprintf(_('Could not join user %s to group %s'),
+            // TRANS: Message given having failed to add a user to a group.
+            // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
+            $channel->error($cur, sprintf(_('Could not join user %1$s to group %2$s'),
                                           $cur->nickname, $group->nickname));
             return;
         }
 
-        $channel->output($cur, sprintf(_('%s joined group %s'),
+        // TRANS: Message given having added a user to a group.
+        // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
+        $channel->output($cur, sprintf(_('%1$s joined group %2$s'),
                                               $cur->nickname,
                                               $group->nickname));
     }
@@ -370,12 +380,16 @@ class DropCommand extends Command
                 Event::handle('EndLeaveGroup', array($group, $cur));
             }
         } catch (Exception $e) {
-            $channel->error($cur, sprintf(_('Could not remove user %s to group %s'),
+            // TRANS: Message given having failed to remove a user from a group.
+            // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
+            $channel->error($cur, sprintf(_('Could not remove user %1$s from group %2$s'),
                                           $cur->nickname, $group->nickname));
             return;
         }
 
-        $channel->output($cur, sprintf(_('%s left group %s'),
+        // TRANS: Message given having removed a user from a group.
+        // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
+        $channel->output($cur, sprintf(_('%1$s left group %2$s'),
                                               $cur->nickname,
                                               $group->nickname));
     }
@@ -395,18 +409,24 @@ class WhoisCommand extends Command
     {
         $recipient = $this->getProfile($this->other);
 
+        // TRANS: Whois output.
+        // TRANS: %1$s nickname of the queried user, %2$s is their profile URL.
         $whois = sprintf(_("%1\$s (%2\$s)"), $recipient->nickname,
                          $recipient->profileurl);
         if ($recipient->fullname) {
+            // TRANS: Whois output. %s is the full name of the queried user.
             $whois .= "\n" . sprintf(_('Fullname: %s'), $recipient->fullname);
         }
         if ($recipient->location) {
+            // TRANS: Whois output. %s is the location of the queried user.
             $whois .= "\n" . sprintf(_('Location: %s'), $recipient->location);
         }
         if ($recipient->homepage) {
+            // TRANS: Whois output. %s is the homepage of the queried user.
             $whois .= "\n" . sprintf(_('Homepage: %s'), $recipient->homepage);
         }
         if ($recipient->bio) {
+            // TRANS: Whois output. %s is the bio information of the queried user.
             $whois .= "\n" . sprintf(_('About: %s'), $recipient->bio);
         }
         $channel->output($this->user, $whois);
@@ -447,7 +467,9 @@ class MessageCommand extends Command
         $this->text = common_shorten_links($this->text);
 
         if (Message::contentTooLong($this->text)) {
-            $channel->error($this->user, sprintf(_('Message too long - maximum is %d characters, you sent %d'),
+            // TRANS: Message given if content is too long.
+            // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
+            $channel->error($this->user, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d'),
                                                  Message::maxContent(), mb_strlen($this->text)));
             return;
         }
@@ -465,6 +487,8 @@ class MessageCommand extends Command
         $message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
         if ($message) {
             $message->notify();
+            // TRANS: Message given have sent a direct message to another user.
+            // TRANS: %s is the name of the other user.
             $channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other));
         } else {
             $channel->error($this->user, _('Error sending direct message.'));
@@ -500,6 +524,8 @@ class RepeatCommand extends Command
 
         if ($repeat) {
 
+            // TRANS: Message given having repeated a notice from another user.
+            // TRANS: %s is the name of the user for which the notice was repeated.
             $channel->output($this->user, sprintf(_('Notice from %s repeated'), $recipient->nickname));
         } else {
             $channel->error($this->user, _('Error repeating notice.'));
index 7786b5941e25ba770d3f11c029f360af5b322f50..5dc2b38dab44caedcf24fe981ff9db3877ec2e88 100644 (file)
@@ -100,6 +100,7 @@ class HTMLOutputter extends XMLOutputter
             $type = common_negotiate_type($cp, $sp);
 
             if (!$type) {
+                // TRANS: Client exception 406
                 throw new ClientException(_('This page is not available in a '.
                                             'media type you accept'), 406);
             }
index 64b59e73966e61b9894e85efbd57eadd4e6a2f9b..8009adc9b741c278506271e67e900b48c6e91ddc 100644 (file)
@@ -202,16 +202,19 @@ function _mdomain($backtrace)
     static $cached;
     $path = $backtrace[0]['file'];
     if (!isset($cached[$path])) {
+        $final = 'statusnet'; // assume default domain
         if (DIRECTORY_SEPARATOR !== '/') {
             $path = strtr($path, DIRECTORY_SEPARATOR, '/');
         }
-        $cut = strpos($path, '/plugins/') + 9;
-        $cut2 = strpos($path, '/', $cut);
-        if ($cut && $cut2) {
-            $cached[$path] = substr($path, $cut, $cut2 - $cut);
-        } else {
-            return null;
+        $cut = strpos($path, '/plugins/');
+        if ($cut) {
+            $cut += strlen('/plugins/');
+            $cut2 = strpos($path, '/', $cut);
+            if ($cut && $cut2) {
+                $final = substr($path, $cut, $cut2 - $cut);
+            }
         }
+        $cached[$path] = $final;
     }
     return $cached[$path];
 }
@@ -286,6 +289,7 @@ function get_nice_language_list()
  */
 function get_all_languages() {
     return array(
+        'af'      => array('q' => 0.8, 'lang' => 'af', 'name' => 'Afrikaans', 'direction' => 'ltr'),
         'ar'      => array('q' => 0.8, 'lang' => 'ar', 'name' => 'Arabic', 'direction' => 'rtl'),
         'arz'     => array('q' => 0.8, 'lang' => 'arz', 'name' => 'Egyptian Spoken Arabic', 'direction' => 'rtl'),
         'bg'      => array('q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'),
@@ -301,7 +305,8 @@ function get_all_languages() {
         'fi'      => array('q' => 1, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'),
         'fa'      => array('q' => 1, 'lang' => 'fa', 'name' => 'Persian', 'direction' => 'rtl'),
         'fr-fr'   => array('q' => 1, 'lang' => 'fr', 'name' => 'French', 'direction' => 'ltr'),
-        'ga'      => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'),
+        'ga'      => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Irish', 'direction' => 'ltr'),
+        'gl'      => array('q' => 0.8, 'lang' => 'gl', 'name' => 'Galician', 'direction' => 'ltr'),
         'he'      => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'),
         'hsb'     => array('q' => 0.8, 'lang' => 'hsb', 'name' => 'Upper Sorbian', 'direction' => 'ltr'),
         'ia'      => array('q' => 0.8, 'lang' => 'ia', 'name' => 'Interlingua', 'direction' => 'ltr'),
index 10d90d0081e877f5742194387a7019b5cad5f084..1c96c42d7a7245d8a9ac3537ddddd08cfa367839 100644 (file)
@@ -171,7 +171,7 @@ class MediaFile
             return;
         }
 
-        if (!MediaFile::respectsQuota($user, $_FILES['attach']['size'])) {
+        if (!MediaFile::respectsQuota($user, $_FILES[$param]['size'])) {
 
             // Should never actually get here
 
index 7278c41a9cf2640323e34430c79c7118d3e6b8e7..84c20a5b3ff1ed13d49695113b661f74fd67f0ec 100644 (file)
@@ -212,8 +212,8 @@ class NoticeForm extends Form
                 $this->out->checkbox('notice_data-geo', _('Share my location'), true);
                 $this->out->elementEnd('div');
                 $this->out->inlineScript(' var NoticeDataGeo_text = {'.
-                    'ShareDisable: "'._('Do not share my location').'",'.
-                    'ErrorTimeout: "'._('Sorry, retrieving your geo location is taking longer than expected, please try again later').'"'.
+                    'ShareDisable: ' .json_encode(_('Do not share my location')).','.
+                    'ErrorTimeout: ' .json_encode(_('Sorry, retrieving your geo location is taking longer than expected, please try again later')).
                     '}');
             }
 
index 4f997a3286a78b339644c8a7dd72f32fd31e07ed..5265326b27da4461f799cdb9a03630a983843399 100644 (file)
@@ -426,10 +426,18 @@ class NoticeListItem extends Widget
         if (empty($name)) {
             $latdms = $this->decimalDegreesToDMS(abs($lat));
             $londms = $this->decimalDegreesToDMS(abs($lon));
+            // TRANS: Used in coordinates as abbreviation of north
+            $north = _('N');
+            // TRANS: Used in coordinates as abbreviation of south
+            $south = _('S');
+            // TRANS: Used in coordinates as abbreviation of east
+            $east = _('E');
+            // TRANS: Used in coordinates as abbreviation of west
+            $west = _('W');
             $name = sprintf(
                 _('%1$u°%2$u\'%3$u"%4$s %5$u°%6$u\'%7$u"%8$s'),
-                $latdms['deg'],$latdms['min'], $latdms['sec'],($lat>0?_('N'):_('S')),
-                $londms['deg'],$londms['min'], $londms['sec'],($lon>0?_('E'):_('W')));
+                $latdms['deg'],$latdms['min'], $latdms['sec'],($lat>0? $north:$south),
+                $londms['deg'],$londms['min'], $londms['sec'],($lon>0? $east:$west));
         }
 
         $url  = $location->getUrl();
index 82e0224af2182141780eb744797eaf0d600cc33b..504b77566993ccdbab8d08197888aac194a13868 100644 (file)
@@ -174,6 +174,12 @@ class ProfileAction extends OwnerDesignAction
         $subbed_count = $this->profile->subscriberCount();
         $notice_count = $this->profile->noticeCount();
         $group_count  = $this->user->getGroups()->N;
+        $age_days     = (time() - strtotime($this->profile->created)) / 86400;
+        if ($age_days < 1) {
+            // Rather than extrapolating out to a bajillion...
+            $age_days = 1;
+        }
+        $daily_count = round($notice_count / $age_days);
 
         $this->elementStart('div', array('id' => 'entity_statistics',
                                          'class' => 'section'));
@@ -224,6 +230,12 @@ class ProfileAction extends OwnerDesignAction
         $this->element('dd', null, $notice_count);
         $this->elementEnd('dl');
 
+        $this->elementStart('dl', 'entity_daily_notices');
+        // TRANS: Average count of posts made per day since account registration
+        $this->element('dt', null, _('Daily average'));
+        $this->element('dd', null, $daily_count);
+        $this->elementEnd('dl');
+
         $this->elementEnd('div');
     }
 
index c0013bb3da4db96627e0e7723bf1ac0e8007e7e4..e0669a1d56c976a8b3de99dcec1905dd4c47e73a 100644 (file)
@@ -832,7 +832,7 @@ function common_linkify($url) {
     }
 
     if (!empty($f)) {
-        if ($f->getEnclosure()) {
+        if ($f->getEnclosure() || File_oembed::staticGet('file_id',$f->id)) {
             $is_attachment = true;
             $attachment_id = $f->id;
 
@@ -855,10 +855,10 @@ function common_linkify($url) {
     return XMLStringer::estring('a', $attrs, $url);
 }
 
-function common_shorten_links($text)
+function common_shorten_links($text, $always = false)
 {
     $maxLength = Notice::maxContent();
-    if ($maxLength == 0 || mb_strlen($text) <= $maxLength) return $text;
+    if (!$always && ($maxLength == 0 || mb_strlen($text) <= $maxLength)) return $text;
     return common_replace_urls_callback($text, array('File_redirection', 'makeShort'));
 }
 
@@ -1079,24 +1079,38 @@ function common_date_string($dt)
     if ($now < $t) { // that shouldn't happen!
         return common_exact_date($dt);
     } else if ($diff < 60) {
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return _('a few seconds ago');
     } else if ($diff < 92) {
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return _('about a minute ago');
     } else if ($diff < 3300) {
+        // XXX: should support plural.
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return sprintf(_('about %d minutes ago'), round($diff/60));
     } else if ($diff < 5400) {
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return _('about an hour ago');
     } else if ($diff < 22 * 3600) {
+        // XXX: should support plural.
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return sprintf(_('about %d hours ago'), round($diff/3600));
     } else if ($diff < 37 * 3600) {
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return _('about a day ago');
     } else if ($diff < 24 * 24 * 3600) {
+        // XXX: should support plural.
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return sprintf(_('about %d days ago'), round($diff/(24*3600)));
     } else if ($diff < 46 * 24 * 3600) {
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return _('about a month ago');
     } else if ($diff < 330 * 24 * 3600) {
+        // XXX: should support plural.
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return sprintf(_('about %d months ago'), round($diff/(30*24*3600)));
     } else if ($diff < 480 * 24 * 3600) {
+        // TRANS: Used in notices to indicate when the notice was made compared to now.
         return _('about a year ago');
     } else {
         return common_exact_date($dt);
index 10dab614ef0417f6f7ea34d48ceea965f40ce894..b6ca4a23ebf29bffad288b730cd031ce6e0da739 100644 (file)
@@ -9,11 +9,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:15:59+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:08+0000\n"
 "Language-Team: Afrikaans\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: af\n"
 "X-Message-Group: out-statusnet\n"
@@ -4616,7 +4616,7 @@ msgstr ""
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -4968,7 +4968,7 @@ msgid "Before"
 msgstr "Voor"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -4976,11 +4976,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6212,7 +6212,7 @@ msgstr ""
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Onbekend"
 
index 84c856ba8cd3d3860466b9d2393fa66147822c71..44a1607dada0074c1a21ba657c2309a14b1a0869 100644 (file)
@@ -9,12 +9,12 @@ msgid ""
 msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:02+0000\n"
+"POT-Creation-Date: 2010-04-29 23:21+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:11+0000\n"
 "Language-Team: Arabic\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: ar\n"
 "X-Message-Group: out-statusnet\n"
@@ -1227,7 +1227,7 @@ msgstr "الوصف مطلوب."
 
 #: actions/editapplication.php:194
 msgid "Source URL is too long."
-msgstr ""
+msgstr "المسار المصدر طويل جدًا."
 
 #: actions/editapplication.php:200 actions/newapplication.php:185
 msgid "Source URL is not valid."
@@ -2008,15 +2008,13 @@ msgstr "هذا عنوان محادثة فورية خاطئ."
 
 #. TRANS: Server error thrown on database error canceling IM address confirmation.
 #: actions/imsettings.php:397
-#, fuzzy
 msgid "Couldn't delete IM confirmation."
-msgstr "تعذّر حذف تأكيد البريد الإلكتروني."
+msgstr "تعذّر حذف تأكيد البريد المراسلة الفورية."
 
 #. TRANS: Message given after successfully canceling IM address confirmation.
 #: actions/imsettings.php:402
-#, fuzzy
 msgid "IM confirmation cancelled."
-msgstr "Ø£Ù\8fÙ\84غÙ\8a Ø§Ù\84تأÙ\83Ù\8aد."
+msgstr "Ø£Ù\8fÙ\84غÙ\8a ØªØ£Ù\83Ù\8aد Ø§Ù\84Ù\85راسÙ\84Ø© Ø§Ù\84Ù\81Ù\88رÙ\8aØ©."
 
 #. TRANS: Message given trying to remove an IM address that is not
 #. TRANS: registered for the active user.
@@ -2026,9 +2024,8 @@ msgstr "هذه ليست هويتك في جابر."
 
 #. TRANS: Message given after successfully removing a registered IM address.
 #: actions/imsettings.php:447
-#, fuzzy
 msgid "The IM address was removed."
-msgstr "أزيل هذا العنوان."
+msgstr "أزيل عنوان المراسلة الفورية هذا."
 
 #: actions/inbox.php:59
 #, php-format
@@ -2046,7 +2043,7 @@ msgstr "هذا صندوق بريدك الوارد، والذي يسرد رسائ
 
 #: actions/invite.php:39
 msgid "Invites have been disabled."
-msgstr ""
+msgstr "تم تعطيل الدعوات."
 
 #: actions/invite.php:41
 #, fuzzy, php-format
@@ -2258,9 +2255,8 @@ msgid "Can't make %1$s an admin for group %2$s."
 msgstr "لم يمكن جعل %1$s إداريا للمجموعة %2$s."
 
 #: actions/microsummary.php:69
-#, fuzzy
 msgid "No current status."
-msgstr "Ù\84ا Ø­Ø§Ù\84Ø© Ø­Ø§Ù\84Ù\8aØ©"
+msgstr "Ù\84ا Ø­Ø§Ù\84Ø© Ø¬Ø§Ø±Ù\8aØ©."
 
 #: actions/newapplication.php:52
 msgid "New Application"
@@ -2603,24 +2599,24 @@ msgid "Path and server settings for this StatusNet site."
 msgstr ""
 
 #: actions/pathsadminpanel.php:157
-#, fuzzy, php-format
+#, php-format
 msgid "Theme directory not readable: %s."
-msgstr "لا يمكن قراءة دليل السمات: %s"
+msgstr "لا يمكن قراءة دليل السمات: %s."
 
 #: actions/pathsadminpanel.php:163
-#, fuzzy, php-format
+#, php-format
 msgid "Avatar directory not writable: %s."
-msgstr "لا يمكن الكتابة في دليل الأفتارات: %s"
+msgstr "لا يمكن الكتابة في دليل الأفتارات: %s."
 
 #: actions/pathsadminpanel.php:169
-#, fuzzy, php-format
+#, php-format
 msgid "Background directory not writable: %s."
-msgstr "لا يمكن الكتابة في دليل الخلفيات: %s"
+msgstr "لا يمكن الكتابة في دليل الخلفيات: %s."
 
 #: actions/pathsadminpanel.php:177
-#, fuzzy, php-format
+#, php-format
 msgid "Locales directory not readable: %s."
-msgstr "لا يمكن قراءة دليل المحليات: %s"
+msgstr "لا يمكن قراءة دليل المحليات: %s."
 
 #: actions/pathsadminpanel.php:183
 msgid "Invalid SSL server. The maximum length is 255 characters."
@@ -2760,9 +2756,9 @@ msgid "People search"
 msgstr "بحث في الأشخاص"
 
 #: actions/peopletag.php:68
-#, fuzzy, php-format
+#, php-format
 msgid "Not a valid people tag: %s."
-msgstr "ليس وسم أشخاص صالح: %s"
+msgstr "ليس وسم أشخاص صالح: %s."
 
 #: actions/peopletag.php:142
 #, php-format
@@ -2770,9 +2766,8 @@ msgid "Users self-tagged with %1$s - page %2$d"
 msgstr "المستخدمون الذين وسموا أنفسهم ب%1$s - الصفحة %2$d"
 
 #: actions/postnotice.php:95
-#, fuzzy
 msgid "Invalid notice content."
-msgstr "محتوى إشعار غير صالح"
+msgstr "محتوى إشعار غير صالح."
 
 #: actions/postnotice.php:101
 #, php-format
@@ -2913,9 +2908,9 @@ msgid "Settings saved."
 msgstr "حُفظت الإعدادات."
 
 #: actions/public.php:83
-#, fuzzy, php-format
+#, php-format
 msgid "Beyond the page limit (%s)."
-msgstr "وراء حد الصفحة (%s)"
+msgstr "بعد حد الصفحة (%s)."
 
 #: actions/public.php:92
 msgid "Could not retrieve public stream."
@@ -3385,9 +3380,8 @@ msgid "Sessions"
 msgstr "الجلسات"
 
 #: actions/sessionsadminpanel.php:65
-#, fuzzy
 msgid "Session settings for this StatusNet site."
-msgstr "اÙ\84إعدادات Ø§Ù\84أساسÙ\8aØ© Ù\84موقع StatusNet هذا."
+msgstr "إعدادات Ø¬Ù\84سة موقع StatusNet هذا."
 
 #: actions/sessionsadminpanel.php:175
 msgid "Handle sessions"
@@ -4641,7 +4635,7 @@ msgstr "مشكلة أثناء حفظ الإشعار."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "آر تي @%1$s %2$s"
@@ -5002,7 +4996,7 @@ msgid "Before"
 msgstr "قبل"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5010,11 +5004,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6318,7 +6312,7 @@ msgstr "رسائلك المُرسلة"
 msgid "Tags in %s's notices"
 msgstr "وسوم في إشعارات %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "غير معروفة"
 
index e67405582f9a5de3b2b12f620801fb102cff99c0..30763d3e02ca33356c4680b25986c0b57021ac97 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:06+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:20+0000\n"
 "Language-Team: Egyptian Spoken Arabic\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: arz\n"
 "X-Message-Group: out-statusnet\n"
@@ -4658,7 +4658,7 @@ msgstr "مشكله أثناء حفظ الإشعار."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "آر تى @%1$s %2$s"
@@ -5035,7 +5035,7 @@ msgid "Before"
 msgstr "قبل"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5043,11 +5043,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6298,7 +6298,7 @@ msgstr "رسائلك المُرسلة"
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "مش معروف"
 
index c96b66ee6ea4d5ed9c1710eb13faebc34f172527..650bfdc93f0d29a1007b56d2f77b677bd364de86 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:09+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:24+0000\n"
 "Language-Team: Bulgarian\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: bg\n"
 "X-Message-Group: out-statusnet\n"
@@ -4816,7 +4816,7 @@ msgstr "Проблем при записване на бележката."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5188,7 +5188,7 @@ msgid "Before"
 msgstr "Преди"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5196,11 +5196,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6472,7 +6472,7 @@ msgstr "Изпратените от вас съобщения"
 msgid "Tags in %s's notices"
 msgstr "Етикети в бележките на %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "Непознато действие"
index 9e0994529c24622fedeac9337f32b778c75cba85..2ab02917ba254cb1a15007b831732f70db068f97 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:12+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:27+0000\n"
 "Language-Team: Dutch\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: br\n"
 "X-Message-Group: out-statusnet\n"
@@ -2105,7 +2105,7 @@ msgstr "Kemennadenn bersonel"
 
 #: actions/invite.php:194
 msgid "Optionally add a personal message to the invitation."
-msgstr ""
+msgstr "Ouzhpennañ ur gemennadenn bersonel d'ar bedadenn (diret)."
 
 #. TRANS: Send button for inviting friends
 #: actions/invite.php:198
@@ -2772,6 +2772,8 @@ msgstr "Danvez direizh an ali."
 #, php-format
 msgid "Notice license ‘%1$s’ is not compatible with site license ‘%2$s’."
 msgstr ""
+"Aotre-implijout ar menegoù \"%1$s\" ne ya ket gant aotre-implijout al "
+"lec'hienn \"%2$s\"."
 
 #: actions/profilesettings.php:60
 msgid "Profile settings"
@@ -2781,6 +2783,8 @@ msgstr "Arventennoù ar profil"
 msgid ""
 "You can update your personal profile info here so people know more about you."
 msgstr ""
+"Gellout a reoc'h hizivaat titouroù ho profil evit ma ouifemp muioc'h a draoù "
+"diwar ho penn."
 
 #: actions/profilesettings.php:99
 msgid "Profile information"
@@ -2788,7 +2792,7 @@ msgstr "Titouroù ar profil"
 
 #: actions/profilesettings.php:108 lib/groupeditform.php:154
 msgid "1-64 lowercase letters or numbers, no punctuation or spaces"
-msgstr ""
+msgstr "1 da 64 lizherenn vihan pe sifr, hep poentaouiñ nag esaouenn"
 
 #: actions/profilesettings.php:111 actions/register.php:448
 #: actions/showgroup.php:256 actions/tagother.php:104
@@ -2804,12 +2808,12 @@ msgstr "Pajenn degemer"
 
 #: actions/profilesettings.php:117 actions/register.php:455
 msgid "URL of your homepage, blog, or profile on another site"
-msgstr ""
+msgstr "URL ho pajenn degemer, ho blog, pe ho profil en ul lec'hienn all"
 
 #: actions/profilesettings.php:122 actions/register.php:461
 #, php-format
 msgid "Describe yourself and your interests in %d chars"
-msgstr ""
+msgstr "Deskrivit ac'hanoc'h hag ho interestoù, gant %d arouezenn"
 
 #: actions/profilesettings.php:125 actions/register.php:464
 msgid "Describe yourself and your interests"
@@ -2844,6 +2848,8 @@ msgstr "Balizennoù"
 msgid ""
 "Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated"
 msgstr ""
+"Merkoù evidoc'h oc'h unan (lizherennoù, sifroù, -, ., ha _), dispartiet gant "
+"virgulennoù pe esaouennoù"
 
 #: actions/profilesettings.php:151
 msgid "Language"
@@ -2859,12 +2865,14 @@ msgstr "Takad eur"
 
 #: actions/profilesettings.php:162
 msgid "What timezone are you normally in?"
-msgstr ""
+msgstr "Pehini eo gwerzhid-eur boaz ?"
 
 #: actions/profilesettings.php:167
 msgid ""
 "Automatically subscribe to whoever subscribes to me (best for non-humans)"
 msgstr ""
+"En em enskrivañ ez emgefre d'an holl re hag en em goumanant din (erbedet "
+"evit an implijerien nann-denel)"
 
 #: actions/profilesettings.php:228 actions/register.php:223
 #, php-format
@@ -2886,7 +2894,7 @@ msgstr "Balizenn direizh : \"%s\""
 
 #: actions/profilesettings.php:306
 msgid "Couldn't update user for autosubscribe."
-msgstr ""
+msgstr "Dibosupl eo hizivaat ar c'houmanant ez emgefre."
 
 #: actions/profilesettings.php:363
 msgid "Couldn't save location prefs."
@@ -2912,16 +2920,16 @@ msgstr "Dreist da bevennoù ar bajenn (%s)."
 
 #: actions/public.php:92
 msgid "Could not retrieve public stream."
-msgstr ""
+msgstr "Dibosupl eo adtapout al lanv foran."
 
 #: actions/public.php:130
 #, php-format
 msgid "Public timeline, page %d"
-msgstr ""
+msgstr "Lanv foran - pajenn %d"
 
 #: actions/public.php:132 lib/publicgroupnav.php:79
 msgid "Public timeline"
-msgstr ""
+msgstr "Lanv foran"
 
 #: actions/public.php:160
 msgid "Public Stream Feed (RSS 1.0)"
@@ -2941,6 +2949,7 @@ msgid ""
 "This is the public timeline for %%site.name%% but no one has posted anything "
 "yet."
 msgstr ""
+"Kronologiezh foran %%site.name%% eo, met den n'en deus skrivet tra ebet."
 
 #: actions/public.php:191
 msgid "Be the first to post!"
@@ -2951,6 +2960,8 @@ msgstr "Bezit an hini gentañ da bostañ !"
 msgid ""
 "Why not [register an account](%%action.register%%) and be the first to post!"
 msgstr ""
+"Perak ne [groufec'h ket ur gont](%%action.register%%) ha bezañ an hini "
+"gentañ da embann un dra !"
 
 #: actions/public.php:242
 #, php-format
@@ -2968,10 +2979,12 @@ msgid ""
 "blogging) service based on the Free Software [StatusNet](http://status.net/) "
 "tool."
 msgstr ""
+"%%site.name%% a zo ur servij [micro-blogging](http://br.wikipedia.org/wiki/"
+"Microblog) diazezet war ar meziant frank [StatusNet](http://status.net/)."
 
 #: actions/publictagcloud.php:57
 msgid "Public tag cloud"
-msgstr ""
+msgstr "Koumoulenn a merkoù foran"
 
 #: actions/publictagcloud.php:63
 #, php-format
@@ -2993,10 +3006,12 @@ msgid ""
 "Why not [register an account](%%action.register%%) and be the first to post "
 "one!"
 msgstr ""
+"Perak ne [groufec'h ket ur gont](%%action.register%%) ha bezañ an hini "
+"gentañ da embann un dra !"
 
 #: actions/publictagcloud.php:134
 msgid "Tag cloud"
-msgstr ""
+msgstr "Koumoulenn merkoù"
 
 #: actions/recoverpassword.php:36
 msgid "You are already logged in!"
@@ -3024,17 +3039,19 @@ msgstr "Re gozh eo ar c'hod gwiriañ. Adkrogit mar plij."
 
 #: actions/recoverpassword.php:111
 msgid "Could not update user with confirmed email address."
-msgstr ""
+msgstr "Dibosupl eo hizivaat an implijer gant ar chomlec'h postel gwiriekaet."
 
 #: actions/recoverpassword.php:152
 msgid ""
 "If you have forgotten or lost your password, you can get a new one sent to "
 "the email address you have stored in your account."
 msgstr ""
+"M'o peus disoñjet pe kollet ho ger-tremen, e c'helloc'h kaout unan nevez hag "
+"a vo kaset deoc'h d'ar chomlec'h postel termenet en ho kont."
 
 #: actions/recoverpassword.php:158
 msgid "You have been identified. Enter a new password below. "
-msgstr ""
+msgstr "Diskleriet oc'h bet. Lakait ur ger-tremen nevez amañ da heul. "
 
 #: actions/recoverpassword.php:188
 msgid "Password recovery"
@@ -3046,7 +3063,7 @@ msgstr "Lesanv pe chomlec'h postel"
 
 #: actions/recoverpassword.php:193
 msgid "Your nickname on this server, or your registered email address."
-msgstr ""
+msgstr "Ho lesanv war ar servijer-mañ, pe ar chomlec'h postel o peus enrollet."
 
 #: actions/recoverpassword.php:199 actions/recoverpassword.php:200
 msgid "Recover"
@@ -3097,10 +3114,12 @@ msgid ""
 "Instructions for recovering your password have been sent to the email "
 "address registered to your account."
 msgstr ""
+"Kaset eo bet deoc'h, d'ar chomlec'h postel termenet en ho kont, an titouroù "
+"ret evit gouzout penaos adtapout o ger-tremen."
 
 #: actions/recoverpassword.php:357
 msgid "Unexpected password reset."
-msgstr ""
+msgstr "Adderaouekadur dic'hortoz ar ger-tremen."
 
 #: actions/recoverpassword.php:365
 msgid "Password must be 6 chars or more."
@@ -3217,6 +3236,8 @@ msgid ""
 "(You should receive a message by email momentarily, with instructions on how "
 "to confirm your email address.)"
 msgstr ""
+"(Resevout a reoc'h a-benn nebeut ur postel gant an titouroù evit kadarnaat "
+"ho chomlec'h.)"
 
 #: actions/remotesubscribe.php:98
 #, php-format
@@ -3265,7 +3286,7 @@ msgstr ""
 
 #: actions/remotesubscribe.php:176
 msgid "That’s a local profile! Login to subscribe."
-msgstr ""
+msgstr "Lec'hel eo ar profil-mañ ! Kevreit evit koumananti."
 
 #: actions/remotesubscribe.php:183
 msgid "Couldn’t get a request token."
@@ -3461,11 +3482,11 @@ msgstr "Sekred an implijer"
 
 #: actions/showapplication.php:273
 msgid "Request token URL"
-msgstr ""
+msgstr "URL ar jedouer reked"
 
 #: actions/showapplication.php:278
 msgid "Access token URL"
-msgstr ""
+msgstr "URL ar jedouer moned"
 
 #: actions/showapplication.php:283
 msgid "Authorize URL"
@@ -3480,6 +3501,7 @@ msgstr ""
 #: actions/showapplication.php:309
 msgid "Are you sure you want to reset your consumer key and secret?"
 msgstr ""
+"Ha sur oc'h o peus c'hoant adderaouekaat ho alc'hwez bevezer ha sekred ?"
 
 #: actions/showfavorites.php:79
 #, php-format
@@ -4614,7 +4636,7 @@ msgstr "Ur gudenn 'zo bet pa veze enrollet boest degemer ar strollad."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -4908,7 +4930,7 @@ msgstr ""
 #: lib/action.php:820
 #, php-format
 msgid "**%%site.name%%** is a microblogging service."
-msgstr ""
+msgstr "**%%site.name%%** a zo ur servij microblogging."
 
 #. TRANS: Second sentence of the StatusNet site license. Mentions the StatusNet source code license.
 #: lib/action.php:824
@@ -4967,7 +4989,7 @@ msgid "Before"
 msgstr "Kent"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -4975,11 +4997,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -5532,7 +5554,7 @@ msgstr ""
 
 #: lib/connectsettingsaction.php:116
 msgid "Updates by SMS"
-msgstr ""
+msgstr "Hizivadennoù dre SMS"
 
 #: lib/connectsettingsaction.php:120
 msgid "Connections"
@@ -5759,7 +5781,7 @@ msgstr "Digeriñ ur gont nevez"
 #. TRANS: Subject for address confirmation email
 #: lib/mail.php:174
 msgid "Email address confirmation"
-msgstr ""
+msgstr "Kadarnadur ar chomlec'h postel"
 
 #. TRANS: Body for address confirmation email.
 #: lib/mail.php:177
@@ -5811,7 +5833,7 @@ msgstr ""
 #: lib/mail.php:298
 #, php-format
 msgid "New email address for posting to %s"
-msgstr ""
+msgstr "Chomlec'h postel nevez evit embann e %s"
 
 #. TRANS: Body of notification mail for new posting email address
 #: lib/mail.php:302
@@ -6018,7 +6040,7 @@ msgstr ""
 
 #: lib/mediafile.php:159
 msgid "Missing a temporary folder."
-msgstr ""
+msgstr "Mankout a ra un doser padennek."
 
 #: lib/mediafile.php:162
 msgid "Failed to write file to disk."
@@ -6216,7 +6238,7 @@ msgstr "Ar c'hemenadennoù kaset ganeoc'h"
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Dianav"
 
index 7b59c0ef44aa233bf58a8c9bc7c8b6f7381b998a..b12c03a1ce6fa66a3d90c6b11550fb17d2361d77 100644 (file)
@@ -12,11 +12,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:15+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:30+0000\n"
 "Language-Team: Catalan\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: ca\n"
 "X-Message-Group: out-statusnet\n"
@@ -166,6 +166,8 @@ msgid ""
 "Try subscribing to more people, [join a group](%%action.groups%%) or post "
 "something yourself."
 msgstr ""
+"Proveu de subscriure més gent, [uniu-vos a un grup](%%action.groups%%) o "
+"envieu quelcom personal."
 
 #. TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@"
 #: actions/all.php:142
@@ -239,9 +241,10 @@ msgid ""
 "You must specify a parameter named 'device' with a value of one of: sms, im, "
 "none."
 msgstr ""
+"Heu d'especificar un paràmetre anomenat 'device' (dispositiu) amb un valor "
+"dels següents: sms, im, none (cap)"
 
 #: actions/apiaccountupdatedeliverydevice.php:132
-#, fuzzy
 msgid "Could not update user."
 msgstr "No s'ha pogut actualitzar l'usuari."
 
@@ -256,9 +259,8 @@ msgid "User has no profile."
 msgstr "L'usuari no té perfil."
 
 #: actions/apiaccountupdateprofile.php:147
-#, fuzzy
 msgid "Could not save profile."
-msgstr "No s'ha pogut guardar el perfil."
+msgstr "No s'ha pogut desar el perfil."
 
 #: actions/apiaccountupdateprofilebackgroundimage.php:108
 #: actions/apiaccountupdateprofileimage.php:97 actions/apimediaupload.php:80
@@ -271,6 +273,8 @@ msgid ""
 "The server was unable to handle that much POST data (%s bytes) due to its "
 "current configuration."
 msgstr ""
+"El servidor no ha pogut gestionar tantes dades POST (%s bytes) a causa de la "
+"configuració actual."
 
 #: actions/apiaccountupdateprofilebackgroundimage.php:136
 #: actions/apiaccountupdateprofilebackgroundimage.php:146
@@ -279,15 +283,13 @@ msgstr ""
 #: actions/groupdesignsettings.php:290 actions/groupdesignsettings.php:300
 #: actions/userdesignsettings.php:210 actions/userdesignsettings.php:220
 #: actions/userdesignsettings.php:263 actions/userdesignsettings.php:273
-#, fuzzy
 msgid "Unable to save your design settings."
-msgstr "No s'ha pogut guardar la teva configuració de Twitter!"
+msgstr "No s'han pogut desar els paràmetres de disseny."
 
 #: actions/apiaccountupdateprofilebackgroundimage.php:187
 #: actions/apiaccountupdateprofilecolors.php:142
-#, fuzzy
 msgid "Could not update your design."
-msgstr "No s'ha pogut actualitzar l'usuari."
+msgstr "No s'ha pogut actualitzar el vostre disseny."
 
 #: actions/apiblockcreate.php:105
 msgid "You cannot block yourself!"
@@ -388,9 +390,8 @@ msgid "Could not determine source user."
 msgstr "No s'ha pogut determinar l'usuari d'origen."
 
 #: actions/apifriendshipsshow.php:142
-#, fuzzy
 msgid "Could not find target user."
-msgstr "No es pot trobar cap estatus."
+msgstr "No s'ha pogut trobar l'usuari de destinació."
 
 #: actions/apigroupcreate.php:166 actions/editgroup.php:186
 #: actions/newgroup.php:126 actions/profilesettings.php:215
@@ -513,12 +514,11 @@ msgstr "grups sobre %s"
 
 #: actions/apioauthauthorize.php:101
 msgid "No oauth_token parameter provided."
-msgstr ""
+msgstr "No s'ha proporcionat cap paràmetre oauth_token."
 
 #: actions/apioauthauthorize.php:106
-#, fuzzy
 msgid "Invalid token."
-msgstr "Mida invàlida."
+msgstr "El testimoni no és vàlid."
 
 #: actions/apioauthauthorize.php:123 actions/avatarsettings.php:268
 #: actions/deletenotice.php:169 actions/disfavor.php:74
@@ -665,7 +665,7 @@ msgstr "No s'ha trobat."
 #: actions/apistatusesupdate.php:316 actions/newnotice.php:178
 #, php-format
 msgid "Max notice size is %d chars, including attachment URL."
-msgstr ""
+msgstr "La mida màxima de l'avís és %d caràcters, incloent l'URL de l'adjunt."
 
 #: actions/apisubscriptions.php:231 actions/apisubscriptions.php:261
 msgid "Unsupported format."
@@ -677,14 +677,14 @@ msgid "%1$s / Favorites from %2$s"
 msgstr "%1$s / Preferits de %2$s"
 
 #: actions/apitimelinefavorites.php:118
-#, fuzzy, php-format
+#, php-format
 msgid "%1$s updates favorited by %2$s / %2$s."
-msgstr "%s actualitzacions favorites per %s / %s."
+msgstr "%1$s actualitzacions preferides per %2$s / %2$s."
 
 #: actions/apitimelinementions.php:117
-#, fuzzy, php-format
+#, php-format
 msgid "%1$s / Updates mentioning %2$s"
-msgstr "%1$s / Notificacions contestant a %2$s"
+msgstr "%1$s / Actualitzacions que mencionen %2$s"
 
 #: actions/apitimelinementions.php:130
 #, php-format
@@ -1075,6 +1075,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 ""
+"Esteu segur que voleu suprimir l'usuari? S'esborraran totes les dades de "
+"l'usuari de la base de dades, sense cap còpia de seguretat."
 
 #. TRANS: Submit button title for 'Yes' when deleting a user.
 #: actions/deleteuser.php:163 lib/deleteuserform.php:77
@@ -1278,9 +1280,8 @@ msgid "Callback URL is not valid."
 msgstr ""
 
 #: actions/editapplication.php:258
-#, fuzzy
 msgid "Could not update application."
-msgstr "No s'ha pogut actualitzar el grup."
+msgstr "No s'ha pogut actualitzar l'aplicació."
 
 #: actions/editgroup.php:56
 #, php-format
@@ -1293,9 +1294,8 @@ msgstr "Has d'haver entrat per crear un grup."
 
 #: actions/editgroup.php:107 actions/editgroup.php:172
 #: actions/groupdesignsettings.php:107 actions/grouplogo.php:109
-#, fuzzy
 msgid "You must be an admin to edit the group."
-msgstr "Has de ser admin per editar aquest grup"
+msgstr "Heu de ser administrador per a editar el grup."
 
 #: actions/editgroup.php:158
 msgid "Use this form to edit the group."
@@ -1671,9 +1671,8 @@ msgid "Could not convert request token to access token."
 msgstr "No s'han pogut convertir els senyals de petició a senyals d'accés."
 
 #: actions/finishremotesubscribe.php:118
-#, fuzzy
 msgid "Remote service uses unknown version of OMB protocol."
-msgstr "Versió desconeguda del protocol OMB."
+msgstr "El servei remot utilitza una versió desconeguda del protocol OMB."
 
 #: actions/finishremotesubscribe.php:138
 msgid "Error updating remote profile."
@@ -1887,13 +1886,13 @@ msgid "Create a new group"
 msgstr "Crea un grup nou"
 
 #: actions/groupsearch.php:52
-#, fuzzy, php-format
+#, php-format
 msgid ""
 "Search for groups on %%site.name%% by their name, location, or description. "
 "Separate the terms by spaces; they must be 3 characters or more."
 msgstr ""
-"Troba gent a %%site.name%% per nom, ubicació o interessos. Separa els termes "
-"de cerca amb espais; han de ser majors a 3 caràcters."
+"Cerca grups a %%site.name%% per nom, ubicació o descripció. Separeu els "
+"termes de cerca amb espais; han de contenir com a mínim 3 caràcters."
 
 #: actions/groupsearch.php:58
 msgid "Group search"
@@ -2061,9 +2060,8 @@ msgstr "Aquesta adreça de missatgeria instantània és incorrecta."
 
 #. TRANS: Server error thrown on database error canceling IM address confirmation.
 #: actions/imsettings.php:397
-#, fuzzy
 msgid "Couldn't delete IM confirmation."
-msgstr "No s'ha pogut eliminar la confirmació de correu electrònic."
+msgstr "No s'ha pogut suprimir la confirmació de MI."
 
 #. TRANS: Message given after successfully canceling IM address confirmation.
 #: actions/imsettings.php:402
@@ -2082,9 +2080,9 @@ msgid "The IM address was removed."
 msgstr "S'ha suprimit l'adreça de MI."
 
 #: actions/inbox.php:59
-#, fuzzy, php-format
+#, php-format
 msgid "Inbox for %1$s - page %2$d"
-msgstr "Safata d'entrada per %s"
+msgstr "Safata d'entrada per a %1$s - pàgina %2$d"
 
 #: actions/inbox.php:62
 #, php-format
@@ -2102,11 +2100,10 @@ msgid "Invites have been disabled."
 msgstr "S'han inhabilitat les invitacions."
 
 #: actions/invite.php:41
-#, fuzzy, php-format
+#, php-format
 msgid "You must be logged in to invite other users to use %s."
 msgstr ""
-"Has d'estar dins del servei per poder convidar altres usuaris a utilitzar-lo "
-"%s"
+"Heu d'haver iniciat una sessió per a convidar altres usuaris a utilitzar %s"
 
 #: actions/invite.php:72
 #, php-format
@@ -2181,9 +2178,9 @@ msgstr "Envia"
 
 #. TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English.
 #: actions/invite.php:228
-#, fuzzy, php-format
+#, php-format
 msgid "%1$s has invited you to join them on %2$s"
-msgstr "%1$s t'ha convidat us ha convidat a unir-te al grup %2$s"
+msgstr "%1$s us ha convidat a unir-vos al grup %2$s"
 
 #. TRANS: Body text for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English.
 #: actions/invite.php:231
@@ -2322,13 +2319,12 @@ msgid "Login with your username and password."
 msgstr "Inicieu una sessió amb nom d'usuari i contrasenya"
 
 #: actions/login.php:273
-#, fuzzy, php-format
+#, php-format
 msgid ""
 "Don't have a username yet? [Register](%%action.register%%) a new account."
 msgstr ""
-"Inicia una sessió amb el teu nom d'usuari i la teva contrasenya. Encara no "
-"tens un nom d'usuari? [Crea](%%action.register%%) un nou compte o prova "
-"[OpenID] (%%action.openidlogin%%)."
+"No teniu cap nom d'usuari encara? [Registreu-hi](%%action.register%%) un nou "
+"compte."
 
 #: actions/makeadmin.php:92
 msgid "Only an admin can make another user an admin."
@@ -2340,14 +2336,14 @@ msgid "%1$s is already an admin for group \"%2$s\"."
 msgstr "%1$s ja és un administrador del grup «%2$s»."
 
 #: actions/makeadmin.php:133
-#, fuzzy, php-format
+#, php-format
 msgid "Can't get membership record for %1$s in group %2$s."
-msgstr "No s'ha pogut eliminar l'usuari %s del grup %s"
+msgstr "No s'ha pogut obtenir el registre de pertinència de %1$s al grup %2$s."
 
 #: actions/makeadmin.php:146
-#, fuzzy, php-format
+#, php-format
 msgid "Can't make %1$s an admin for group %2$s."
-msgstr "No es pot fer %s un administrador del grup %s"
+msgstr "No es pot fer %1$s administrador del grup %2$s."
 
 #: actions/microsummary.php:69
 msgid "No current status."
@@ -2358,9 +2354,8 @@ msgid "New Application"
 msgstr "Nova Aplicació"
 
 #: actions/newapplication.php:64
-#, fuzzy
 msgid "You must be logged in to register an application."
-msgstr "Has d'haver entrat per crear un grup."
+msgstr "Heu d'haver iniciat una sessió per a registrar-hi una aplicació."
 
 #: actions/newapplication.php:143
 msgid "Use this form to register a new application."
@@ -2484,9 +2479,8 @@ msgid "Nudge sent!"
 msgstr "Reclamació enviada!"
 
 #: actions/oauthappssettings.php:59
-#, fuzzy
 msgid "You must be logged in to list your applications."
-msgstr "Heu d'iniciar una sessió per editar un grup."
+msgstr "Heu d'haver iniciat una sessió per a llistar les vostres aplicacions."
 
 #: actions/oauthappssettings.php:74
 msgid "OAuth applications"
@@ -2537,9 +2531,9 @@ msgstr "estat de %1$s a %2$s"
 
 #. TRANS: Error message displaying attachments. %s is a raw MIME type (eg 'image/png')
 #: actions/oembed.php:158
-#, fuzzy, php-format
+#, php-format
 msgid "Content type %s not supported."
-msgstr "tipus de contingut "
+msgstr "El tipus de contingut %s no està permès."
 
 #. TRANS: Error message displaying attachments. %s is the site's base URL.
 #: actions/oembed.php:162
@@ -2867,9 +2861,9 @@ msgid "Not a valid people tag: %s."
 msgstr "Etiqueta no vàlida per a la gent: %s"
 
 #: actions/peopletag.php:142
-#, fuzzy, php-format
+#, php-format
 msgid "Users self-tagged with %1$s - page %2$d"
-msgstr "Usuaris que s'han etiquetat %s - pàgina %d"
+msgstr "Usuaris que s'han etiquetat amb %1$s - pàgina %2$d"
 
 #: actions/postnotice.php:95
 msgid "Invalid notice content."
@@ -3422,14 +3416,12 @@ msgid "Couldn’t get a request token."
 msgstr "No s'ha pogut obtenir un senyal de petició."
 
 #: actions/repeat.php:57
-#, fuzzy
 msgid "Only logged-in users can repeat notices."
-msgstr "Només l'usuari pot llegir les seves safates de correu."
+msgstr "Només els usuaris que han iniciat una sessió poden enviar avisos."
 
 #: actions/repeat.php:64 actions/repeat.php:71
-#, fuzzy
 msgid "No notice specified."
-msgstr "No s'ha especificat perfil."
+msgstr "No s'ha especificat cap avís."
 
 #: actions/repeat.php:76
 #, fuzzy
@@ -3460,14 +3452,14 @@ msgid "Replies to %1$s, page %2$d"
 msgstr "Respostes a %1$s, pàgina %2$d"
 
 #: actions/replies.php:145
-#, fuzzy, php-format
+#, php-format
 msgid "Replies feed for %s (RSS 1.0)"
-msgstr "Feed d'avisos de %s"
+msgstr "Canal de respostes de %s (RSS 1.0)"
 
 #: actions/replies.php:152
-#, fuzzy, php-format
+#, php-format
 msgid "Replies feed for %s (RSS 2.0)"
-msgstr "Feed d'avisos de %s"
+msgstr "Canal de respostes de %s (RSS 2.0)"
 
 #: actions/replies.php:159
 #, php-format
@@ -3609,7 +3601,7 @@ msgstr ""
 
 #: actions/showapplication.php:261
 msgid "Application info"
-msgstr ""
+msgstr "Informació de l'aplicació"
 
 #: actions/showapplication.php:263
 msgid "Consumer key"
@@ -3724,19 +3716,19 @@ msgid "Group actions"
 msgstr "Accions del grup"
 
 #: actions/showgroup.php:338
-#, fuzzy, php-format
+#, php-format
 msgid "Notice feed for %s group (RSS 1.0)"
-msgstr "Feed d'avisos del grup %s"
+msgstr "Canal d'avisos del grup %s (RSS 1.0)"
 
 #: actions/showgroup.php:344
-#, fuzzy, php-format
+#, php-format
 msgid "Notice feed for %s group (RSS 2.0)"
-msgstr "Feed d'avisos del grup %s"
+msgstr "Canal d'avisos del grup %s (RSS 2.0)"
 
 #: actions/showgroup.php:350
-#, fuzzy, php-format
+#, php-format
 msgid "Notice feed for %s group (Atom)"
-msgstr "Feed d'avisos del grup %s"
+msgstr "Canal d'avisos del grup %s (Atom)"
 
 #: actions/showgroup.php:355
 #, php-format
@@ -4003,9 +3995,8 @@ msgid "Site Notice"
 msgstr "Avís del lloc"
 
 #: actions/sitenoticeadminpanel.php:67
-#, fuzzy
 msgid "Edit site-wide message"
-msgstr "Nou missatge"
+msgstr "Edita el missatge per a tot el lloc"
 
 #: actions/sitenoticeadminpanel.php:103
 msgid "Unable to save site notice."
@@ -4073,10 +4064,9 @@ msgstr "Escriu el codi que has rebut en el teu telèfon mòbil."
 
 #. TRANS: Button label to confirm SMS confirmation code in SMS settings.
 #: actions/smssettings.php:148
-#, fuzzy
 msgctxt "BUTTON"
 msgid "Confirm"
-msgstr "Confirmar"
+msgstr "Confirma"
 
 #. TRANS: Field label for SMS phone number input in SMS settings form.
 #: actions/smssettings.php:153
@@ -4090,9 +4080,8 @@ msgstr "Número de telèfon, no puntuació ni espais, en l'àrea del codi"
 
 #. TRANS: Form legend for SMS preferences form.
 #: actions/smssettings.php:195
-#, fuzzy
 msgid "SMS preferences"
-msgstr "Preferències"
+msgstr "Preferències de l'SMS"
 
 #. TRANS: Checkbox label in SMS preferences form.
 #: actions/smssettings.php:201
@@ -4105,9 +4094,8 @@ msgstr ""
 
 #. TRANS: Confirmation message for successful SMS preferences save.
 #: actions/smssettings.php:315
-#, fuzzy
 msgid "SMS preferences saved."
-msgstr "S'han desat les preferències."
+msgstr "S'han desat les preferències de l'SMS."
 
 #. TRANS: Message given saving SMS phone number without having provided one.
 #: actions/smssettings.php:338
@@ -4263,9 +4251,8 @@ msgid "This action only accepts POST requests."
 msgstr ""
 
 #: actions/subscribe.php:107
-#, fuzzy
 msgid "No such profile."
-msgstr "No existeix el fitxer."
+msgstr "No existeix el perfil."
 
 #: actions/subscribe.php:117
 #, fuzzy
@@ -4282,9 +4269,9 @@ msgid "%s subscribers"
 msgstr "%s subscriptors"
 
 #: actions/subscribers.php:52
-#, fuzzy, php-format
+#, php-format
 msgid "%1$s subscribers, page %2$d"
-msgstr "%s subscriptors, pàgina %d"
+msgstr "%1$s subscriptors, pàgina %2$d"
 
 #: actions/subscribers.php:63
 msgid "These are the people who listen to your notices."
@@ -4685,9 +4672,9 @@ msgid "Updates from %1$s on %2$s!"
 msgstr "Actualitzacions de %1$s a %2$s!"
 
 #: actions/version.php:73
-#, fuzzy, php-format
+#, php-format
 msgid "StatusNet %s"
-msgstr "Estadístiques"
+msgstr "StatusNet %s"
 
 #: actions/version.php:153
 #, php-format
@@ -4729,12 +4716,10 @@ msgstr "Connectors"
 
 #. TRANS: Secondary navigation menu option leading to version information on the StatusNet site.
 #: actions/version.php:196 lib/action.php:779
-#, fuzzy
 msgid "Version"
-msgstr "Sessions"
+msgstr "Versió"
 
 #: actions/version.php:197
-#, fuzzy
 msgid "Author(s)"
 msgstr "Autoria"
 
@@ -4756,19 +4741,16 @@ msgid "A file this large would exceed your monthly quota of %d bytes."
 msgstr ""
 
 #: classes/Group_member.php:41
-#, fuzzy
 msgid "Group join failed."
-msgstr "Perfil del grup"
+msgstr "No s'ha pogut unir al grup."
 
 #: classes/Group_member.php:53
-#, fuzzy
 msgid "Not part of group."
-msgstr "No s'ha pogut actualitzar el grup."
+msgstr "No s'és part del grup."
 
 #: classes/Group_member.php:60
-#, fuzzy
 msgid "Group leave failed."
-msgstr "Perfil del grup"
+msgstr "La sortida del grup ha fallat."
 
 #: classes/Local_group.php:41
 #, fuzzy
@@ -4837,7 +4819,7 @@ msgstr "Problema en guardar l'avís."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -4917,9 +4899,8 @@ msgstr "Canvieu la gestió del correu"
 
 #. TRANS: Link title attribute in user account settings menu.
 #: lib/accountsettingsaction.php:137
-#, fuzzy
 msgid "Design your profile"
-msgstr "Perfil de l'usuari"
+msgstr "Dissenyeu el vostre perfil"
 
 #. TRANS: Link title attribute in user account settings menu.
 #: lib/accountsettingsaction.php:144
@@ -4967,10 +4948,9 @@ msgstr "Canvia l'adreça electrònica, l'avatar, la contrasenya o el perfil"
 
 #. TRANS: Tooltip for main menu option "Services"
 #: lib/action.php:442
-#, fuzzy
 msgctxt "TOOLTIP"
 msgid "Connect to services"
-msgstr "No s'ha pogut redirigir al servidor: %s"
+msgstr "Connecta als serveis"
 
 #. TRANS: Main menu option when logged in and connection are possible for access to options to connect to other services
 #: lib/action.php:445
@@ -4979,63 +4959,55 @@ msgstr "Connexió"
 
 #. TRANS: Tooltip for menu option "Admin"
 #: lib/action.php:448
-#, fuzzy
 msgctxt "TOOLTIP"
 msgid "Change site configuration"
 msgstr "Canvia la configuració del lloc"
 
 #. TRANS: Main menu option when logged in and site admin for access to site configuration
 #: lib/action.php:451
-#, fuzzy
 msgctxt "MENU"
 msgid "Admin"
-msgstr "Admin"
+msgstr "Administrador"
 
 #. TRANS: Tooltip for main menu option "Invite"
 #: lib/action.php:455
-#, fuzzy, php-format
+#, php-format
 msgctxt "TOOLTIP"
 msgid "Invite friends and colleagues to join you on %s"
-msgstr "Convidar amics i companys perquè participin a %s"
+msgstr "Convida amics i coneguts perquè participin a %s"
 
 #. TRANS: Main menu option when logged in and invitations are allowed for inviting new users
 #: lib/action.php:458
-#, fuzzy
 msgctxt "MENU"
 msgid "Invite"
 msgstr "Convida"
 
 #. TRANS: Tooltip for main menu option "Logout"
 #: lib/action.php:464
-#, fuzzy
 msgctxt "TOOLTIP"
 msgid "Logout from the site"
 msgstr "Finalitza la sessió del lloc"
 
 #. TRANS: Main menu option when logged in to log out the current user
 #: lib/action.php:467
-#, fuzzy
 msgctxt "MENU"
 msgid "Logout"
 msgstr "Finalitza la sessió"
 
 #. TRANS: Tooltip for main menu option "Register"
 #: lib/action.php:472
-#, fuzzy
 msgctxt "TOOLTIP"
 msgid "Create an account"
 msgstr "Crea un compte"
 
 #. TRANS: Main menu option when not logged in to register a new account
 #: lib/action.php:475
-#, fuzzy
 msgctxt "MENU"
 msgid "Register"
 msgstr "Registre"
 
 #. TRANS: Tooltip for main menu option "Login"
 #: lib/action.php:478
-#, fuzzy
 msgctxt "TOOLTIP"
 msgid "Login to the site"
 msgstr "Inicia una sessió al lloc"
@@ -5208,7 +5180,7 @@ msgid "Before"
 msgstr "Anteriors"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5216,11 +5188,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -5261,7 +5233,6 @@ msgstr "Configuració bàsica del lloc"
 
 #. TRANS: Menu item for site administration
 #: lib/adminpanelaction.php:351
-#, fuzzy
 msgctxt "MENU"
 msgid "Site"
 msgstr "Lloc"
@@ -5273,16 +5244,14 @@ msgstr "Configuració del disseny"
 
 #. TRANS: Menu item for site administration
 #: lib/adminpanelaction.php:359
-#, fuzzy
 msgctxt "MENU"
 msgid "Design"
 msgstr "Disseny"
 
 #. TRANS: Menu item title/tooltip
 #: lib/adminpanelaction.php:365
-#, fuzzy
 msgid "User configuration"
-msgstr "Configuració dels camins"
+msgstr "Configuració de l'usuari"
 
 #. TRANS: Menu item for site administration
 #: lib/adminpanelaction.php:367 lib/personalgroupnav.php:115
@@ -5291,9 +5260,8 @@ msgstr "Usuari"
 
 #. TRANS: Menu item title/tooltip
 #: lib/adminpanelaction.php:373
-#, fuzzy
 msgid "Access configuration"
-msgstr "Configuració del disseny"
+msgstr "Configuració de l'accés"
 
 #. TRANS: Menu item title/tooltip
 #: lib/adminpanelaction.php:381
@@ -5302,9 +5270,8 @@ msgstr "Configuració dels camins"
 
 #. TRANS: Menu item title/tooltip
 #: lib/adminpanelaction.php:389
-#, fuzzy
 msgid "Sessions configuration"
-msgstr "Configuració del disseny"
+msgstr "Configuració de les sessions"
 
 #. TRANS: Menu item title/tooltip
 #: lib/adminpanelaction.php:397
@@ -5326,36 +5293,33 @@ msgstr ""
 #. TRANS: Form legend.
 #: lib/applicationeditform.php:137
 msgid "Edit application"
-msgstr ""
+msgstr "Edita l'aplicació"
 
 #. TRANS: Form guide.
 #: lib/applicationeditform.php:187
 msgid "Icon for this application"
-msgstr ""
+msgstr "Icona de l'aplicació"
 
 #. TRANS: Form input field instructions.
 #: lib/applicationeditform.php:209
-#, fuzzy, php-format
+#, php-format
 msgid "Describe your application in %d characters"
-msgstr "Descriu el grup amb 140 caràcters"
+msgstr "Descriviu la vostra aplicació en %d caràcters"
 
 #. TRANS: Form input field instructions.
 #: lib/applicationeditform.php:213
-#, fuzzy
 msgid "Describe your application"
-msgstr "Descriu el grup amb 140 caràcters"
+msgstr "Descriviu la vostra aplicació"
 
 #. TRANS: Form input field instructions.
 #: lib/applicationeditform.php:224
-#, fuzzy
 msgid "URL of the homepage of this application"
-msgstr "URL del teu web, blog del grup u tema"
+msgstr "URL de la pàgina d'inici de l'aplicació"
 
 #. TRANS: Form input field label.
 #: lib/applicationeditform.php:226
-#, fuzzy
 msgid "Source URL"
-msgstr "Font"
+msgstr "URL d'origen"
 
 #. TRANS: Form input field instructions.
 #: lib/applicationeditform.php:233
@@ -5376,32 +5340,33 @@ msgstr ""
 #. TRANS: Radio button label for application type
 #: lib/applicationeditform.php:278
 msgid "Browser"
-msgstr ""
+msgstr "Navegador"
 
 #. TRANS: Radio button label for application type
 #: lib/applicationeditform.php:295
 msgid "Desktop"
-msgstr ""
+msgstr "Escriptori"
 
 #. TRANS: Form guide.
 #: lib/applicationeditform.php:297
 msgid "Type of application, browser or desktop"
-msgstr ""
+msgstr "Tipus d'aplicació, navegador o escriptori"
 
 #. TRANS: Radio button label for access type.
 #: lib/applicationeditform.php:320
 msgid "Read-only"
-msgstr ""
+msgstr "Només lectura"
 
 #. TRANS: Radio button label for access type.
 #: lib/applicationeditform.php:339
 msgid "Read-write"
-msgstr ""
+msgstr "Lectura i escriptura"
 
 #. TRANS: Form guide.
 #: lib/applicationeditform.php:341
 msgid "Default access for this application: read-only, or read-write"
 msgstr ""
+"Accés per defecte per a l'aplicació: només lectura, o lectura i escriptura"
 
 #. TRANS: Submit button title
 #: lib/applicationeditform.php:359
@@ -5411,25 +5376,24 @@ msgstr "Cancel·la"
 #. TRANS: Application access type
 #: lib/applicationlist.php:136
 msgid "read-write"
-msgstr ""
+msgstr "lectura i escriptura"
 
 #. TRANS: Application access type
 #: lib/applicationlist.php:138
 msgid "read-only"
-msgstr ""
+msgstr "només lectura"
 
 #. TRANS: Used in application list. %1$s is a modified date, %2$s is access type (read-write or read-only)
 #: lib/applicationlist.php:144
 #, php-format
 msgid "Approved %1$s - \"%2$s\" access."
-msgstr ""
+msgstr "Aprovat: %1$s - accés «%2$s»."
 
 #. TRANS: Button label
 #: lib/applicationlist.php:159
-#, fuzzy
 msgctxt "BUTTON"
 msgid "Revoke"
-msgstr "Suprimeix"
+msgstr "Revoca"
 
 #. TRANS: DT element label in attachment list.
 #: lib/attachmentlist.php:88
@@ -5448,7 +5412,7 @@ msgstr "Proveïdor"
 
 #: lib/attachmentnoticesection.php:67
 msgid "Notices where this attachment appears"
-msgstr ""
+msgstr "Avisos on apareix l'adjunt"
 
 #: lib/attachmenttagcloudsection.php:48
 msgid "Tags for this attachment"
@@ -5509,9 +5473,9 @@ msgstr ""
 #. TRANS: Message given having nudged another user.
 #. TRANS: %s is the nickname of the user that was nudged.
 #: lib/command.php:234
-#, fuzzy, php-format
+#, php-format
 msgid "Nudge sent to %s"
-msgstr "Reclamació enviada"
+msgstr "S'ha enviat un avís a %s"
 
 #: lib/command.php:260
 #, php-format
@@ -5520,6 +5484,9 @@ msgid ""
 "Subscribers: %2$s\n"
 "Notices: %3$s"
 msgstr ""
+"Subscripcions: %1$s\n"
+"Subscriptors: %2$s\n"
+"Avisos: %3$s"
 
 #: lib/command.php:302
 msgid "Notice marked as fave."
@@ -5539,7 +5506,7 @@ msgstr "No s'ha pogut afegir l'usuari %1$s al grup %2$s."
 #. TRANS: Message given having failed to remove a user from a group.
 #. TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
 #: lib/command.php:385
-#, fuzzy, php-format
+#, php-format
 msgid "Could not remove user %1$s from group %2$s"
 msgstr "No s'ha pogut suprimir l'usuari %1$s del grup %2$s."
 
@@ -5575,13 +5542,16 @@ msgid ""
 "%s is a remote profile; you can only send direct messages to users on the "
 "same server."
 msgstr ""
+"%s és un perfil remot; només podeu enviar missatges directess a usuaris del "
+"mateix servidor."
 
 #. TRANS: Message given if content is too long.
 #. TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
 #: lib/command.php:472
-#, fuzzy, php-format
+#, php-format
 msgid "Message too long - maximum is %1$d characters, you sent %2$d"
-msgstr "Missatge massa llarg - màxim és 140 caràcters, tu has enviat %d"
+msgstr ""
+"El missatge és massa llarg - el màxim és %1$d caràcters, i n'heu enviat %2$d"
 
 #. TRANS: Message given have sent a direct message to another user.
 #. TRANS: %s is the name of the other user.
@@ -5595,26 +5565,23 @@ msgid "Error sending direct message."
 msgstr "Error al enviar el missatge directe."
 
 #: lib/command.php:514
-#, fuzzy
 msgid "Cannot repeat your own notice"
-msgstr "No es poden posar en on les notificacions."
+msgstr "No es pot repetir el vostre propi avís"
 
 #: lib/command.php:519
-#, fuzzy
 msgid "Already repeated that notice"
-msgstr "Eliminar aquesta nota"
+msgstr "Ja s'ha repetit l'avís"
 
 #. TRANS: Message given having repeated a notice from another user.
 #. TRANS: %s is the name of the user for which the notice was repeated.
 #: lib/command.php:529
-#, fuzzy, php-format
+#, php-format
 msgid "Notice from %s repeated"
-msgstr "Notificació publicada"
+msgstr "S'ha repetit l'avís de %s"
 
 #: lib/command.php:531
-#, fuzzy
 msgid "Error repeating notice."
-msgstr "Problema en guardar l'avís."
+msgstr "S'ha produït un error en repetir l'avís."
 
 #: lib/command.php:562
 #, fuzzy, php-format
@@ -5627,9 +5594,8 @@ msgid "Reply to %s sent"
 msgstr "S'ha enviat la resposta a %s"
 
 #: lib/command.php:573
-#, fuzzy
 msgid "Error saving notice."
-msgstr "Problema en guardar l'avís."
+msgstr "S'ha produït un error en desar l'avís."
 
 #: lib/command.php:620
 msgid "Specify the name of the user to subscribe to"
@@ -5676,12 +5642,14 @@ msgstr "No es poden posar en on les notificacions."
 
 #: lib/command.php:723
 msgid "Login command is disabled"
-msgstr ""
+msgstr "L'ordre d'inici de sessió està inhabilitada"
 
 #: lib/command.php:734
 #, php-format
 msgid "This link is useable only once, and is good for only 2 minutes: %s"
 msgstr ""
+"L'enllaç només es pot fer servir una vegada, i només funciona durant 2 "
+"minuts: %s"
 
 #: lib/command.php:761
 #, fuzzy, php-format
@@ -5768,7 +5736,7 @@ msgstr "No s'ha trobat cap fitxer de configuració. "
 
 #: lib/common.php:136
 msgid "I looked for configuration files in the following places: "
-msgstr ""
+msgstr "S'han cercat fitxers de configuracions en els llocs següents: "
 
 #: lib/common.php:138
 msgid "You may wish to run the installer to fix this."
@@ -5956,9 +5924,9 @@ msgid "Unsupported image file format."
 msgstr "Format d'imatge no suportat."
 
 #: lib/imagefile.php:88
-#, fuzzy, php-format
+#, php-format
 msgid "That file is too big. The maximum file size is %s."
-msgstr "Pots pujar una imatge de logo per al grup."
+msgstr "La mida del fitxer és massa gran, La mida màxima és %s."
 
 #: lib/imagefile.php:93
 msgid "Partial upload."
@@ -5991,12 +5959,12 @@ msgstr "kB"
 #: lib/jabber.php:387
 #, php-format
 msgid "[%s]"
-msgstr ""
+msgstr "[%s]"
 
 #: lib/jabber.php:567
-#, fuzzy, php-format
+#, php-format
 msgid "Unknown inbox source %d."
-msgstr "Llengua desconeguda «%s»"
+msgstr "Font %d de la safata d'entrada desconeguda."
 
 #: lib/joinform.php:114
 msgid "Join"
@@ -6067,11 +6035,9 @@ msgstr ""
 
 #. TRANS: Profile info line in new-subscriber notification e-mail
 #: lib/mail.php:269
-#, fuzzy, php-format
+#, php-format
 msgid "Bio: %s"
-msgstr ""
-"Biografia: %s\n"
-"\n"
+msgstr "Biografia: %s"
 
 #. TRANS: Subject of notification mail for new posting email address
 #: lib/mail.php:298
@@ -6114,9 +6080,9 @@ msgstr "Confirmació SMS"
 
 #. TRANS: Main body heading for SMS-by-email address confirmation message
 #: lib/mail.php:457
-#, fuzzy, php-format
+#, php-format
 msgid "%s: confirm you own this phone number with this code:"
-msgstr "Esperant confirmació per aquest número de telèfon."
+msgstr "%s: confirmeu-ho si teniu aquest número de telèfon amb aquest codi:"
 
 #. TRANS: Subject for 'nudge' notification email
 #: lib/mail.php:478
@@ -6169,9 +6135,9 @@ msgstr ""
 
 #. TRANS: Subject for favorite notification email
 #: lib/mail.php:583
-#, fuzzy, php-format
+#, php-format
 msgid "%s (@%s) added your notice as a favorite"
-msgstr "%s ha afegit la teva nota com a favorita"
+msgstr "%s (@%s) ha afegit el vostre avís com a preferit"
 
 #. TRANS: Body for favorite notification email
 #: lib/mail.php:586
@@ -6268,9 +6234,9 @@ msgid "Sorry, no incoming email allowed."
 msgstr "Ho sentim, no s'hi permet correu d'entrada."
 
 #: lib/mailhandler.php:228
-#, fuzzy, php-format
+#, php-format
 msgid "Unsupported message type: %s"
-msgstr "Format d'imatge no suportat."
+msgstr "Tipus de missatge no permès: %s"
 
 #: lib/mediafile.php:98 lib/mediafile.php:123
 msgid "There was a database error while saving your file. Please try again."
@@ -6296,7 +6262,7 @@ msgstr "Manca una carpeta temporal."
 
 #: lib/mediafile.php:162
 msgid "Failed to write file to disk."
-msgstr ""
+msgstr "No s'ha pogut escriure el fitxer al disc."
 
 #: lib/mediafile.php:165
 msgid "File upload stopped by extension."
@@ -6311,9 +6277,8 @@ msgid "File could not be moved to destination directory."
 msgstr ""
 
 #: lib/mediafile.php:201 lib/mediafile.php:237
-#, fuzzy
 msgid "Could not determine file's MIME type."
-msgstr "No s'ha pogut recuperar la conversa pública."
+msgstr "No s'ha pogut determinar el tipus MIME del fitxer."
 
 #: lib/mediafile.php:270
 #, php-format
@@ -6338,7 +6303,6 @@ msgid "Available characters"
 msgstr "Caràcters disponibles"
 
 #: lib/messageform.php:178 lib/noticeform.php:236
-#, fuzzy
 msgctxt "Send button for sending notice"
 msgid "Send"
 msgstr "Envia"
@@ -6361,50 +6325,49 @@ msgid "Attach a file"
 msgstr "Adjunta un fitxer"
 
 #: lib/noticeform.php:212
-#, fuzzy
 msgid "Share my location"
-msgstr "Comparteix la vostra ubicació"
+msgstr "Comparteix la meva ubicació"
 
 #: lib/noticeform.php:215
-#, fuzzy
 msgid "Do not share my location"
-msgstr "Comparteix la vostra ubicació"
+msgstr "No comparteixis la meva ubicació"
 
 #: lib/noticeform.php:216
 msgid ""
 "Sorry, retrieving your geo location is taking longer than expected, please "
 "try again later"
 msgstr ""
+"Ho sentim, la obtenció de la vostra ubicació geogràfic està trigant més de "
+"l'esperat; torneu-ho a provar més tard"
 
 #. TRANS: Used in coordinates as abbreviation of north
 #: lib/noticelist.php:430
-#, fuzzy
 msgid "N"
-msgstr "No"
+msgstr "N"
 
 #. TRANS: Used in coordinates as abbreviation of south
 #: lib/noticelist.php:432
 msgid "S"
-msgstr ""
+msgstr "S"
 
 #. TRANS: Used in coordinates as abbreviation of east
 #: lib/noticelist.php:434
 msgid "E"
-msgstr ""
+msgstr "E"
 
 #. TRANS: Used in coordinates as abbreviation of west
 #: lib/noticelist.php:436
 msgid "W"
-msgstr ""
+msgstr "O"
 
 #: lib/noticelist.php:438
 #, php-format
 msgid "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s"
-msgstr ""
+msgstr "%1$u°%2$u'%3$u\"%4$s %5$u°%6$u'%7$u\"%8$s"
 
 #: lib/noticelist.php:447
 msgid "at"
-msgstr ""
+msgstr "a"
 
 #: lib/noticelist.php:567
 msgid "in context"
@@ -6423,9 +6386,8 @@ msgid "Reply"
 msgstr "Respon"
 
 #: lib/noticelist.php:674
-#, fuzzy
 msgid "Notice repeated"
-msgstr "Notificació publicada"
+msgstr "Avís repetit"
 
 #: lib/nudgeform.php:116
 msgid "Nudge this user"
@@ -6456,9 +6418,8 @@ msgid "Error inserting remote profile"
 msgstr "Error en inserir perfil remot"
 
 #: lib/oauthstore.php:345
-#, fuzzy
 msgid "Duplicate notice"
-msgstr "Eliminar nota."
+msgstr "Duplica l'avís"
 
 #: lib/oauthstore.php:490
 msgid "Couldn't insert new subscription."
@@ -6497,10 +6458,9 @@ msgstr "Els teus missatges enviats"
 msgid "Tags in %s's notices"
 msgstr "Etiquetes en les notificacions de %s's"
 
-#: lib/plugin.php:114
-#, fuzzy
+#: lib/plugin.php:115
 msgid "Unknown"
-msgstr "Acció desconeguda"
+msgstr "Desconegut"
 
 #: lib/profileaction.php:109 lib/profileaction.php:205 lib/subgroupnav.php:82
 msgid "Subscriptions"
@@ -6560,14 +6520,12 @@ msgid "Popular"
 msgstr "Popular"
 
 #: lib/redirectingaction.php:94
-#, fuzzy
 msgid "No return-to arguments."
-msgstr "No argument de la id."
+msgstr "No hi ha arguments de retorn."
 
 #: lib/repeatform.php:107
-#, fuzzy
 msgid "Repeat this notice?"
-msgstr "Repeteix l'avís"
+msgstr "Voleu repetir l'avís?"
 
 #: lib/repeatform.php:132
 msgid "Yes"
@@ -6578,9 +6536,9 @@ msgid "Repeat this notice"
 msgstr "Repeteix l'avís"
 
 #: lib/revokeroleform.php:91
-#, fuzzy, php-format
+#, php-format
 msgid "Revoke the \"%s\" role from this user"
-msgstr "Bloca l'usuari del grup"
+msgstr "Revoca el rol «%s» de l'usuari"
 
 #: lib/router.php:704
 msgid "No single user defined for single-user mode."
@@ -6712,9 +6670,9 @@ msgid "Unsubscribe"
 msgstr "Cancel·lar subscripció"
 
 #: lib/usernoprofileexception.php:58
-#, fuzzy, php-format
+#, php-format
 msgid "User %s (%d) has no profile record."
-msgstr "L'usuari no té perfil."
+msgstr "L'usuari %s (%d) no té un registre de perfil."
 
 #: lib/userprofile.php:117
 msgid "Edit Avatar"
index e619430aa9888863dad93d3ced6e9f33d339c584..2180ad6cecb71869d5503beb8418aa038a8cd386 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:18+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:33+0000\n"
 "Language-Team: Czech\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: cs\n"
 "X-Message-Group: out-statusnet\n"
@@ -4846,7 +4846,7 @@ msgstr "Problém při ukládání sdělení"
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -5231,7 +5231,7 @@ msgid "Before"
 msgstr "Starší »"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5239,11 +5239,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6532,7 +6532,7 @@ msgstr ""
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
index f0225630f406228178036e0fb3891d10a90011b3..eda01937ab93645a8287a441cb876fe50c27a614 100644 (file)
@@ -15,12 +15,12 @@ msgid ""
 msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:22+0000\n"
+"POT-Creation-Date: 2010-04-29 23:21+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:36+0000\n"
 "Language-Team: German\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: de\n"
 "X-Message-Group: out-statusnet\n"
@@ -506,9 +506,9 @@ msgstr "%s’s Gruppen"
 
 #. TRANS: Meant to convey the user %2$s is a member of each of the groups listed on site %1$s
 #: actions/apigrouplist.php:107
-#, fuzzy, php-format
+#, php-format
 msgid "%1$s groups %2$s is a member of."
-msgstr "Gruppen in denen %s Mitglied ist"
+msgstr "%1$s Gruppen in denen %2$s Mitglied ist"
 
 #. TRANS: Message is used as a title. %s is a site name.
 #. TRANS: Message is used as a page title. %s is a nick name.
@@ -3316,13 +3316,12 @@ msgid "Invalid username or password."
 msgstr "Benutzername oder Passwort falsch."
 
 #: actions/register.php:343
-#, fuzzy
 msgid ""
 "With this form you can create a new account. You can then post notices and "
 "link up to friends and colleagues. "
 msgstr ""
-"Hier kannst du einen neuen Zugang einrichten. Danach kannst du Nachrichten "
-"und Links an deine Freunde und Kollegen schicken. "
+"Hier kannst du einen neuen Zugang einrichten. Anschließend kannst du "
+"Nachrichten und Links mit deinen Freunden und Kollegen teilen. "
 
 #: actions/register.php:425
 msgid "1-64 lowercase letters or numbers, no punctuation or spaces. Required."
@@ -3355,13 +3354,13 @@ msgid "Longer name, preferably your \"real\" name"
 msgstr "Längerer Name, bevorzugt dein „echter“ Name"
 
 #: actions/register.php:494
-#, fuzzy, php-format
+#, php-format
 msgid ""
 "My text and files are available under %s except this private data: password, "
 "email address, IM address, and phone number."
 msgstr ""
-"außer folgende private Daten: Passwort, E-Mail-Adresse, IM-Adresse und "
-"Telefonnummer."
+"Abgesehen von folgenden Daten: Passwort, Email Adresse, IM Adresse und "
+"Telefonnummer, sind all meine Texte und Dateien unter %s verfügbar."
 
 #: actions/register.php:542
 #, php-format
@@ -4898,7 +4897,7 @@ msgstr "Problem bei Speichern der Nachricht."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5260,7 +5259,7 @@ msgid "Before"
 msgstr "Vorher"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "root-Element eines Feeds erwartet aber ganzes XML Dokument erhalten."
 
@@ -5268,11 +5267,11 @@ msgstr "root-Element eines Feeds erwartet aber ganzes XML Dokument erhalten."
 msgid "Can't handle remote content yet."
 msgstr "Fremdinhalt kann noch nicht eingebunden werden."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Kann eingebundenen XML Inhalt nicht verarbeiten."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Eingebundener Base64 Inhalt kann noch nicht verarbeitet werden."
 
@@ -6657,7 +6656,7 @@ msgstr "Deine gesendeten Nachrichten"
 msgid "Tags in %s's notices"
 msgstr "Stichworte in %ss Nachrichten"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Unbekannter Befehl"
 
index 8fa761ae8104927ddbf0d182af97a14cd0541064..a75fef345bab0e73c0ea88b67c8ce3ec02460dea 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:29+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:39+0000\n"
 "Language-Team: Greek\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: el\n"
 "X-Message-Group: out-statusnet\n"
@@ -4769,7 +4769,7 @@ msgstr ""
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -5142,7 +5142,7 @@ msgid "Before"
 msgstr ""
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5150,11 +5150,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6409,7 +6409,7 @@ msgstr ""
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
index a52c4b5701dd3b75a86717a65806a3089d8a5094..38caf74c608d286d332bb5f9191f6052be24f8cb 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:33+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:42+0000\n"
 "Language-Team: British English\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: en-gb\n"
 "X-Message-Group: out-statusnet\n"
@@ -4779,7 +4779,7 @@ msgstr "Problem saving group inbox."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5137,7 +5137,7 @@ msgid "Before"
 msgstr "Before"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5145,11 +5145,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6396,7 +6396,7 @@ msgstr "Your sent messages"
 msgid "Tags in %s's notices"
 msgstr "Tags in %s's notices"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Unknown"
 
index 4e4d4bf06dc5c48aba13a4a2d7c8da1988ba392b..7147c728f93cb9f8dc79a4a5cf3eb5594734244e 100644 (file)
@@ -15,11 +15,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:36+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:46+0000\n"
 "Language-Team: Spanish\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: es\n"
 "X-Message-Group: out-statusnet\n"
@@ -4883,7 +4883,7 @@ msgstr "Hubo un problema al guarda la bandeja de entrada del grupo."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5246,7 +5246,7 @@ msgid "Before"
 msgstr "Antes"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 "A espera de un elemento de alimentación de raíz, pero se obtuvo un documento "
@@ -5256,11 +5256,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr "Aún no se puede manejar contenido remoto."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Aún no se puede manejar contenido XML incrustado."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Aún no se puede manejar contenido incrustado Base64."
 
@@ -6652,7 +6652,7 @@ msgstr "Mensajes enviados"
 msgid "Tags in %s's notices"
 msgstr "Etiquetas en avisos de %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Desconocido"
 
index 76e68fda7c5816d3a08bac777ad121b8595bc190..77e38b3a80f6660f29e5bbcf3a81838b463b4e0a 100644 (file)
@@ -11,7 +11,7 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:48+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:52+0000\n"
 "Last-Translator: Ahmad Sufi Mahmudi\n"
 "Language-Team: Persian\n"
 "MIME-Version: 1.0\n"
@@ -20,7 +20,7 @@ msgstr ""
 "X-Language-Code: fa\n"
 "X-Message-Group: out-statusnet\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 
 #. TRANS: Page title
@@ -4775,7 +4775,7 @@ msgstr "مشکل در ذخیره کردن آگهی."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -5146,7 +5146,7 @@ msgid "Before"
 msgstr "قبل از"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5154,11 +5154,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6415,7 +6415,7 @@ msgstr "پیام های فرستاده شده به وسیله ی شما"
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
index b015ccdbe71d078a9e9532ec6319d66a0d3c5053..a09c1415df66ff8ae1ed92cfdd4a56dc6a725f35 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:45+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:49+0000\n"
 "Language-Team: Finnish\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: fi\n"
 "X-Message-Group: out-statusnet\n"
@@ -4949,7 +4949,7 @@ msgstr "Ongelma päivityksen tallentamisessa."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, fuzzy, php-format
 msgid "RT @%1$s %2$s"
 msgstr "%1$s (%2$s)"
@@ -5332,7 +5332,7 @@ msgid "Before"
 msgstr "Aiemmin"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5340,11 +5340,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6643,7 +6643,7 @@ msgstr "Lähettämäsi viestit"
 msgid "Tags in %s's notices"
 msgstr "Tagit käyttäjän %s päivityksissä"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "Tuntematon toiminto"
index 07c850bdd0fb69e0cebb726f4770b15b4cbc3ee0..cf3f5d3b5bbc8a68ea48c5a4c36cb64cb6b8fd4f 100644 (file)
@@ -16,11 +16,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:52+0000\n"
+"PO-Revision-Date: 2010-05-03 19:17:56+0000\n"
 "Language-Team: French\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: fr\n"
 "X-Message-Group: out-statusnet\n"
@@ -4913,7 +4913,7 @@ msgstr "Problème lors de l’enregistrement de la boîte de réception du group
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5275,7 +5275,7 @@ msgid "Before"
 msgstr "Avant"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "Attendait un élément racine mais a reçu tout un document XML."
 
@@ -5283,11 +5283,11 @@ msgstr "Attendait un élément racine mais a reçu tout un document XML."
 msgid "Can't handle remote content yet."
 msgstr "Impossible de gérer le contenu distant pour le moment."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Impossible de gérer le contenu XML embarqué pour le moment."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Impossible de gérer le contenu en Base64 embarqué pour le moment."
 
@@ -6685,7 +6685,7 @@ msgstr "Vos messages envoyés"
 msgid "Tags in %s's notices"
 msgstr "Marques dans les avis de %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Inconnu"
 
index d16b9d2d96ffd9cbbe5365d8693a905199549e3e..6fd5580455a3dbba93c9b600b7ef42279f0d9bed 100644 (file)
@@ -9,11 +9,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:16:55+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:04+0000\n"
 "Language-Team: Irish\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: ga\n"
 "X-Message-Group: out-statusnet\n"
@@ -5004,7 +5004,7 @@ msgstr "Aconteceu un erro ó gardar o chío."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, fuzzy, php-format
 msgid "RT @%1$s %2$s"
 msgstr "%1$s (%2$s)"
@@ -5391,7 +5391,7 @@ msgid "Before"
 msgstr "Antes »"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5399,11 +5399,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6800,7 +6800,7 @@ msgstr "As túas mensaxes enviadas"
 msgid "Tags in %s's notices"
 msgstr "O usuario non ten último chio."
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "Acción descoñecida"
index ee17dbd29284218ffac600e880059981836de7ca..0b59b9adb8ed8bb8328ff5e61c65a8e024995e99 100644 (file)
@@ -9,12 +9,12 @@ msgid ""
 msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:07+0000\n"
+"POT-Creation-Date: 2010-04-29 23:21+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:08+0000\n"
 "Language-Team: Galician\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: gl\n"
 "X-Message-Group: out-statusnet\n"
@@ -4880,7 +4880,7 @@ msgstr "Houbo un problema ao gardar a caixa de entrada do grupo."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "♻ @%1$s %2$s"
@@ -5242,7 +5242,7 @@ msgid "Before"
 msgstr "Anteriores"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 "Esperábase unha fonte de novas raíz pero recibiuse un documento XML completo."
@@ -5251,11 +5251,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr "Aínda non é posible manexar contidos remotos."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Aínda non se poden manexar contidos XML integrados."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Aínda non se poden manexar contidos Base64."
 
@@ -5793,8 +5793,8 @@ msgstr ""
 "get <alcume> - obter a última nota do usuario\n"
 "whois <alcume> - obtén a información do perfil do usuario\n"
 "lose <alcume> - facer que o usuario deixe de seguilo\n"
-"fav <alcume> - marcar como “favorita” a última nota do usuario\n"
-"fav #<id da nota> - marcar como “favorita” a nota coa id indicada\n"
+"fav <alcume> - marcar como \"favorita\" a última nota do usuario\n"
+"fav #<id da nota> - marcar como \"favorita\" a nota coa id indicada\n"
 "repeat #<id da nota> - repetir a nota doa id indicada\n"
 "repeat <alcume> - repetir a última nota do usuario\n"
 "reply #<id da nota> - responder a unha nota coa id indicada\n"
@@ -5803,11 +5803,11 @@ msgstr ""
 "login - obter un enderezo para identificarse na interface web\n"
 "drop <grupo> - deixar o grupo indicado\n"
 "stats - obter as súas estatísticas\n"
-"stop - idéntico a “off”\n"
-"quit - idéntico a “off”\n"
-"sub <alcume> - idéntico a “follow”\n"
-"unsub <alcume> - idéntico a “leave”\n"
-"last <alcume> - idéntico a “get”\n"
+"stop - idéntico a \"off\"\n"
+"quit - idéntico a \"off\"\n"
+"sub <alcume> - idéntico a \"follow\"\n"
+"unsub <alcume> - idéntico a \"leave\"\n"
+"last <alcume> - idéntico a \"get\"\n"
 "on <alcume> - aínda non se integrou\n"
 "off <alcume> - aínda non se integrou\n"
 "nudge <alcume> - facerlle un aceno ao usuario indicado\n"
@@ -5841,7 +5841,7 @@ msgstr "MI"
 
 #: lib/connectsettingsaction.php:111
 msgid "Updates by instant messenger (IM)"
-msgstr ""
+msgstr "Actualizacións por mensaxería instantánea (MI)"
 
 #: lib/connectsettingsaction.php:116
 msgid "Updates by SMS"
@@ -5868,7 +5868,7 @@ msgid ""
 "You can upload your personal background image. The maximum file size is 2MB."
 msgstr ""
 "Pode cargar a súa imaxe de fondo persoal. O ficheiro non pode ocupar máis de "
-"2 MiB."
+"2MB."
 
 #: lib/designsettings.php:418
 msgid "Design defaults restored."
@@ -5900,7 +5900,7 @@ msgstr "Atom"
 
 #: lib/feed.php:91
 msgid "FOAF"
-msgstr "FOAF"
+msgstr "Amigo dun amigo"
 
 #: lib/feedlist.php:64
 msgid "Export data"
@@ -5908,7 +5908,7 @@ msgstr "Exportar os datos"
 
 #: lib/galleryaction.php:121
 msgid "Filter tags"
-msgstr "Filtrar etiquetas"
+msgstr "Filtrar as etiquetas"
 
 #: lib/galleryaction.php:131
 msgid "All"
@@ -5933,7 +5933,7 @@ msgstr "Continuar"
 #: lib/grantroleform.php:91
 #, php-format
 msgid "Grant this user the \"%s\" role"
-msgstr "Atribuírlle a este usuario o rol «%s»"
+msgstr "Outorgarlle a este usuario o rol \"%s\""
 
 #: lib/groupeditform.php:163
 msgid "URL of the homepage or blog of the group or topic"
@@ -5952,8 +5952,8 @@ msgstr "Describa o grupo ou o tema en %d caracteres"
 msgid ""
 "Location for the group, if any, like \"City, State (or Region), Country\""
 msgstr ""
-"Localidade do grupo, e a ten, como por exemplo «Cidade, Provincia, "
-"Comunidade, País»."
+"Localidade do grupo, se a ten, como por exemplo \"Cidade, Provincia, "
+"Comunidade, País\""
 
 #: lib/groupeditform.php:187
 #, php-format
@@ -6043,11 +6043,11 @@ msgstr "Non se coñece o tipo de ficheiro"
 
 #: lib/imagefile.php:244
 msgid "MB"
-msgstr "MiB"
+msgstr "MB"
 
 #: lib/imagefile.php:246
 msgid "kB"
-msgstr "KiB"
+msgstr "kB"
 
 #: lib/jabber.php:387
 #, php-format
@@ -6264,7 +6264,7 @@ msgstr ""
 "\n"
 "%4$s\n"
 "\n"
-"Non responda a este correo, non lle chegará ao remitente.\n"
+"Non responda a esta mensaxe, non lle chegará ao remitente.\n"
 "\n"
 "Atentamente,\n"
 "%5$s\n"
@@ -6322,7 +6322,7 @@ msgid ""
 "\n"
 "\t%s"
 msgstr ""
-"Pode ler a conversación completa en:\n"
+"Pode ler a conversa completa en:\n"
 "\n"
 "%s"
 
@@ -6358,7 +6358,7 @@ msgid ""
 "\n"
 "P.S. You can turn off these email notifications here: %8$s\n"
 msgstr ""
-"%1$s (@%9$s) acaba de enviar unha nota á súa atención (un “respost@”) en %2"
+"%1$s (@%9$s) acaba de enviar unha nota á súa atención (unha resposta) en %2"
 "$s.\n"
 "\n"
 "A nota está en:\n"
@@ -6373,14 +6373,14 @@ msgstr ""
 "\n"
 "%6$s\n"
 "\n"
-"A lista de todas as notas á súa @tención está en:\n"
+"A lista de todas as respostas está en:\n"
 "\n"
 "%7$s\n"
 "\n"
 "Atentamente,\n"
 "%2$s\n"
 "\n"
-"P.S: pode desactivar estas notificacións por correo electrónico en %8$s\n"
+"P.S.: pode desactivar estas notificacións por correo electrónico en %8$s\n"
 
 #: lib/mailbox.php:89
 msgid "Only the user can read their own mailboxes."
@@ -6417,7 +6417,7 @@ msgstr "Non se permite recibir correo electrónico."
 #: lib/mailhandler.php:228
 #, php-format
 msgid "Unsupported message type: %s"
-msgstr "Non se soporta o tipo de mensaxe %s"
+msgstr "Non se soporta o tipo de mensaxe: %s"
 
 #: lib/mediafile.php:98 lib/mediafile.php:123
 msgid "There was a database error while saving your file. Please try again."
@@ -6446,7 +6446,7 @@ msgstr "Falta un cartafol temporal."
 
 #: lib/mediafile.php:162
 msgid "Failed to write file to disk."
-msgstr "Non se puido escribir o ficheiro en disco."
+msgstr "Non se puido escribir o ficheiro no disco."
 
 #: lib/mediafile.php:165
 msgid "File upload stopped by extension."
@@ -6480,7 +6480,7 @@ msgstr "Enviar unha nota directa"
 
 #: lib/messageform.php:146
 msgid "To"
-msgstr "a"
+msgstr "A"
 
 #: lib/messageform.php:159 lib/noticeform.php:185
 msgid "Available characters"
@@ -6522,7 +6522,7 @@ msgid ""
 "try again later"
 msgstr ""
 "Estase tardando máis do esperado en obter a súa xeolocalización, vólvao "
-"intentar máis tarde."
+"intentar máis tarde"
 
 #. TRANS: Used in coordinates as abbreviation of north
 #: lib/noticelist.php:430
@@ -6547,7 +6547,7 @@ msgstr "O"
 #: lib/noticelist.php:438
 #, 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 \"s% 4% 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:447
 msgid "at"
@@ -6642,7 +6642,7 @@ msgstr "As mensaxes enviadas"
 msgid "Tags in %s's notices"
 msgstr "Etiquetas nas notas de %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Descoñecida"
 
@@ -6705,11 +6705,11 @@ msgstr "Populares"
 
 #: lib/redirectingaction.php:94
 msgid "No return-to arguments."
-msgstr "Sen argumentos “return-to”."
+msgstr "Sen argumentos \"return-to\"."
 
 #: lib/repeatform.php:107
 msgid "Repeat this notice?"
-msgstr "Quere repetir esta nova?"
+msgstr "Quere repetir esta nota?"
 
 #: lib/repeatform.php:132
 msgid "Yes"
@@ -6717,12 +6717,12 @@ msgstr "Si"
 
 #: lib/repeatform.php:132
 msgid "Repeat this notice"
-msgstr "Repetir esta nova"
+msgstr "Repetir esta nota"
 
 #: lib/revokeroleform.php:91
 #, php-format
 msgid "Revoke the \"%s\" role from this user"
-msgstr "Revogarlle o rol “%s” a este usuario"
+msgstr "Revogarlle o rol \"%s\" a este usuario"
 
 #: lib/router.php:704
 msgid "No single user defined for single-user mode."
@@ -6806,7 +6806,7 @@ msgstr "Convidar"
 #: lib/subgroupnav.php:106
 #, php-format
 msgid "Invite friends and colleagues to join you on %s"
-msgstr "Convida a amigos e compañeiros a unírseche en %s"
+msgstr "Convide a amigos e compañeiros a unírselle en %s"
 
 #: lib/subscriberspeopleselftagcloudsection.php:48
 #: lib/subscriptionspeopleselftagcloudsection.php:48
index 857ce5a2c34589044b8725bbd9835ace17a7f6dc..2c9927ebfea2e84db3e1a5bd3acaaa686d23d1e9 100644 (file)
@@ -8,11 +8,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:10+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:12+0000\n"
 "Language-Team: Hebrew\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: he\n"
 "X-Message-Group: out-statusnet\n"
@@ -4849,7 +4849,7 @@ msgstr "בעיה בשמירת ההודעה."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -5234,7 +5234,7 @@ msgid "Before"
 msgstr "לפני >>"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5242,11 +5242,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6533,7 +6533,7 @@ msgstr ""
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
index 5d226be60aaaa25b48b307b52dea4bdcd2c831ae..a5126d75ad7b0f4bbe69537ec7ac008436897e3b 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:21+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:15+0000\n"
 "Language-Team: Dutch\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: hsb\n"
 "X-Message-Group: out-statusnet\n"
@@ -4589,7 +4589,7 @@ msgstr ""
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -4941,7 +4941,7 @@ msgid "Before"
 msgstr ""
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -4949,11 +4949,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6186,7 +6186,7 @@ msgstr "Twoje pósłane powěsće"
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Njeznaty"
 
index 62ec146c31cf08f48aca923333e3343566ae9b63..1b05490b9ecdff0e2b876616d0eb440cbbd9ff0a 100644 (file)
@@ -9,11 +9,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:24+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:18+0000\n"
 "Language-Team: Interlingua\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: ia\n"
 "X-Message-Group: out-statusnet\n"
@@ -4857,7 +4857,7 @@ msgstr "Problema salveguardar le cassa de entrata del gruppo."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5215,7 +5215,7 @@ msgid "Before"
 msgstr "Ante"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 "Expectava le elemento-radice de un syndication, ma recipeva un documento XML "
@@ -5225,11 +5225,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr "Non pote ancora tractar contento remote."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Non pote ancora tractar contento XML incastrate."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Non pote ancora tractar contento Base64 incastrate."
 
@@ -6615,7 +6615,7 @@ msgstr "Tu messages inviate"
 msgid "Tags in %s's notices"
 msgstr "Etiquettas in le notas de %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Incognite"
 
index 34f87d2441f91b804dc3b9eb32cab9793b891a72..2b2f19f5d6cf0061357514656ac6bfc3da8bd85d 100644 (file)
@@ -9,11 +9,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:27+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:21+0000\n"
 "Language-Team: Icelandic\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: is\n"
 "X-Message-Group: out-statusnet\n"
@@ -4899,7 +4899,7 @@ msgstr "Vandamál komu upp við að vista babl."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, fuzzy, php-format
 msgid "RT @%1$s %2$s"
 msgstr "%1$s (%2$s)"
@@ -5282,7 +5282,7 @@ msgid "Before"
 msgstr "Áður"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5290,11 +5290,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6577,7 +6577,7 @@ msgstr "Skilaboð sem þú hefur sent"
 msgid "Tags in %s's notices"
 msgstr "Merki í babli %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "Óþekkt aðgerð"
index de429fe9b6a57897502cd1f768ab549abaa2a5ab..6b6351f89bba334483cc792732cc7991adf6aba4 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:37+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:25+0000\n"
 "Language-Team: Italian\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: it\n"
 "X-Message-Group: out-statusnet\n"
@@ -4857,7 +4857,7 @@ msgstr "Problema nel salvare la casella della posta del gruppo."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5219,7 +5219,7 @@ msgid "Before"
 msgstr "Precedenti"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "Atteso un elemento root del feed, ma ricevuto un documento XML intero."
 
@@ -5227,11 +5227,11 @@ msgstr "Atteso un elemento root del feed, ma ricevuto un documento XML intero."
 msgid "Can't handle remote content yet."
 msgstr "Impossibile gestire contenuti remoti."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Impossibile gestire contenuti XML incorporati."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Impossibile gestire contenuti Base64."
 
@@ -6621,7 +6621,7 @@ msgstr "I tuoi messaggi inviati"
 msgid "Tags in %s's notices"
 msgstr "Etichette nei messaggi di %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Sconosciuto"
 
index 76ca28c248fe3bd478577cd00588944cb5dd6fb1..d3943819ab35ca3ce1749bc72f289f69f2b93516 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:40+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:28+0000\n"
 "Language-Team: Japanese\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: ja\n"
 "X-Message-Group: out-statusnet\n"
@@ -4890,7 +4890,7 @@ msgstr "グループ受信箱を保存する際に問題が発生しました。
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -5267,7 +5267,7 @@ msgid "Before"
 msgstr "前>>"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5275,11 +5275,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6610,7 +6610,7 @@ msgstr "あなたが送ったメッセージ"
 msgid "Tags in %s's notices"
 msgstr "%s のつぶやきのタグ"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "不明"
 
index 8411920419169ee272db5b5cb9180b700fb01762..835611a9fdf27ce5b223f9440aee083bb4d37e86 100644 (file)
@@ -9,11 +9,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:43+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:31+0000\n"
 "Language-Team: Korean\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: ko\n"
 "X-Message-Group: out-statusnet\n"
@@ -4871,7 +4871,7 @@ msgstr "통지를 저장하는데 문제가 발생했습니다."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, fuzzy, php-format
 msgid "RT @%1$s %2$s"
 msgstr "%1$s (%2$s)"
@@ -5252,7 +5252,7 @@ msgid "Before"
 msgstr "앞 페이지"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5260,11 +5260,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6546,7 +6546,7 @@ msgstr "당신의 보낸 메시지들"
 msgid "Tags in %s's notices"
 msgstr "%s의 게시글의 태그"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "알려지지 않은 행동"
index 76cd8f711f62d503b4ce02b99edb20eab199a9ae..215f5089cd37f2bd7212cbb9c64f4bbb4ae2c7fe 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:47+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:38+0000\n"
 "Language-Team: Macedonian\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: mk\n"
 "X-Message-Group: out-statusnet\n"
@@ -4878,7 +4878,7 @@ msgstr "Проблем при зачувувањето на групното п
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5240,7 +5240,7 @@ msgid "Before"
 msgstr "Пред"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "Се очекува коренски каналски елемент, но добив цел XML документ."
 
@@ -5248,11 +5248,11 @@ msgstr "Се очекува коренски каналски елемент, н
 msgid "Can't handle remote content yet."
 msgstr "Сè уште не е поддржана обработката на далечинска содржина."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Сè уште не е поддржана обработката на XML содржина."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Сè уште не е достапна обработката на вметната Base64 содржина."
 
@@ -6642,7 +6642,7 @@ msgstr "Ваши испратени пораки"
 msgid "Tags in %s's notices"
 msgstr "Ознаки во забелешките на %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Непознато"
 
index 4ac3bff5751ef9742696f2c70536ad46ca53c363..c36addf5588d12e92c4815d736bcea8731d73657 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:50+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:41+0000\n"
 "Language-Team: Norwegian (bokmål)‬\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: no\n"
 "X-Message-Group: out-statusnet\n"
@@ -4273,12 +4273,12 @@ msgstr "Alle abonnementer"
 
 #: actions/subscribers.php:63
 msgid "These are the people who listen to your notices."
-msgstr ""
+msgstr "Dette er personene som lytter til dine notiser."
 
 #: actions/subscribers.php:67
 #, php-format
 msgid "These are the people who listen to %s's notices."
-msgstr ""
+msgstr "Dette er personene som lytter til %ss notiser."
 
 #: actions/subscribers.php:108
 msgid ""
@@ -4310,12 +4310,12 @@ msgstr "Alle abonnementer"
 
 #: actions/subscriptions.php:65
 msgid "These are the people whose notices you listen to."
-msgstr ""
+msgstr "Dette er personene hvis notiser du lytter til."
 
 #: actions/subscriptions.php:69
 #, php-format
 msgid "These are the people whose notices %s listens to."
-msgstr ""
+msgstr "Dette er personene hvis notiser %s lytter til."
 
 #: actions/subscriptions.php:126
 #, php-format
@@ -4792,7 +4792,7 @@ msgstr "Problem ved lagring av gruppeinnboks."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5150,7 +5150,7 @@ msgid "Before"
 msgstr "Før"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5158,11 +5158,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6500,7 +6500,7 @@ msgstr "Dine sendte meldinger"
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Ukjent"
 
index cef426ff5aae908e24ef16c324d56113a11f7ae0..f42b339413eee752bddb50f5ba473bcdbd676f92 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:57+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:47+0000\n"
 "Language-Team: Dutch\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: nl\n"
 "X-Message-Group: out-statusnet\n"
@@ -4920,7 +4920,7 @@ msgstr ""
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5283,7 +5283,7 @@ msgid "Before"
 msgstr "Eerder"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "Verwachtte een root-feed element maar kreeg een heel XML-document."
 
@@ -5291,11 +5291,11 @@ msgstr "Verwachtte een root-feed element maar kreeg een heel XML-document."
 msgid "Can't handle remote content yet."
 msgstr "Het is nog niet mogelijk inhoud uit andere omgevingen te verwerken."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Het is nog niet mogelijk ingebedde XML-inhoud te verwerken"
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Het is nog niet mogelijk ingebedde Base64-inhoud te verwerken"
 
@@ -6696,7 +6696,7 @@ msgstr "Uw verzonden berichten"
 msgid "Tags in %s's notices"
 msgstr "Labels in de mededelingen van %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Onbekend"
 
index 6a2a705d75c5caae538bf3f32700b35be61835c1..ddff42772962f36d39c26a8a8261e4c21cd94b5b 100644 (file)
@@ -9,11 +9,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:17:54+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:44+0000\n"
 "Language-Team: Norwegian Nynorsk\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: nn\n"
 "X-Message-Group: out-statusnet\n"
@@ -4938,7 +4938,7 @@ msgstr "Eit problem oppstod ved lagring av notis."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, fuzzy, php-format
 msgid "RT @%1$s %2$s"
 msgstr "%1$s (%2$s)"
@@ -5321,7 +5321,7 @@ msgid "Before"
 msgstr "Før »"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5329,11 +5329,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6624,7 +6624,7 @@ msgstr "Dine sende meldingar"
 msgid "Tags in %s's notices"
 msgstr "Merkelappar i %s sine notisar"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "Uventa handling."
index cd23aea29119c49c2368d3d205a203af5ff1b5d0..c816475e19624a465c1317a005be9b95192ef347 100644 (file)
@@ -12,7 +12,7 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:01+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:50+0000\n"
 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <pl@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -20,7 +20,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2);\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: pl\n"
 "X-Message-Group: out-statusnet\n"
@@ -4851,7 +4851,7 @@ msgstr "Problem podczas zapisywania skrzynki odbiorczej grupy."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5214,7 +5214,7 @@ msgid "Before"
 msgstr "Wcześniej"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "Oczekiwano elementu kanału roota, ale otrzymano cały dokument XML."
 
@@ -5222,11 +5222,11 @@ msgstr "Oczekiwano elementu kanału roota, ale otrzymano cały dokument XML."
 msgid "Can't handle remote content yet."
 msgstr "Nie można jeszcze obsługiwać zdalnej treści."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Nie można jeszcze obsługiwać zagnieżdżonej treści XML."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Nie można jeszcze obsługiwać zagnieżdżonej treści Base64."
 
@@ -6615,7 +6615,7 @@ msgstr "Wysłane wiadomości"
 msgid "Tags in %s's notices"
 msgstr "Znaczniki we wpisach użytkownika %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Nieznane"
 
index 048664eb8130ee0260bdb806d24091249cf53fda..2d6571767466ae66d137eaefa55a6580c4d08e8f 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:04+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:53+0000\n"
 "Language-Team: Portuguese\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: pt\n"
 "X-Message-Group: out-statusnet\n"
@@ -4849,7 +4849,7 @@ msgstr "Problema na gravação da caixa de entrada do grupo."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5212,7 +5212,7 @@ msgid "Before"
 msgstr "Anteriores"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 "Era esperado um elemento raiz da fonte, mas foi recebido um documento XML "
@@ -5222,11 +5222,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr "Ainda não é possível processar conteúdos remotos."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Ainda não é possível processar conteúdo XML embutido."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Ainda não é possível processar conteúdo Base64 embutido."
 
@@ -6608,7 +6608,7 @@ msgstr "Mensagens enviadas"
 msgid "Tags in %s's notices"
 msgstr "Categorias nas notas de %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Desconhecida"
 
index 4263dde6b54d4b1109a2f73202c1843c50d0e945..1409dc6146610fb4ed8f8e35fe8707ec3f95cd29 100644 (file)
@@ -13,11 +13,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:12+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:56+0000\n"
 "Language-Team: Brazilian Portuguese\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: pt-br\n"
 "X-Message-Group: out-statusnet\n"
@@ -1536,9 +1536,8 @@ msgstr "Esse é o endereço de e-mail errado."
 
 #. TRANS: Message given after successfully canceling e-mail address confirmation.
 #: actions/emailsettings.php:438
-#, fuzzy
 msgid "Email confirmation cancelled."
-msgstr "A confirmação foi cancelada."
+msgstr "A confirmação por e-mail foi cancelada."
 
 #. TRANS: Message given trying to remove an e-mail address that is not
 #. TRANS: registered for the active user.
@@ -1548,9 +1547,8 @@ msgstr "Esse não é seu endereço de email."
 
 #. TRANS: Message given after successfully removing a registered e-mail address.
 #: actions/emailsettings.php:479
-#, fuzzy
 msgid "The email address was removed."
-msgstr "O endereço foi removido."
+msgstr "O endereço de e-mail foi removido."
 
 #: actions/emailsettings.php:493 actions/smssettings.php:568
 msgid "No incoming email address."
@@ -1690,9 +1688,8 @@ msgid "Remote service uses unknown version of OMB protocol."
 msgstr "O serviço remoto usa uma versão desconhecida do protocolo OMB."
 
 #: actions/finishremotesubscribe.php:138
-#, fuzzy
 msgid "Error updating remote profile."
-msgstr "Ocorreu um erro na atualização do perfil remoto"
+msgstr "Ocorreu um erro durante a atualização do perfil remoto."
 
 #: actions/getfile.php:79
 msgid "No such file."
@@ -2014,9 +2011,8 @@ msgstr ""
 
 #. TRANS: Form legend for IM preferences form.
 #: actions/imsettings.php:155
-#, fuzzy
 msgid "IM preferences"
-msgstr "Preferências"
+msgstr "Preferências do mensageiro instantâneo"
 
 #. TRANS: Checkbox label in IM preferences form.
 #: actions/imsettings.php:160
@@ -2088,15 +2084,13 @@ msgstr "Isso é um endereço de MI errado."
 
 #. TRANS: Server error thrown on database error canceling IM address confirmation.
 #: actions/imsettings.php:397
-#, fuzzy
 msgid "Couldn't delete IM confirmation."
-msgstr "Não foi possível excluir a confirmação de e-mail."
+msgstr "Não foi possível excluir a confirmação do mensageiro instantâneo."
 
 #. TRANS: Message given after successfully canceling IM address confirmation.
 #: actions/imsettings.php:402
-#, fuzzy
 msgid "IM confirmation cancelled."
-msgstr "A confirmação foi cancelada."
+msgstr "A confirmação do mensageiro instantâneo foi cancelada."
 
 #. TRANS: Message given trying to remove an IM address that is not
 #. TRANS: registered for the active user.
@@ -2106,9 +2100,8 @@ msgstr "Essa não é sua ID do Jabber."
 
 #. TRANS: Message given after successfully removing a registered IM address.
 #: actions/imsettings.php:447
-#, fuzzy
 msgid "The IM address was removed."
-msgstr "O endereço foi removido."
+msgstr "O endereço de mensageiro instantâneo foi removido."
 
 #: actions/inbox.php:59
 #, php-format
@@ -2131,10 +2124,10 @@ msgid "Invites have been disabled."
 msgstr "Os convites foram desabilitados."
 
 #: actions/invite.php:41
-#, fuzzy, php-format
+#, php-format
 msgid "You must be logged in to invite other users to use %s."
 msgstr ""
-"Você deve estar autenticado para convidar outros usuários para usar o %s"
+"Você deve estar autenticado para convidar outros usuários para usar o %s."
 
 #: actions/invite.php:72
 #, php-format
@@ -2344,17 +2337,15 @@ msgstr ""
 "senha antes de alterar suas configurações."
 
 #: actions/login.php:270
-#, fuzzy
 msgid "Login with your username and password."
-msgstr "Autentique-se com um nome de usuário e uma senha"
+msgstr "Autentique-se com seu nome de usuário e senha."
 
 #: actions/login.php:273
-#, fuzzy, php-format
+#, php-format
 msgid ""
 "Don't have a username yet? [Register](%%action.register%%) a new account."
 msgstr ""
-"Digite seu nome de usuário e senha. Ainda não possui um usuário? [Registre](%"
-"%action.register%%) uma nova conta."
+"Ainda não possui um usuário? [Registre](%%action.register%%) uma nova conta."
 
 #: actions/makeadmin.php:92
 msgid "Only an admin can make another user an admin."
@@ -2378,9 +2369,8 @@ msgid "Can't make %1$s an admin for group %2$s."
 msgstr "Não foi possível tornar %1$s um administrador do grupo %2$s."
 
 #: actions/microsummary.php:69
-#, fuzzy
 msgid "No current status."
-msgstr "Nenhuma mensagem atual"
+msgstr "Nenhuma mensagem atual."
 
 #: actions/newapplication.php:52
 msgid "New Application"
@@ -2547,9 +2537,9 @@ msgid "You are not a user of that application."
 msgstr "Você não é um usuário dessa aplicação."
 
 #: actions/oauthconnectionssettings.php:186
-#, fuzzy, php-format
+#, php-format
 msgid "Unable to revoke access for app: %s."
-msgstr "Não foi possível revogar o acesso para a aplicação: "
+msgstr "Não foi possível revogar o acesso para a aplicação: %s."
 
 #: actions/oauthconnectionssettings.php:198
 msgid "You have not authorized any applications to use your account."
@@ -4903,7 +4893,7 @@ msgstr "Problema no salvamento das mensagens recebidas do grupo."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5262,7 +5252,7 @@ msgid "Before"
 msgstr "Anterior"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 "Era esperado um elemento raiz da fonte, mas foi obtido o documento XML "
@@ -5272,11 +5262,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr "Ainda não é possível manipular conteúdo remoto."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Ainda não é possível manipular conteúdo XML incorporado."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Ainda não é possível manipular conteúdo Base64."
 
@@ -6643,7 +6633,7 @@ msgstr "Suas mensagens enviadas"
 msgid "Tags in %s's notices"
 msgstr "Etiquetas nas mensagens de %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Desconhecido"
 
index 7f697bd8d5a58abb9756dc0937a1981d0ed594c0..054ed2bc2ae7c368e56cd1c795158057f536d81a 100644 (file)
@@ -13,11 +13,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:15+0000\n"
+"PO-Revision-Date: 2010-05-03 19:18:59+0000\n"
 "Language-Team: Russian\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: ru\n"
 "X-Message-Group: out-statusnet\n"
@@ -4869,7 +4869,7 @@ msgstr "Проблемы с сохранением входящих сообще
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5230,7 +5230,7 @@ msgid "Before"
 msgstr "Туда"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "Ожидался корневой элемент потока, а получен XML-документ целиком."
 
@@ -5238,11 +5238,11 @@ msgstr "Ожидался корневой элемент потока, а пол
 msgid "Can't handle remote content yet."
 msgstr "Пока ещё нельзя обрабатывать удалённое содержимое."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Пока ещё нельзя обрабатывать встроенный XML."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Пока ещё нельзя обрабатывать встроенное содержание Base64."
 
@@ -6629,7 +6629,7 @@ msgstr "Ваши исходящие сообщения"
 msgid "Tags in %s's notices"
 msgstr "Теги записей пользователя %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Неизвестно"
 
index e0aad71466a9d57fc69e1f9ee68f608f022383b6..caa8258f97a9108a8498fb38042d20cb2d51b5f8 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-04-26 22:15+0000\n"
+"POT-Creation-Date: 2010-05-03 19:17+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -4575,7 +4575,7 @@ msgstr ""
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -4927,7 +4927,7 @@ msgid "Before"
 msgstr ""
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -4935,11 +4935,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6166,7 +6166,7 @@ msgstr ""
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
index 65a64dc320e95b9e8e59b5e1fbc29b0d59af25b4..e50bf1a3288d59c09e269e8a52d48d56ed95179e 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:20+0000\n"
+"PO-Revision-Date: 2010-05-03 19:19:02+0000\n"
 "Language-Team: Swedish\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: sv\n"
 "X-Message-Group: out-statusnet\n"
@@ -4846,7 +4846,7 @@ msgstr "Problem med att spara gruppinkorg."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5204,7 +5204,7 @@ msgid "Before"
 msgstr "Tidigare"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr "Förväntade ett flödes rotelement, men fick ett helt XML-dokument."
 
@@ -5212,11 +5212,11 @@ msgstr "Förväntade ett flödes rotelement, men fick ett helt XML-dokument."
 msgid "Can't handle remote content yet."
 msgstr "Kan inte hantera fjärrinnehåll ännu."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Kan inte hantera inbäddat XML-innehåll ännu."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Kan inte hantera inbäddat Base64-innehåll ännu."
 
@@ -6596,7 +6596,7 @@ msgstr "Dina skickade meddelanden"
 msgid "Tags in %s's notices"
 msgstr "Taggar i %ss notiser"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Okänd"
 
index 54e7d0de1821b0f1bb6d8e117bd280550b1d5a88..7084c9114a2d17983acd142366f4e8d7f4e8d903 100644 (file)
@@ -9,12 +9,12 @@ msgid ""
 msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:38+0000\n"
+"POT-Creation-Date: 2010-04-29 23:21+0000\n"
+"PO-Revision-Date: 2010-05-03 19:19:06+0000\n"
 "Language-Team: Telugu\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: te\n"
 "X-Message-Group: out-statusnet\n"
@@ -2113,6 +2113,8 @@ msgid ""
 "You will be notified when your invitees accept the invitation and register "
 "on the site. Thanks for growing the community!"
 msgstr ""
+"ఆహ్వానితులు మీ ఆహ్వానాన్ని అంగీకరించి సైటులో నమోదైనప్పుడు మీకు తెలియజేస్తాము. ఇక్కడి ప్రజని "
+"పెంచుతున్నందుకు ధన్యవాదాలు!"
 
 #: actions/invite.php:162
 msgid ""
@@ -2450,7 +2452,7 @@ msgstr "మీరు నమోదు చేసివున్న ఉపకరణ
 #: actions/oauthappssettings.php:135
 #, php-format
 msgid "You have not registered any applications yet."
-msgstr ""
+msgstr "మీరు ఇంకా ఏ ఉపకరణాన్నీ నమోదు చేసుకోలేదు."
 
 #: actions/oauthconnectionssettings.php:72
 msgid "Connected applications"
@@ -2471,7 +2473,7 @@ msgstr ""
 
 #: actions/oauthconnectionssettings.php:198
 msgid "You have not authorized any applications to use your account."
-msgstr ""
+msgstr "మీ ఖాతాని ఉపయోగించుకోడానికి మీరు ఏ ఉపకరణాన్నీ అధీకరించలేదు."
 
 #: actions/oauthconnectionssettings.php:211
 msgid "Developers can edit the registration settings for their applications "
@@ -3907,7 +3909,7 @@ msgstr "అప్రమేయ భాష"
 
 #: actions/siteadminpanel.php:263
 msgid "Site language when autodetection from browser settings is not available"
-msgstr ""
+msgstr "విహారిణి అమరికల నుండి భాషని స్వయంచాలకంగా పొందలేకపోయినప్పుడు ఉపయోగించే సైటు భాష"
 
 #: actions/siteadminpanel.php:271
 msgid "Limits"
@@ -3927,7 +3929,7 @@ msgstr ""
 
 #: actions/siteadminpanel.php:278
 msgid "How long users must wait (in seconds) to post the same thing again."
-msgstr ""
+msgstr "అదే విషయాన్ని మళ్ళీ టపా చేయడానికి వాడుకరులు ఎంత సమయం (క్షణాల్లో) వేచివుండాలి."
 
 #: actions/sitenoticeadminpanel.php:56
 msgid "Site Notice"
@@ -4234,6 +4236,8 @@ msgid ""
 "%s has no subscribers. Why not [register an account](%%%%action.register%%%"
 "%) and be the first?"
 msgstr ""
+"%sకి చందాదార్లు ఎవరూ లేరు. [ఒక ఖాతాని నమోదు చేసుకుని](%%%%action.register%%%%) మీరు "
+"ఎందుకు మొదటి చందాదారు కాకూడదు?"
 
 #: actions/subscriptions.php:52
 #, php-format
@@ -4247,12 +4251,12 @@ msgstr "%1$s చందాలు, పేజీ %2$d"
 
 #: actions/subscriptions.php:65
 msgid "These are the people whose notices you listen to."
-msgstr ""
+msgstr "మీరు ఈ వ్యక్తుల నోటీసులని వింటున్నారు."
 
 #: actions/subscriptions.php:69
 #, php-format
 msgid "These are the people whose notices %s listens to."
-msgstr ""
+msgstr "%s వీరి నోటీసులని వింటున్నారు."
 
 #: actions/subscriptions.php:126
 #, php-format
@@ -4729,7 +4733,7 @@ msgstr "సందేశాన్ని భద్రపరచడంలో పొ
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5096,7 +5100,7 @@ msgid "Before"
 msgstr "ఇంతక్రితం"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5104,11 +5108,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -5465,9 +5469,9 @@ msgstr ""
 #. TRANS: Message given if content is too long.
 #. TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
 #: lib/command.php:472
-#, fuzzy, php-format
+#, php-format
 msgid "Message too long - maximum is %1$d characters, you sent %2$d"
-msgstr "à°¨à±\8bà°\9fà°¿à°¸à±\81 à°\9aాలా à°ªà±\8aà°¡à°µà±\81à°\97à°¾ à°\89à°\82ది - %1$d à°\85à°\95à±\8dషరాలà±\81 à°\97à°°à°¿à°·à±\8dà° à°\82, à°®à±\80à°°à±\81 %2$d à°ªà°\82పిà°\82à°\9aారà±\81."
+msgstr "à°¸à°\82à°¦à±\87à°¶à°\82 à°\9aాలా à°ªà±\8aà°¡à°µà±\81à°\97à°¾ à°\89à°\82ది - %1$d à°\85à°\95à±\8dషరాలà±\81 à°\97à°°à°¿à°·à±\8dà° à°\82, à°®à±\80à°°à±\81 %2$d à°ªà°\82పిà°\82à°\9aారà±\81"
 
 #. TRANS: Message given have sent a direct message to another user.
 #. TRANS: %s is the name of the other user.
@@ -6452,7 +6456,7 @@ msgstr "మీరు పంపిన సందేశాలు"
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
index 8514f78d5db9a9790159529598712fe18945fcba..28869e63fbc768c51f288f598e8fa87b94bb0856 100644 (file)
@@ -10,11 +10,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:42+0000\n"
+"PO-Revision-Date: 2010-05-03 19:19:10+0000\n"
 "Language-Team: Turkish\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: tr\n"
 "X-Message-Group: out-statusnet\n"
@@ -4852,7 +4852,7 @@ msgstr "Durum mesajını kaydederken hata oluştu."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -5237,7 +5237,7 @@ msgid "Before"
 msgstr "Önce »"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5245,11 +5245,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6538,7 +6538,7 @@ msgstr ""
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
index efdcae240f18c9fdd4b51048f5c47c550f31c879..349e2da72e5da8cbb427f7f5fa0864682bd489b1 100644 (file)
@@ -12,11 +12,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:45+0000\n"
+"PO-Revision-Date: 2010-05-03 19:19:13+0000\n"
 "Language-Team: Ukrainian\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: uk\n"
 "X-Message-Group: out-statusnet\n"
@@ -4854,7 +4854,7 @@ msgstr "Проблема при збереженні вхідних дописі
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr "RT @%1$s %2$s"
@@ -5212,7 +5212,7 @@ msgid "Before"
 msgstr "Назад"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 "В очікуванні кореневого елементу веб-стрічки, отримали цілий документ XML."
@@ -5221,11 +5221,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr "Поки що не можу обробити віддалений контент."
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr "Поки що не можу обробити вбудований XML контент."
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr "Поки що не можу обробити вбудований контент Base64."
 
@@ -6611,7 +6611,7 @@ msgstr "Надіслані вами повідомлення"
 msgid "Tags in %s's notices"
 msgstr "Теґи у дописах %s"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr "Невідомо"
 
index 4dd5e6ceb8aebd946b4ace4a1f8e0d5d9a182faa..5c22fbad66fb2576871fd6eb1c8de5c78402fed0 100644 (file)
@@ -8,11 +8,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:48+0000\n"
+"PO-Revision-Date: 2010-05-03 19:19:17+0000\n"
 "Language-Team: Vietnamese\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: vi\n"
 "X-Message-Group: out-statusnet\n"
@@ -5006,7 +5006,7 @@ msgstr "Có lỗi xảy ra khi lưu tin nhắn."
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, fuzzy, php-format
 msgid "RT @%1$s %2$s"
 msgstr "%s (%s)"
@@ -5395,7 +5395,7 @@ msgid "Before"
 msgstr "Trước"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5403,11 +5403,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6768,7 +6768,7 @@ msgstr "Thư bạn đã gửi"
 msgid "Tags in %s's notices"
 msgstr "cảnh báo tin nhắn"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "Không tìm thấy action"
index e38cda2ec6f0ccca4dff7d838c29bc559dbeb83f..71d3293f41a97b98f28846dc111fd824c1eb4fa5 100644 (file)
@@ -11,11 +11,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:51+0000\n"
+"PO-Revision-Date: 2010-05-03 19:19:20+0000\n"
 "Language-Team: Simplified Chinese\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: zh-hans\n"
 "X-Message-Group: out-statusnet\n"
@@ -4935,7 +4935,7 @@ msgstr "保存通告时出错。"
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, fuzzy, php-format
 msgid "RT @%1$s %2$s"
 msgstr "%1$s (%2$s)"
@@ -5325,7 +5325,7 @@ msgid "Before"
 msgstr "之前 »"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5333,11 +5333,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6643,7 +6643,7 @@ msgstr "您发送的消息"
 msgid "Tags in %s's notices"
 msgstr "%s's 的消息的标签"
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 #, fuzzy
 msgid "Unknown"
 msgstr "未知动作"
index 4240b921ab94474a43f9e2dbf069b1d97780e122..b7aca62bc3544f8c2858f943865e56af3e457354 100644 (file)
@@ -8,11 +8,11 @@ msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2010-04-24 14:16+0000\n"
-"PO-Revision-Date: 2010-04-26 22:18:54+0000\n"
+"PO-Revision-Date: 2010-05-03 19:19:23+0000\n"
 "Language-Team: Traditional Chinese\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: MediaWiki 1.17alpha (r65552); Translate extension (2010-04-25)\n"
+"X-Generator: MediaWiki 1.17alpha (r65870); Translate extension (2010-05-01)\n"
 "X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
 "X-Language-Code: zh-hant\n"
 "X-Message-Group: out-statusnet\n"
@@ -4760,7 +4760,7 @@ msgstr "儲存使用者發生錯誤"
 
 #. TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
 #. TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
-#: classes/Notice.php:1535
+#: classes/Notice.php:1533
 #, php-format
 msgid "RT @%1$s %2$s"
 msgstr ""
@@ -5138,7 +5138,7 @@ msgid "Before"
 msgstr "之前的內容»"
 
 #. TRANS: Client exception thrown when a feed instance is a DOMDocument.
-#: lib/activity.php:121
+#: lib/activity.php:122
 msgid "Expecting a root feed element but got a whole XML document."
 msgstr ""
 
@@ -5146,11 +5146,11 @@ msgstr ""
 msgid "Can't handle remote content yet."
 msgstr ""
 
-#: lib/activityutils.php:236
+#: lib/activityutils.php:244
 msgid "Can't handle embedded XML content yet."
 msgstr ""
 
-#: lib/activityutils.php:240
+#: lib/activityutils.php:248
 msgid "Can't handle embedded Base64 content yet."
 msgstr ""
 
@@ -6420,7 +6420,7 @@ msgstr ""
 msgid "Tags in %s's notices"
 msgstr ""
 
-#: lib/plugin.php:114
+#: lib/plugin.php:115
 msgid "Unknown"
 msgstr ""
 
diff --git a/plugins/AutoSandbox/AutoSandboxPlugin.php b/plugins/AutoSandbox/AutoSandboxPlugin.php
new file mode 100644 (file)
index 0000000..ffd8bf4
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to automatically sandbox newly registered users in an effort to beat
+ * spammers. If the user proves to be legitimate, moderators can un-sandbox them.
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Sean Carmody<seancarmody@gmail.com>
+ * @copyright 2010
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+define('AUTOSANDBOX', '0.1');
+
+//require_once(INSTALLDIR.'/plugins/AutoSandbox/autosandbox.php');
+
+class AutoSandboxPlugin extends Plugin
+{
+    var $contact;
+    var $debug;
+
+    function onInitializePlugin() 
+    {
+        if(!isset($this->debug))
+        {
+            $this->debug = 0;
+        }
+
+        if(!isset($this->contact)) {
+           $default = common_config('newuser', 'default');
+           if (!empty($default)) {
+               $this->contact = $default;
+           }
+        } 
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'AutoSandbox',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Sean Carmody',
+                            'homepage' => 'http://status.net/wiki/Plugin:AutoSandbox',
+                            'rawdescription' =>
+                            _m('Automatically sandboxes newly registered members.'));
+        return true;
+    }
+
+    function onStartRegistrationFormData($action)
+    {
+
+         $instr = 'Note you will initially be "sandboxed" so your posts will not appear in the public timeline.';
+
+         if (isset($this->contact)) {
+             $contactuser = User::staticGet('nickname', $this->contact);
+             if (!empty($contactuser)) {
+                 $contactlink = "@<a href=\"$contactuser->uri\">$contactuser->nickname</a>";
+                 $instr = $instr . " Send a message to $contactlink to speed up the unsandboxing process.";
+             }
+         } 
+
+         $output = common_markup_to_html($instr);
+         $action->elementStart('div', 'instructions');
+         $action->raw($output);
+         $action->elementEnd('div');
+    }
+
+    function onEndUserRegister(&$profile,&$user)
+    {
+       $profile->sandbox();
+       if ($this->debug) {
+           common_log(LOG_WARNING, "AutoSandbox: sandboxed of $user->nickname");
+        }
+    }
+}
diff --git a/plugins/AutoSandbox/LICENSE b/plugins/AutoSandbox/LICENSE
new file mode 100644 (file)
index 0000000..011faa4
--- /dev/null
@@ -0,0 +1,21 @@
+Copyright (c) 2010 Stubborn Mule - http://www.stubbornmule.net
+AUTHORS:
+   Sean Carmody
+
+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.
diff --git a/plugins/AutoSandbox/README b/plugins/AutoSandbox/README
new file mode 100644 (file)
index 0000000..2f5d625
--- /dev/null
@@ -0,0 +1,39 @@
+StatusNet AutoSandbox plugin 0.1 03/16/10
+=========================================
+Automatically sandboxes newly registered users as a spam-management technique.
+Only really suits small sites where all users can be hand-moderated. A moderator
+will then have to unbox legimate users, using the following built-in script:
+
+./scripts/userrole.php -n username -r moderator
+
+(replace 'username' with the nickname of the user you wish to make a moderator).
+
+The following note will be added to the top of the Registration form:
+
+"Note you will initially be "sandboxed" so your posts will not appear in the
+public timeline."
+
+This can be followed by the following extra information if a contact user (denoted
+here by XXX) is specified:
+
+"Send a message to @XXX to speed up the unsandboxing process."
+
+If no contact user is specified, it will default to the "Default subscription" user
+who automatically subscribes to new users (set in Admin -> User).
+
+Use:
+1. Add plugin:
+
+Default usage:
+addPlugin('AutoSandbox');
+
+Specify a contact user (replace 'someuser' with appropriate username):
+addPlugin('AutoSandbox', array('contact' => 'someuser'));
+
+Stop contact user from defaulting to the Defaul subscription:
+addPlugin('AutoSandbox', array('contact' => ''));
+
+Changelog
+=========
+0.1 initial release
+
diff --git a/plugins/AutoSandbox/locale/AutoSandbox.pot b/plugins/AutoSandbox/locale/AutoSandbox.pot
new file mode 100644 (file)
index 0000000..b01f9dc
--- /dev/null
@@ -0,0 +1,21 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: AutoSandboxPlugin.php:66
+msgid "Automatically sandboxes newly registered members."
+msgstr ""
index d586631a4a09dd4542784c1c7c0c2b239c9b137c..b2b18bf275681c76bcd13d836ec504f9a7d50259 100644 (file)
@@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
     exit(1);
 }
 
-require_once(INSTALLDIR.'/plugins/Autocomplete/autocomplete.php');
-
 class AutocompletePlugin extends Plugin
 {
     function __construct()
@@ -40,6 +38,16 @@ class AutocompletePlugin extends Plugin
         parent::__construct();
     }
 
+    function onAutoload($cls)
+    {
+        switch ($cls)
+        {
+         case 'AutocompleteAction':
+            require_once(INSTALLDIR.'/plugins/Autocomplete/autocomplete.php');
+            return false;
+        }
+    }
+
     function onEndShowScripts($action){
         if (common_logged_in()) {
             $action->script('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js');
diff --git a/plugins/Autocomplete/locale/Autocomplete.pot b/plugins/Autocomplete/locale/Autocomplete.pot
new file mode 100644 (file)
index 0000000..c0274af
--- /dev/null
@@ -0,0 +1,24 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: AutocompletePlugin.php:79
+msgid ""
+"The autocomplete plugin allows users to autocomplete screen names in @ "
+"replies. When an \"@\" is typed into the notice text area, an autocomplete "
+"box is displayed populated with the user's friend' screen names."
+msgstr ""
diff --git a/plugins/BitlyUrl/locale/BitlyUrl.pot b/plugins/BitlyUrl/locale/BitlyUrl.pot
new file mode 100644 (file)
index 0000000..2802375
--- /dev/null
@@ -0,0 +1,22 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: BitlyUrlPlugin.php:60
+#, php-format
+msgid "Uses <a href=\"http://%1$s/\">%1$s</a> URL-shortener service."
+msgstr ""
diff --git a/plugins/Blacklist/locale/Blacklist.pot b/plugins/Blacklist/locale/Blacklist.pot
new file mode 100644 (file)
index 0000000..90eda09
--- /dev/null
@@ -0,0 +1,54 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: BlacklistPlugin.php:153
+#, php-format
+msgid "You may not register with homepage '%s'"
+msgstr ""
+
+#: BlacklistPlugin.php:163
+#, php-format
+msgid "You may not register with nickname '%s'"
+msgstr ""
+
+#: BlacklistPlugin.php:188
+#, php-format
+msgid "You may not use homepage '%s'"
+msgstr ""
+
+#: BlacklistPlugin.php:198
+#, php-format
+msgid "You may not use nickname '%s'"
+msgstr ""
+
+#: BlacklistPlugin.php:242
+#, php-format
+msgid "You may not use url '%s' in notices"
+msgstr ""
+
+#: BlacklistPlugin.php:351
+msgid "Keep a blacklist of forbidden nickname and URL patterns."
+msgstr ""
+
+#: blacklistadminpanel.php:185
+msgid "Nicknames"
+msgstr ""
+
+#: blacklistadminpanel.php:193
+msgid "URLs"
+msgstr ""
diff --git a/plugins/CasAuthentication/locale/CasAuthentication.pot b/plugins/CasAuthentication/locale/CasAuthentication.pot
new file mode 100644 (file)
index 0000000..20a2bf2
--- /dev/null
@@ -0,0 +1,35 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: CasAuthenticationPlugin.php:82
+msgid "CAS"
+msgstr ""
+
+#: CasAuthenticationPlugin.php:83
+msgid "Login or register with CAS"
+msgstr ""
+
+#: CasAuthenticationPlugin.php:150
+msgid ""
+"The CAS Authentication plugin allows for StatusNet to handle authentication "
+"through CAS (Central Authentication Service)."
+msgstr ""
+
+#: caslogin.php:28
+msgid "Already logged in."
+msgstr ""
diff --git a/plugins/ClientSideShorten/ClientSideShortenPlugin.php b/plugins/ClientSideShorten/ClientSideShortenPlugin.php
new file mode 100644 (file)
index 0000000..ba1f7d3
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to enable client side url shortening in the status box
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Craig Andrews http://candrews.integralblue.com
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+require_once(INSTALLDIR.'/plugins/ClientSideShorten/shorten.php');
+
+class ClientSideShortenPlugin extends Plugin
+{
+    function __construct()
+    {
+        parent::__construct();
+    }
+
+    function onAutoload($cls)
+    {
+        switch ($cls)
+        {
+         case 'ShortenAction':
+            require_once(INSTALLDIR.'/plugins/ClientSideShorten/shorten.php');
+            return false;
+        }
+    }
+
+    function onEndShowScripts($action){
+        $action->inlineScript('var Notice_maxContent = ' . Notice::maxContent());
+        if (common_logged_in()) {
+            $action->script('plugins/ClientSideShorten/shorten.js');
+        }
+    }
+
+    function onRouterInitialized($m)
+    {
+        if (common_logged_in()) {
+            $m->connect('plugins/ClientSideShorten/shorten', array('action'=>'shorten'));
+        }
+    }
+
+    function onPluginVersion(&$versions)
+    {
+        $versions[] = array('name' => 'Shorten',
+                            'version' => STATUSNET_VERSION,
+                            'author' => 'Craig Andrews',
+                            'homepage' => 'http://status.net/wiki/Plugin:ClientSideShorten',
+                            'rawdescription' =>
+                            _m('ClientSideShorten causes the web interface\'s notice form to automatically shorten urls as they entered, and before the notice is submitted.'));
+        return true;
+    }
+
+}
+
diff --git a/plugins/ClientSideShorten/README b/plugins/ClientSideShorten/README
new file mode 100644 (file)
index 0000000..e6524c9
--- /dev/null
@@ -0,0 +1,6 @@
+ClientSideShorten causes the web interface's notice form to automatically shorten urls as they entered, and before the notice is submitted.
+
+Installation
+============
+Add "addPlugin('ClientSideShorten');" to the bottom of your config.php
+That's it!
diff --git a/plugins/ClientSideShorten/locale/ClientSideShorten.pot b/plugins/ClientSideShorten/locale/ClientSideShorten.pot
new file mode 100644 (file)
index 0000000..83caff3
--- /dev/null
@@ -0,0 +1,27 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ClientSideShortenPlugin.php:74
+msgid ""
+"ClientSideShorten causes the web interface's notice form to automatically "
+"shorten urls as they entered, and before the notice is submitted."
+msgstr ""
+
+#: shorten.php:55
+msgid "'text' argument must be specified."
+msgstr ""
diff --git a/plugins/ClientSideShorten/shorten.js b/plugins/ClientSideShorten/shorten.js
new file mode 100644 (file)
index 0000000..856c7f0
--- /dev/null
@@ -0,0 +1,66 @@
+//wrap everything in a self-executing anonymous function to avoid conflicts
+(function(){
+
+    // smart(x) from Paul Irish
+    // http://paulirish.com/2009/throttled-smartresize-jquery-event-handler/
+
+    (function($,sr){
+
+        // debouncing function from John Hann
+        // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
+        var debounce = function (func, threshold, execAsap) {
+            var timeout;
+
+            return function debounced () {
+                var obj = this, args = arguments;
+                function delayed () {
+                    if (!execAsap)
+                        func.apply(obj, args);
+                        timeout = null; 
+                };
+
+                if (timeout)
+                    clearTimeout(timeout);
+                else if (execAsap)
+                    func.apply(obj, args);
+
+                timeout = setTimeout(delayed, threshold || 100); 
+            };
+        }
+        jQuery.fn[sr] = function(fn){  return fn ? this.bind('keypress', debounce(fn, 1000)) : this.trigger(sr); };
+
+    })(jQuery,'smartkeypress');
+
+    function shorten()
+    {
+        $noticeDataText = $('#'+SN.C.S.NoticeDataText);
+        if(Notice_maxContent > 0 && $noticeDataText.val().length > Notice_maxContent){
+            var original = $noticeDataText.val();
+            shortenAjax = $.ajax({
+                url: $('address .url')[0].href+'/plugins/ClientSideShorten/shorten',
+                data: { text: $noticeDataText.val() },
+                dataType: 'text',
+                success: function(data) {
+                    if(original == $noticeDataText.val()) {
+                        $noticeDataText.val(data).keyup();
+                    }
+                }
+            });
+        }
+    }
+
+    $(document).ready(function(){
+        $noticeDataText = $('#'+SN.C.S.NoticeDataText);
+        $noticeDataText.smartkeypress(function(e){
+            //if(typeof(shortenAjax) !== 'undefined') shortenAjax.abort();
+            if(e.charCode == '32') {
+                shorten();
+            }
+        });
+        $noticeDataText.bind('paste', function() {
+            //if(typeof(shortenAjax) !== 'undefined') shortenAjax.abort();
+            setTimeout(shorten,1);
+        });
+    });
+
+})();
diff --git a/plugins/ClientSideShorten/shorten.php b/plugins/ClientSideShorten/shorten.php
new file mode 100644 (file)
index 0000000..07c19e2
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List users for autocompletion
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+/**
+ * Shorten all URLs in a string
+ *
+ * @category Plugin
+ * @package  StatusNet
+ * @author   Craig Andrews <candrews@integralblue.com>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+
+class ShortenAction extends Action
+{
+    private $text;
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+        $this->groups=array();
+        $this->users=array();
+        $this->text = $this->arg('text');
+        if(is_null($this->text)){
+            throw new ClientException(_m('\'text\' argument must be specified.'));
+        }
+        return true;
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+        header('Content-Type: text/plain');
+        $shortened_text = common_shorten_links($this->text);
+        print $shortened_text;
+    }
+}
+
diff --git a/plugins/DirectionDetector/locale/DirectionDetector.pot b/plugins/DirectionDetector/locale/DirectionDetector.pot
new file mode 100644 (file)
index 0000000..ebeda2d
--- /dev/null
@@ -0,0 +1,21 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: DirectionDetectorPlugin.php:221
+msgid "shows notices with right-to-left content in correct direction."
+msgstr ""
diff --git a/plugins/EmailAuthentication/locale/EmailAuthentication.pot b/plugins/EmailAuthentication/locale/EmailAuthentication.pot
new file mode 100644 (file)
index 0000000..d945e25
--- /dev/null
@@ -0,0 +1,23 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: EmailAuthenticationPlugin.php:61
+msgid ""
+"The Email Authentication plugin allows users to login using their email "
+"address."
+msgstr ""
index 4bc00248c95478f5727a5c71620fe47d845eb4b4..dce10d230fa1d8731196d550850fdd5a47a2e7da 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,72 +16,129 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: facebookaction.php:171
-msgid "Home"
+#: facebookutil.php:285
+#, php-format
+msgid ""
+"Hi, %1$s. We're sorry to inform you that we are unable to update your "
+"Facebook status from %2$s, and have disabled the Facebook application for "
+"your account. This may be because you have removed the Facebook "
+"application's authorization, or have deleted your Facebook account.  You can "
+"re-enable the Facebook application and automatic status updating by re-"
+"installing the %2$s Facebook application.\n"
+"\n"
+"Regards,\n"
+"\n"
+"%2$s"
 msgstr ""
 
-#: facebookaction.php:179
-msgid "Invite"
+#: FBConnectAuth.php:51
+msgid "You must be logged into Facebook to use Facebook Connect."
 msgstr ""
 
-#: facebookaction.php:188
-msgid "Settings"
+#: FBConnectAuth.php:77
+msgid "There is already a local user linked with this Facebook."
 msgstr ""
 
-#: facebookaction.php:228
+#: FBConnectAuth.php:90 FBConnectSettings.php:164
+msgid "There was a problem with your session token. Try again, please."
+msgstr ""
+
+#: FBConnectAuth.php:95
+msgid "You can't register if you don't agree to the license."
+msgstr ""
+
+#: FBConnectAuth.php:105
+msgid "Something weird happened."
+msgstr ""
+
+#: FBConnectAuth.php:119
 #, php-format
 msgid ""
-"To use the %s Facebook Application you need to login with your username and "
-"password. Don't have a username yet? "
+"This is the first time you've logged into %s so we must connect your "
+"Facebook to a local account. You can either create a new account, or connect "
+"with your existing account, if you have one."
 msgstr ""
 
-#: facebookaction.php:230
-msgid " a new account."
+#: FBConnectAuth.php:125
+msgid "Facebook Account Setup"
 msgstr ""
 
-#: facebookaction.php:236
-msgid "Register"
+#: FBConnectAuth.php:158
+msgid "Connection options"
 msgstr ""
 
-#: facebookaction.php:249 facebookaction.php:275 facebooklogin.php:91
-msgid "Login"
+#: FBConnectAuth.php:183
+msgid "Create new account"
 msgstr ""
 
-#: facebookaction.php:268
-msgid "Nickname"
+#: FBConnectAuth.php:185
+msgid "Create a new user with this nickname."
 msgstr ""
 
-#: facebookaction.php:271 FBConnectAuth.php:196
+#: FBConnectAuth.php:188
+msgid "New nickname"
+msgstr ""
+
+#: FBConnectAuth.php:190
+msgid "1-64 lowercase letters or numbers, no punctuation or spaces"
+msgstr ""
+
+#: FBConnectAuth.php:193
+msgid "Create"
+msgstr ""
+
+#: FBConnectAuth.php:198
+msgid "Connect existing account"
+msgstr ""
+
+#: FBConnectAuth.php:200
+msgid ""
+"If you already have an account, login with your username and password to "
+"connect it to your Facebook."
+msgstr ""
+
+#: FBConnectAuth.php:203
+msgid "Existing nickname"
+msgstr ""
+
+#: FBConnectAuth.php:206 facebookaction.php:271
 msgid "Password"
 msgstr ""
 
-#: facebookaction.php:281
-msgid "Lost or forgotten password?"
+#: FBConnectAuth.php:209
+msgid "Connect"
 msgstr ""
 
-#: facebookaction.php:330 facebookhome.php:248
-msgid "Pagination"
+#: FBConnectAuth.php:225 FBConnectAuth.php:234
+msgid "Registration not allowed."
 msgstr ""
 
-#: facebookaction.php:339 facebookhome.php:257
-msgid "After"
+#: FBConnectAuth.php:241
+msgid "Not a valid invitation code."
 msgstr ""
 
-#: facebookaction.php:347 facebookhome.php:265
-msgid "Before"
+#: FBConnectAuth.php:251
+msgid "Nickname must have only lowercase letters and numbers and no spaces."
 msgstr ""
 
-#: facebookaction.php:365
-msgid "No notice content!"
+#: FBConnectAuth.php:256
+msgid "Nickname not allowed."
 msgstr ""
 
-#: facebookaction.php:371
-#, php-format
-msgid "That's too long. Max notice size is %d chars."
+#: FBConnectAuth.php:261
+msgid "Nickname already in use. Try another one."
 msgstr ""
 
-#: facebookaction.php:430
-msgid "Notices"
+#: FBConnectAuth.php:279 FBConnectAuth.php:313 FBConnectAuth.php:333
+msgid "Error connecting user to Facebook."
+msgstr ""
+
+#: FBConnectAuth.php:299
+msgid "Invalid username or password."
+msgstr ""
+
+#: facebooklogin.php:91 facebookaction.php:249 facebookaction.php:275
+msgid "Login"
 msgstr ""
 
 #: facebookhome.php:111
@@ -117,6 +174,18 @@ msgstr ""
 msgid "Skip"
 msgstr ""
 
+#: facebookhome.php:248 facebookaction.php:330
+msgid "Pagination"
+msgstr ""
+
+#: facebookhome.php:257 facebookaction.php:339
+msgid "After"
+msgstr ""
+
+#: facebookhome.php:265 facebookaction.php:347
+msgid "Before"
+msgstr ""
+
 #: facebookinvite.php:72
 #, php-format
 msgid "Thanks for inviting your friends to use %s"
@@ -145,208 +214,123 @@ msgstr ""
 msgid "Send invitations"
 msgstr ""
 
-#: FacebookPlugin.php:413 FacebookPlugin.php:433
+#: FacebookPlugin.php:195 FacebookPlugin.php:488 FacebookPlugin.php:510
+#: facebookadminpanel.php:54
 msgid "Facebook"
 msgstr ""
 
-#: FacebookPlugin.php:414
+#: FacebookPlugin.php:196
+msgid "Facebook integration configuration"
+msgstr ""
+
+#: FacebookPlugin.php:489
 msgid "Login or register using Facebook"
 msgstr ""
 
-#: FacebookPlugin.php:434 FBConnectSettings.php:56
+#: FacebookPlugin.php:511 FBConnectSettings.php:56
 msgid "Facebook Connect Settings"
 msgstr ""
 
-#: FacebookPlugin.php:533
+#: FacebookPlugin.php:617
 msgid ""
 "The Facebook plugin allows you to integrate your StatusNet instance with <a "
 "href=\"http://facebook.com/\">Facebook</a> and Facebook Connect."
 msgstr ""
 
-#: facebookremove.php:58
-msgid "Couldn't remove Facebook user."
-msgstr ""
-
-#: facebooksettings.php:74
-msgid "There was a problem saving your sync preferences!"
-msgstr ""
-
-#: facebooksettings.php:76
-msgid "Sync preferences saved."
-msgstr ""
-
-#: facebooksettings.php:99
-msgid "Automatically update my Facebook status with my notices."
-msgstr ""
-
-#: facebooksettings.php:106
-msgid "Send \"@\" replies to Facebook."
+#: FBConnectLogin.php:33
+msgid "Already logged in."
 msgstr ""
 
-#: facebooksettings.php:115
-msgid "Prefix"
+#: FBConnectLogin.php:41
+msgid "Login with your Facebook Account"
 msgstr ""
 
-#: facebooksettings.php:117
-msgid "A string to prefix notices with."
+#: FBConnectLogin.php:55
+msgid "Facebook Login"
 msgstr ""
 
-#: facebooksettings.php:123
-msgid "Save"
+#: facebookremove.php:58
+msgid "Couldn't remove Facebook user."
 msgstr ""
 
-#: facebooksettings.php:133
-#, php-format
-msgid ""
-"If you would like %s to automatically update your Facebook status with your "
-"latest notice, you need to give it permission."
+#: facebookaction.php:171
+msgid "Home"
 msgstr ""
 
-#: facebooksettings.php:146
-#, php-format
-msgid "Allow %s to update my Facebook status"
+#: facebookaction.php:179
+msgid "Invite"
 msgstr ""
 
-#: facebooksettings.php:156
-msgid "Sync preferences"
+#: facebookaction.php:188
+msgid "Settings"
 msgstr ""
 
-#: facebookutil.php:285
+#: facebookaction.php:228
 #, php-format
 msgid ""
-"Hi, %1$s. We're sorry to inform you that we are unable to update your "
-"Facebook status from %2$s, and have disabled the Facebook application for "
-"your account. This may be because you have removed the Facebook "
-"application's authorization, or have deleted your Facebook account.  You can "
-"re-enable the Facebook application and automatic status updating by re-"
-"installing the %2$s Facebook application.\n"
-"\n"
-"Regards,\n"
-"\n"
-"%2$s"
+"To use the %s Facebook Application you need to login with your username and "
+"password. Don't have a username yet? "
 msgstr ""
 
-#: FBConnectAuth.php:51
-msgid "You must be logged into Facebook to use Facebook Connect."
+#: facebookaction.php:230
+msgid " a new account."
 msgstr ""
 
-#: FBConnectAuth.php:77
-msgid "There is already a local user linked with this Facebook."
+#: facebookaction.php:236
+msgid "Register"
 msgstr ""
 
-#: FBConnectAuth.php:90 FBConnectSettings.php:164
-msgid "There was a problem with your session token. Try again, please."
+#: facebookaction.php:268
+msgid "Nickname"
 msgstr ""
 
-#: FBConnectAuth.php:95
-msgid "You can't register if you don't agree to the license."
+#: facebookaction.php:281
+msgid "Lost or forgotten password?"
 msgstr ""
 
-#: FBConnectAuth.php:105
-msgid "Something weird happened."
+#: facebookaction.php:365
+msgid "No notice content!"
 msgstr ""
 
-#: FBConnectAuth.php:119
+#: facebookaction.php:371
 #, php-format
-msgid ""
-"This is the first time you've logged into %s so we must connect your "
-"Facebook to a local account. You can either create a new account, or connect "
-"with your existing account, if you have one."
-msgstr ""
-
-#: FBConnectAuth.php:125
-msgid "Facebook Account Setup"
-msgstr ""
-
-#: FBConnectAuth.php:153
-msgid "Connection options"
-msgstr ""
-
-#: FBConnectAuth.php:162
-msgid "My text and files are available under "
-msgstr ""
-
-#: FBConnectAuth.php:165
-msgid ""
-" except this private data: password, email address, IM address, phone number."
-msgstr ""
-
-#: FBConnectAuth.php:173
-msgid "Create new account"
-msgstr ""
-
-#: FBConnectAuth.php:175
-msgid "Create a new user with this nickname."
-msgstr ""
-
-#: FBConnectAuth.php:178
-msgid "New nickname"
-msgstr ""
-
-#: FBConnectAuth.php:180
-msgid "1-64 lowercase letters or numbers, no punctuation or spaces"
-msgstr ""
-
-#: FBConnectAuth.php:183
-msgid "Create"
-msgstr ""
-
-#: FBConnectAuth.php:188
-msgid "Connect existing account"
-msgstr ""
-
-#: FBConnectAuth.php:190
-msgid ""
-"If you already have an account, login with your username and password to "
-"connect it to your Facebook."
-msgstr ""
-
-#: FBConnectAuth.php:193
-msgid "Existing nickname"
-msgstr ""
-
-#: FBConnectAuth.php:199
-msgid "Connect"
-msgstr ""
-
-#: FBConnectAuth.php:215 FBConnectAuth.php:224
-msgid "Registration not allowed."
+msgid "That's too long. Max notice size is %d chars."
 msgstr ""
 
-#: FBConnectAuth.php:231
-msgid "Not a valid invitation code."
+#: facebookaction.php:430
+msgid "Notices"
 msgstr ""
 
-#: FBConnectAuth.php:241
-msgid "Nickname must have only lowercase letters and numbers and no spaces."
+#: facebookadminpanel.php:65
+msgid "Facebook integration settings"
 msgstr ""
 
-#: FBConnectAuth.php:246
-msgid "Nickname not allowed."
+#: facebookadminpanel.php:129
+msgid "Invalid Facebook API key. Max length is 255 characters."
 msgstr ""
 
-#: FBConnectAuth.php:251
-msgid "Nickname already in use. Try another one."
+#: facebookadminpanel.php:135
+msgid "Invalid Facebook API secret. Max length is 255 characters."
 msgstr ""
 
-#: FBConnectAuth.php:269 FBConnectAuth.php:303 FBConnectAuth.php:323
-msgid "Error connecting user to Facebook."
+#: facebookadminpanel.php:188
+msgid "Facebook application settings"
 msgstr ""
 
-#: FBConnectAuth.php:289
-msgid "Invalid username or password."
+#: facebookadminpanel.php:194
+msgid "API key"
 msgstr ""
 
-#: FBConnectLogin.php:33
-msgid "Already logged in."
+#: facebookadminpanel.php:195
+msgid "API key provided by Facebook"
 msgstr ""
 
-#: FBConnectLogin.php:41
-msgid "Login with your Facebook Account"
+#: facebookadminpanel.php:203
+msgid "Secret"
 msgstr ""
 
-#: FBConnectLogin.php:55
-msgid "Facebook Login"
+#: facebookadminpanel.php:204
+msgid "API secret provided by Facebook"
 msgstr ""
 
 #: FBConnectSettings.php:67
@@ -393,3 +377,47 @@ msgstr ""
 #: FBConnectSettings.php:197
 msgid "Not sure what you're trying to do."
 msgstr ""
+
+#: facebooksettings.php:74
+msgid "There was a problem saving your sync preferences!"
+msgstr ""
+
+#: facebooksettings.php:76
+msgid "Sync preferences saved."
+msgstr ""
+
+#: facebooksettings.php:99
+msgid "Automatically update my Facebook status with my notices."
+msgstr ""
+
+#: facebooksettings.php:106
+msgid "Send \"@\" replies to Facebook."
+msgstr ""
+
+#: facebooksettings.php:115
+msgid "Prefix"
+msgstr ""
+
+#: facebooksettings.php:117
+msgid "A string to prefix notices with."
+msgstr ""
+
+#: facebooksettings.php:123
+msgid "Save"
+msgstr ""
+
+#: facebooksettings.php:133
+#, php-format
+msgid ""
+"If you would like %s to automatically update your Facebook status with your "
+"latest notice, you need to give it permission."
+msgstr ""
+
+#: facebooksettings.php:146
+#, php-format
+msgid "Allow %s to update my Facebook status"
+msgstr ""
+
+#: facebooksettings.php:156
+msgid "Sync preferences"
+msgstr ""
index 452f7902422392507fd5c21901c0e306b112e750..9143ff69caafebb3dbeb9093e6826eb1697897e0 100644 (file)
@@ -52,8 +52,8 @@ class FirePHPPlugin extends Plugin
     {
         static $firephp_priorities = array(FirePHP::ERROR, FirePHP::ERROR, FirePHP::ERROR, FirePHP::ERROR,
                                       FirePHP::WARN, FirePHP::LOG, FirePHP::LOG, FirePHP::INFO);
-        $priority = $firephp_priorities[$priority];
-        $this->firephp->fb($msg, $priority);
+        $fp_priority = $firephp_priorities[$priority];
+        $this->firephp->fb($msg, $fp_priority);
     }
 
     function onPluginVersion(&$versions)
diff --git a/plugins/FirePHP/locale/FirePHP.pot b/plugins/FirePHP/locale/FirePHP.pot
new file mode 100644 (file)
index 0000000..fa16f28
--- /dev/null
@@ -0,0 +1,21 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: FirePHPPlugin.php:66
+msgid "The FirePHP plugin writes StatusNet's log output to FirePHP."
+msgstr ""
index d7275b9290816c43d0cae0daa8fb1f99a48b8bbb..d3a4cd86b8350792fe77e10f91ae136bda8d6dcc 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
diff --git a/plugins/Imap/locale/Imap.pot b/plugins/Imap/locale/Imap.pot
new file mode 100644 (file)
index 0000000..ee8452a
--- /dev/null
@@ -0,0 +1,27 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: imapmailhandler.php:28
+msgid "Error"
+msgstr ""
+
+#: ImapPlugin.php:101
+msgid ""
+"The IMAP plugin allows for StatusNet to check a POP or IMAP mailbox for "
+"incoming mail containing user posts."
+msgstr ""
diff --git a/plugins/InfiniteScroll/locale/InfiniteScroll.pot b/plugins/InfiniteScroll/locale/InfiniteScroll.pot
new file mode 100644 (file)
index 0000000..a0f466f
--- /dev/null
@@ -0,0 +1,25 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: InfiniteScrollPlugin.php:54
+msgid ""
+"Infinite Scroll adds the following functionality to your StatusNet "
+"installation: When a user scrolls towards the bottom of the page, the next "
+"page of notices is automatically retrieved and appended. This means they "
+"never need to click \"Next Page\", which dramatically increases stickiness."
+msgstr ""
index 483209676575af0c1bb4c398b6c827124a1021a1..0dfc4c63be15437841b6705871da3af637088eca 100644 (file)
@@ -31,48 +31,25 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
     exit(1);
 }
 
-require_once 'Net/LDAP2.php';
-
 class LdapAuthenticationPlugin extends AuthenticationPlugin
 {
-    public $host=null;
-    public $port=null;
-    public $version=null;
-    public $starttls=null;
-    public $binddn=null;
-    public $bindpw=null;
-    public $basedn=null;
-    public $options=null;
-    public $filter=null;
-    public $scope=null;
-    public $password_encoding=null;
-    public $attributes=array();
-
     function onInitializePlugin(){
         parent::onInitializePlugin();
-        if(!isset($this->host)){
-            throw new Exception("must specify a host");
-        }
-        if(!isset($this->basedn)){
-            throw new Exception("must specify a basedn");
-        }
         if(!isset($this->attributes['nickname'])){
             throw new Exception("must specify a nickname attribute");
         }
-        if(!isset($this->attributes['username'])){
-            throw new Exception("must specify a username attribute");
-        }
         if($this->password_changeable && (! isset($this->attributes['password']) || !isset($this->password_encoding))){
             throw new Exception("if password_changeable is set, the password attribute and password_encoding must also be specified");
         }
+        $this->ldapCommon = new LdapCommon(get_object_vars($this));
     }
 
     function onAutoload($cls)
     {   
         switch ($cls)
         {
-         case 'MemcacheSchemaCache':
-            require_once(INSTALLDIR.'/plugins/LdapAuthentication/MemcacheSchemaCache.php');
+         case 'LdapCommon':
+            require_once(INSTALLDIR.'/plugins/LdapCommon/LdapCommon.php');
             return false;
         }
     }
@@ -107,19 +84,7 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
 
     function checkPassword($username, $password)
     {
-        $entry = $this->ldap_get_user($username);
-        if(!$entry){
-            return false;
-        }else{
-            $config = $this->ldap_get_config();
-            $config['binddn']=$entry->dn();
-            $config['bindpw']=$password;
-            if($this->ldap_get_connection($config)){
-                return true;
-            }else{
-                return false;
-            }
-        }
+        return $this->ldapCommon->checkPassword($username,$password);
     }
 
     function autoRegister($username, $nickname)
@@ -127,11 +92,16 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
         if(is_null($nickname)){
             $nickname = $username;
         }
-        $entry = $this->ldap_get_user($username,$this->attributes);
+        $entry = $this->ldapCommon->get_user($username,$this->attributes);
         if($entry){
             $registration_data = array();
             foreach($this->attributes as $sn_attribute=>$ldap_attribute){
-                $registration_data[$sn_attribute]=$entry->getValue($ldap_attribute,'single');
+                //ldap won't let us read a user's password,
+                //and we're going to set the password to a random string later anyways,
+                //so don't bother trying to read it.
+                if($sn_attribute != 'password'){
+                    $registration_data[$sn_attribute]=$entry->getValue($ldap_attribute,'single');
+                }
             }
             if(isset($registration_data['email']) && !empty($registration_data['email'])){
                 $registration_data['email_confirmed']=true;
@@ -148,45 +118,12 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
 
     function changePassword($username,$oldpassword,$newpassword)
     {
-        if(! isset($this->attributes['password']) || !isset($this->password_encoding)){
-            //throw new Exception(_('Sorry, changing LDAP passwords is not supported at this time'));
-            return false;
-        }
-        $entry = $this->ldap_get_user($username);
-        if(!$entry){
-            return false;
-        }else{
-            $config = $this->ldap_get_config();
-            $config['binddn']=$entry->dn();
-            $config['bindpw']=$oldpassword;
-            if($ldap = $this->ldap_get_connection($config)){
-                $entry = $this->ldap_get_user($username,array(),$ldap);
-                
-                $newCryptedPassword = $this->hashPassword($newpassword, $this->password_encoding);
-                if ($newCryptedPassword===false) {
-                    return false;
-                }
-                if($this->password_encoding=='ad') {
-                    //TODO I believe this code will work once this bug is fixed: http://pear.php.net/bugs/bug.php?id=16796
-                    $oldCryptedPassword = $this->hashPassword($oldpassword, $this->password_encoding);
-                    $entry->delete( array($this->attributes['password'] => $oldCryptedPassword ));
-                }
-                $entry->replace( array($this->attributes['password'] => $newCryptedPassword ), true);
-                if( Net_LDAP2::isError($entry->upate()) ) {
-                    return false;
-                }
-                return true;
-            }else{
-                return false;
-            }
-        }
-
-        return false;
+        return $this->ldapCommon->changePassword($username,$oldpassword,$newpassword);
     }
 
     function suggestNicknameForUsername($username)
     {
-        $entry = $this->ldap_get_user($username, $this->attributes);
+        $entry = $this->ldapCommon->get_user($username, $this->attributes);
         if(!$entry){
             //this really shouldn't happen
             $nickname = $username;
@@ -198,203 +135,6 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
         }
         return common_nicknamize($nickname);
     }
-    
-    //---utility functions---//
-    function ldap_get_config(){
-        $config = array();
-        $keys = array('host','port','version','starttls','binddn','bindpw','basedn','options','filter','scope');
-        foreach($keys as $key){
-            $value = $this->$key;
-            if($value!==null){
-                $config[$key]=$value;
-            }
-        }
-        return $config;
-    }
-    
-    function ldap_get_connection($config = null){
-        if($config == null && isset($this->default_ldap)){
-            return $this->default_ldap;
-        }
-        
-        //cannot use Net_LDAP2::connect() as StatusNet uses
-        //PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
-        //PEAR handling can be overridden on instance objects, so we do that.
-        $ldap = new Net_LDAP2(isset($config)?$config:$this->ldap_get_config());
-        $ldap->setErrorHandling(PEAR_ERROR_RETURN);
-        $err=$ldap->bind();
-        if (Net_LDAP2::isError($err)) {
-            // if we were called with a config, assume caller will handle
-            // incorrect username/password (LDAP_INVALID_CREDENTIALS)
-            if (isset($config) && $err->getCode() == 0x31) {
-                return null;
-            }
-            throw new Exception('Could not connect to LDAP server: '.$err->getMessage());
-        }
-        if($config == null) $this->default_ldap=$ldap;
-
-        $c = common_memcache();
-        if (!empty($c)) {
-            $cacheObj = new MemcacheSchemaCache(
-                array('c'=>$c,
-                   'cacheKey' => common_cache_key('ldap_schema:' . crc32(serialize($config)))));
-            $ldap->registerSchemaCache($cacheObj);
-        }
-        return $ldap;
-    }
-    
-    /**
-     * get an LDAP entry for a user with a given username
-     * 
-     * @param string $username
-     * $param array $attributes LDAP attributes to retrieve
-     * @return string DN
-     */
-    function ldap_get_user($username,$attributes=array(),$ldap=null){
-        if($ldap==null) {
-            $ldap = $this->ldap_get_connection();
-        }
-        $filter = Net_LDAP2_Filter::create($this->attributes['username'], 'equals',  $username);
-        $options = array(
-            'attributes' => $attributes
-        );
-        $search = $ldap->search($this->basedn, $filter, $options);
-        
-        if (PEAR::isError($search)) {
-            common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
-            return false;
-        }
-
-        $searchcount = $search->count();
-        if($searchcount == 0) {
-            return false;
-        }else if($searchcount == 1) {
-            $entry = $search->shiftEntry();
-            return $entry;
-        }else{
-            common_log(LOG_WARNING, 'Found ' . $searchcount . ' ldap user with the username: ' . $username);
-            return false;
-        }
-    }
-    
-    /**
-     * Code originaly from the phpLDAPadmin development team
-     * http://phpldapadmin.sourceforge.net/
-     *
-     * Hashes a password and returns the hash based on the specified enc_type.
-     *
-     * @param string $passwordClear The password to hash in clear text.
-     * @param string $encodageType Standard LDAP encryption type which must be one of
-     *        crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, or clear.
-     * @return string The hashed password.
-     *
-     */
-
-    function hashPassword( $passwordClear, $encodageType ) 
-    {
-        $encodageType = strtolower( $encodageType );
-        switch( $encodageType ) {
-            case 'crypt': 
-                $cryptedPassword = '{CRYPT}' . crypt($passwordClear,$this->randomSalt(2)); 
-                break;
-                
-            case 'ext_des':
-                // extended des crypt. see OpenBSD crypt man page.
-                if ( ! defined( 'CRYPT_EXT_DES' ) || CRYPT_EXT_DES == 0 ) {return FALSE;} //Your system crypt library does not support extended DES encryption.
-                $cryptedPassword = '{CRYPT}' . crypt( $passwordClear, '_' . $this->randomSalt(8) );
-                break;
-
-            case 'md5crypt':
-                if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 ) {return FALSE;} //Your system crypt library does not support md5crypt encryption.
-                $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$1$' . $this->randomSalt(9) );
-                break;
-
-            case 'blowfish':
-                if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 ) {return FALSE;} //Your system crypt library does not support blowfish encryption.
-                $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$2a$12$' . $this->randomSalt(13) ); // hardcoded to second blowfish version and set number of rounds
-                break;
-
-            case 'md5':
-                $cryptedPassword = '{MD5}' . base64_encode( pack( 'H*' , md5( $passwordClear) ) );
-                break;
-
-            case 'sha':
-                if( function_exists('sha1') ) {
-                    // use php 4.3.0+ sha1 function, if it is available.
-                    $cryptedPassword = '{SHA}' . base64_encode( pack( 'H*' , sha1( $passwordClear) ) );
-                } elseif( function_exists( 'mhash' ) ) {
-                    $cryptedPassword = '{SHA}' . base64_encode( mhash( MHASH_SHA1, $passwordClear) );
-                } else {
-                    return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes.
-                }
-                break;
-
-            case 'ssha':
-                if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) {
-                    mt_srand( (double) microtime() * 1000000 );
-                    $salt = mhash_keygen_s2k( MHASH_SHA1, $passwordClear, substr( pack( "h*", md5( mt_rand() ) ), 0, 8 ), 4 );
-                    $cryptedPassword = "{SSHA}".base64_encode( mhash( MHASH_SHA1, $passwordClear.$salt ).$salt );
-                } else {
-                    return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes.
-                }
-                break;
-
-            case 'smd5':
-                if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) {
-                    mt_srand( (double) microtime() * 1000000 );
-                    $salt = mhash_keygen_s2k( MHASH_MD5, $passwordClear, substr( pack( "h*", md5( mt_rand() ) ), 0, 8 ), 4 );
-                    $cryptedPassword = "{SMD5}".base64_encode( mhash( MHASH_MD5, $passwordClear.$salt ).$salt );
-                } else {
-                    return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes.
-                }
-                break;
-
-            case 'ad':
-                $cryptedPassword = '';
-                $passwordClear = "\"" . $passwordClear . "\"";
-                $len = strlen($passwordClear);
-                for ($i = 0; $i < $len; $i++) {
-                    $cryptedPassword .= "{$passwordClear{$i}}\000";
-                }
-
-            case 'clear':
-            default:
-                $cryptedPassword = $passwordClear;
-        }
-
-        return $cryptedPassword;
-    }
-
-    /**
-     * Code originaly from the phpLDAPadmin development team
-     * http://phpldapadmin.sourceforge.net/
-     *
-     * Used to generate a random salt for crypt-style passwords. Salt strings are used
-     * to make pre-built hash cracking dictionaries difficult to use as the hash algorithm uses
-     * not only the user's password but also a randomly generated string. The string is
-     * stored as the first N characters of the hash for reference of hashing algorithms later.
-     *
-     * --- added 20021125 by bayu irawan <bayuir@divnet.telkom.co.id> ---
-     * --- ammended 20030625 by S C Rigler <srigler@houston.rr.com> ---
-     *
-     * @param int $length The length of the salt string to generate.
-     * @return string The generated salt string.
-     */
-     
-    function randomSalt( $length ) 
-    {
-        $possible = '0123456789'.
-            'abcdefghijklmnopqrstuvwxyz'.
-            'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
-            './';
-        $str = "";
-        mt_srand((double)microtime() * 1000000);
-
-        while( strlen( $str ) < $length )
-            $str .= substr( $possible, ( rand() % strlen( $possible ) ), 1 );
-
-        return $str;
-    }
 
     function onPluginVersion(&$versions)
     {
diff --git a/plugins/LdapAuthentication/MemcacheSchemaCache.php b/plugins/LdapAuthentication/MemcacheSchemaCache.php
deleted file mode 100644 (file)
index 6b91d17..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/** 
- * StatusNet, the distributed open-source microblogging tool
- *
- * Cache the LDAP schema in memcache to improve performance
- *
- * PHP version 5
- *
- * LICENCE: 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 <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 Craig Andrews http://candrews.integralblue.com
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-class MemcacheSchemaCache implements Net_LDAP2_SchemaCache
-{
-    protected $c;
-    protected $cacheKey;
-
-    /**
-    * Initialize the simple cache
-    *
-    * Config is as following:
-    *  memcache     memcache instance
-    *  cachekey  the key in the cache to look at
-    *
-    * @param array $cfg Config array
-    */
-    public function MemcacheSchemaCache($cfg)
-    {
-        $this->c = $cfg['c'];
-        $this->cacheKey = $cfg['cacheKey'];
-    }
-
-    /**
-    * Return the schema object from the cache
-    *
-    * @return Net_LDAP2_Schema|Net_LDAP2_Error|false
-    */
-    public function loadSchema()
-    {
-         return $this->c->get($this->cacheKey);
-    }
-
-    /**
-    * Store a schema object in the cache
-    *
-    * This method will be called, if Net_LDAP2 has fetched a fresh
-    * schema object from LDAP and wants to init or refresh the cache.
-    *
-    * To invalidate the cache and cause Net_LDAP2 to refresh the cache,
-    * you can call this method with null or false as value.
-    * The next call to $ldap->schema() will then refresh the caches object.
-    *
-    * @param mixed $schema The object that should be cached
-    * @return true|Net_LDAP2_Error|false
-    */
-    public function storeSchema($schema) {
-        return $this->c->set($this->cacheKey, $schema);
-    }
-}
diff --git a/plugins/LdapAuthentication/locale/LdapAuthentication.pot b/plugins/LdapAuthentication/locale/LdapAuthentication.pot
new file mode 100644 (file)
index 0000000..8f09b1e
--- /dev/null
@@ -0,0 +1,23 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: LdapAuthenticationPlugin.php:146
+msgid ""
+"The LDAP Authentication plugin allows for StatusNet to handle authentication "
+"through LDAP."
+msgstr ""
index 042b2db8d8796905a8a1df2695d31395ae452d01..97103d158e8c2e0c689cb0f0d31b8abe228c00f2 100644 (file)
@@ -31,41 +31,28 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
     exit(1);
 }
 
-require_once 'Net/LDAP2.php';
-
 class LdapAuthorizationPlugin extends AuthorizationPlugin
 {
-    public $host=null;
-    public $port=null;
-    public $version=null;
-    public $starttls=null;
-    public $binddn=null;
-    public $bindpw=null;
-    public $basedn=null;
-    public $options=null;
-    public $filter=null;
-    public $scope=null;
-    public $provider_name = null;
-    public $uniqueMember_attribute = null;
     public $roles_to_groups = array();
     public $login_group = null;
-    public $attributes = array();
 
     function onInitializePlugin(){
-        if(!isset($this->host)){
-            throw new Exception("must specify a host");
-        }
-        if(!isset($this->basedn)){
-            throw new Exception("must specify a basedn");
-        }
         if(!isset($this->provider_name)){
             throw new Exception("provider_name must be set. Use the provider_name from the LDAP Authentication plugin.");
         }
         if(!isset($this->uniqueMember_attribute)){
             throw new Exception("uniqueMember_attribute must be set.");
         }
-        if(!isset($this->attributes['username'])){
-            throw new Exception("username attribute must be set.");
+        $this->ldapCommon = new LdapCommon(get_object_vars($this));
+    }
+
+    function onAutoload($cls)
+    {
+        switch ($cls)
+        {
+         case 'LdapCommon':
+            require_once(INSTALLDIR.'/plugins/LdapCommon/LdapCommon.php');
+            return false;
         }
     }
 
@@ -75,17 +62,17 @@ class LdapAuthorizationPlugin extends AuthorizationPlugin
         $user_username->user_id=$user->id;
         $user_username->provider_name=$this->provider_name;
         if($user_username->find() && $user_username->fetch()){
-            $entry = $this->ldap_get_user($user_username->username);
+            $entry = $this->ldapCommon->get_user($user_username->username);
             if($entry){
                 if(isset($this->login_group)){
                     if(is_array($this->login_group)){
                         foreach($this->login_group as $group){
-                            if($this->ldap_is_dn_member_of_group($entry->dn(),$group)){
+                            if($this->ldapCommon->is_dn_member_of_group($entry->dn(),$group)){
                                 return true;
                             }
                         }
                     }else{
-                        if($this->ldap_is_dn_member_of_group($entry->dn(),$this->login_group)){
+                        if($this->ldapCommon->is_dn_member_of_group($entry->dn(),$this->login_group)){
                             return true;
                         }
                     }
@@ -107,17 +94,17 @@ class LdapAuthorizationPlugin extends AuthorizationPlugin
         $user_username->user_id=$profile->id;
         $user_username->provider_name=$this->provider_name;
         if($user_username->find() && $user_username->fetch()){
-            $entry = $this->ldap_get_user($user_username->username);
+            $entry = $this->ldapCommon->get_user($user_username->username);
             if($entry){
                 if(isset($this->roles_to_groups[$name])){
                     if(is_array($this->roles_to_groups[$name])){
                         foreach($this->roles_to_groups[$name] as $group){
-                            if($this->ldap_is_dn_member_of_group($entry->dn(),$group)){
+                            if($this->ldapCommon->is_dn_member_of_group($entry->dn(),$group)){
                                 return true;
                             }
                         }
                     }else{
-                        if($this->ldap_is_dn_member_of_group($entry->dn(),$this->roles_to_groups[$name])){
+                        if($this->ldapCommon->is_dn_member_of_group($entry->dn(),$this->roles_to_groups[$name])){
                             return true;
                         }
                     }
@@ -127,94 +114,6 @@ class LdapAuthorizationPlugin extends AuthorizationPlugin
         return false;
     }
 
-    function ldap_is_dn_member_of_group($userDn, $groupDn)
-    {
-        $ldap = $this->ldap_get_connection();
-        $link = $ldap->getLink();
-        $r = @ldap_compare($link, $groupDn, $this->uniqueMember_attribute, $userDn);
-        if ($r === true){
-            return true;
-        }else if($r === false){
-            return false;
-        }else{
-            common_log(LOG_ERR, "LDAP error determining if userDn=$userDn is a member of groupDn=groupDn using uniqueMember_attribute=$this->uniqueMember_attribute error: ".ldap_error($link));
-            return false;
-        }
-    }
-
-    function ldap_get_config(){
-        $config = array();
-        $keys = array('host','port','version','starttls','binddn','bindpw','basedn','options','filter','scope');
-        foreach($keys as $key){
-            $value = $this->$key;
-            if($value!==null){
-                $config[$key]=$value;
-            }
-        }
-        return $config;
-    }
-
-    //-----the below function were copied from LDAPAuthenticationPlugin. They will be moved to a utility class soon.----\\
-    function ldap_get_connection($config = null){
-        if($config == null && isset($this->default_ldap)){
-            return $this->default_ldap;
-        }
-        
-        //cannot use Net_LDAP2::connect() as StatusNet uses
-        //PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
-        //PEAR handling can be overridden on instance objects, so we do that.
-        $ldap = new Net_LDAP2(isset($config)?$config:$this->ldap_get_config());
-        $ldap->setErrorHandling(PEAR_ERROR_RETURN);
-        $err=$ldap->bind();
-        if (Net_LDAP2::isError($err)) {
-            // if we were called with a config, assume caller will handle
-            // incorrect username/password (LDAP_INVALID_CREDENTIALS)
-            if (isset($config) && $err->getCode() == 0x31) {
-                return null;
-            }
-            throw new Exception('Could not connect to LDAP server: '.$err->getMessage());
-            return false;
-        }
-        if($config == null) $this->default_ldap=$ldap;
-        return $ldap;
-    }
-    
-    /**
-     * get an LDAP entry for a user with a given username
-     * 
-     * @param string $username
-     * $param array $attributes LDAP attributes to retrieve
-     * @return string DN
-     */
-    function ldap_get_user($username,$attributes=array(),$ldap=null){
-        if($ldap==null) {
-            $ldap = $this->ldap_get_connection();
-        }
-        if(! $ldap) {
-            throw new Exception("Could not connect to LDAP");
-        }
-        $filter = Net_LDAP2_Filter::create($this->attributes['username'], 'equals',  $username);
-        $options = array(
-            'attributes' => $attributes
-        );
-        $search = $ldap->search(null,$filter,$options);
-        
-        if (PEAR::isError($search)) {
-            common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
-            return false;
-        }
-
-        if($search->count()==0){
-            return false;
-        }else if($search->count()==1){
-            $entry = $search->shiftEntry();
-            return $entry;
-        }else{
-            common_log(LOG_WARNING, 'Found ' . $search->count() . ' ldap user with the username: ' . $username);
-            return false;
-        }
-    }
-
     function onPluginVersion(&$versions)
     {
         $versions[] = array('name' => 'LDAP Authorization',
diff --git a/plugins/LdapAuthorization/locale/LdapAuthorization.pot b/plugins/LdapAuthorization/locale/LdapAuthorization.pot
new file mode 100644 (file)
index 0000000..8156f61
--- /dev/null
@@ -0,0 +1,23 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: LdapAuthorizationPlugin.php:124
+msgid ""
+"The LDAP Authorization plugin allows for StatusNet to handle authorization "
+"through LDAP."
+msgstr ""
diff --git a/plugins/LdapCommon/LdapCommon.php b/plugins/LdapCommon/LdapCommon.php
new file mode 100644 (file)
index 0000000..ee436d8
--- /dev/null
@@ -0,0 +1,369 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Utility class of LDAP functions
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Craig Andrews http://candrews.integralblue.com
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+// We bundle the Net/LDAP2 library...
+set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib');
+
+class LdapCommon
+{
+    protected static $ldap_connections = array();
+    public $host=null;
+    public $port=null;
+    public $version=null;
+    public $starttls=null;
+    public $binddn=null;
+    public $bindpw=null;
+    public $basedn=null;
+    public $options=null;
+    public $filter=null;
+    public $scope=null;
+    public $uniqueMember_attribute = null;
+    public $attributes=array();
+    public $password_encoding=null;
+
+    public function __construct($config)
+    {
+        Event::addHandler('Autoload',array($this,'onAutoload'));
+        foreach($config as $key=>$value) {
+            $this->$key = $value;
+        }
+        $this->ldap_config = $this->get_ldap_config();
+
+        if(!isset($this->host)){
+            throw new Exception("must specify a host");
+        }
+        if(!isset($this->basedn)){
+            throw new Exception("must specify a basedn");
+        }
+        if(!isset($this->attributes['username'])){
+            throw new Exception("username attribute must be set.");
+        }
+    }
+
+    function onAutoload($cls)
+    {
+        switch ($cls)
+        {
+         case 'MemcacheSchemaCache':
+            require_once(INSTALLDIR.'/plugins/LdapCommon/MemcacheSchemaCache.php');
+            return false;
+         case 'Net_LDAP2':
+            require_once 'Net/LDAP2.php';
+            return false;
+         case 'Net_LDAP2_Filter':
+            require_once 'Net/LDAP2/Filter.php';
+            return false;
+         case 'Net_LDAP2_Filter':
+            require_once 'Net/LDAP2/Filter.php';
+            return false;
+         case 'Net_LDAP2_Entry':
+            require_once 'Net/LDAP2/Entry.php';
+            return false;
+        }
+    }
+
+    function get_ldap_config(){
+        $config = array();
+        $keys = array('host','port','version','starttls','binddn','bindpw','basedn','options','filter','scope');
+        foreach($keys as $key){
+            $value = $this->$key;
+            if($value!==null){
+                $config[$key]=$value;
+            }
+        }
+        return $config;
+    }
+
+    function get_ldap_connection($config = null){
+        if($config == null) {
+            $config = $this->ldap_config;
+        }
+        $config_id = crc32(serialize($config));
+        if(array_key_exists($config_id,self::$ldap_connections)) {
+            $ldap = self::$ldap_connections[$config_id];
+        } else {
+            //cannot use Net_LDAP2::connect() as StatusNet uses
+            //PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
+            //PEAR handling can be overridden on instance objects, so we do that.
+            $ldap = new Net_LDAP2($config);
+            $ldap->setErrorHandling(PEAR_ERROR_RETURN);
+            $err=$ldap->bind();
+            if (Net_LDAP2::isError($err)) {
+                // if we were called with a config, assume caller will handle
+                // incorrect username/password (LDAP_INVALID_CREDENTIALS)
+                if (isset($config) && $err->getCode() == 0x31) {
+                    throw new LdapInvalidCredentialsException('Could not connect to LDAP server: '.$err->getMessage());
+                }
+                throw new Exception('Could not connect to LDAP server: '.$err->getMessage());
+            }
+            $c = common_memcache();
+            if (!empty($c)) {
+                $cacheObj = new MemcacheSchemaCache(
+                    array('c'=>$c,
+                       'cacheKey' => common_cache_key('ldap_schema:' . $config_id)));
+                $ldap->registerSchemaCache($cacheObj);
+            }
+            self::$ldap_connections[$config_id] = $ldap;
+        }
+        return $ldap;
+    }
+
+    function checkPassword($username, $password)
+    {
+        $entry = $this->get_user($username);
+        if(!$entry){
+            return false;
+        }else{
+            $config = $this->get_ldap_config();
+            $config['binddn']=$entry->dn();
+            $config['bindpw']=$password;
+            try {
+                $this->get_ldap_connection($config);
+            } catch (LdapInvalidCredentialsException $e) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    function changePassword($username,$oldpassword,$newpassword)
+    {
+        if(! isset($this->attributes['password']) || !isset($this->password_encoding)){
+            //throw new Exception(_('Sorry, changing LDAP passwords is not supported at this time'));
+            return false;
+        }
+        $entry = $this->get_user($username);
+        if(!$entry){
+            return false;
+        }else{
+            $config = $this->get_ldap_config();
+            $config['binddn']=$entry->dn();
+            $config['bindpw']=$oldpassword;
+            try {
+                $ldap = $this->get_ldap_connection($config);
+
+                $entry = $this->get_user($username,array(),$ldap);
+                
+                $newCryptedPassword = $this->hashPassword($newpassword, $this->password_encoding);
+                if ($newCryptedPassword===false) {
+                    return false;
+                }
+                if($this->password_encoding=='ad') {
+                    //TODO I believe this code will work once this bug is fixed: http://pear.php.net/bugs/bug.php?id=16796
+                    $oldCryptedPassword = $this->hashPassword($oldpassword, $this->password_encoding);
+                    $entry->delete( array($this->attributes['password'] => $oldCryptedPassword ));
+                }
+                $entry->replace( array($this->attributes['password'] => $newCryptedPassword ), true);
+                if( Net_LDAP2::isError($entry->upate()) ) {
+                    return false;
+                }
+                return true;
+            } catch (LdapInvalidCredentialsException $e) {
+                return false;
+            }
+        }
+
+        return false;
+    }
+
+    function is_dn_member_of_group($userDn, $groupDn)
+    {
+        $ldap = $this->get_ldap_connection();
+        $link = $ldap->getLink();
+        $r = @ldap_compare($link, $groupDn, $this->uniqueMember_attribute, $userDn);
+        if ($r === true){
+            return true;
+        }else if($r === false){
+            return false;
+        }else{
+            common_log(LOG_ERR, "LDAP error determining if userDn=$userDn is a member of groupDn=$groupDn using uniqueMember_attribute=$this->uniqueMember_attribute error: ".ldap_error($link));
+            return false;
+        }
+    }
+
+    /**
+     * get an LDAP entry for a user with a given username
+     *
+     * @param string $username
+     * $param array $attributes LDAP attributes to retrieve
+     * @return string DN
+     */
+    function get_user($username,$attributes=array()){
+        $ldap = $this->get_ldap_connection();
+        $filter = Net_LDAP2_Filter::create($this->attributes['username'], 'equals',  $username);
+        $options = array(
+            'attributes' => $attributes
+        );
+        $search = $ldap->search(null,$filter,$options);
+
+        if (PEAR::isError($search)) {
+            common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
+            return false;
+        }
+
+        if($search->count()==0){
+            return false;
+        }else if($search->count()==1){
+            $entry = $search->shiftEntry();
+            return $entry;
+        }else{
+            common_log(LOG_WARNING, 'Found ' . $search->count() . ' ldap user with the username: ' . $username);
+            return false;
+        }
+    }
+
+    /**
+     * Code originaly from the phpLDAPadmin development team
+     * http://phpldapadmin.sourceforge.net/
+     *
+     * Hashes a password and returns the hash based on the specified enc_type.
+     *
+     * @param string $passwordClear The password to hash in clear text.
+     * @param string $encodageType Standard LDAP encryption type which must be one of
+     *        crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, or clear.
+     * @return string The hashed password.
+     *
+     */
+
+    function hashPassword( $passwordClear, $encodageType ) 
+    {
+        $encodageType = strtolower( $encodageType );
+        switch( $encodageType ) {
+            case 'crypt': 
+                $cryptedPassword = '{CRYPT}' . crypt($passwordClear,$this->randomSalt(2)); 
+                break;
+                
+            case 'ext_des':
+                // extended des crypt. see OpenBSD crypt man page.
+                if ( ! defined( 'CRYPT_EXT_DES' ) || CRYPT_EXT_DES == 0 ) {return FALSE;} //Your system crypt library does not support extended DES encryption.
+                $cryptedPassword = '{CRYPT}' . crypt( $passwordClear, '_' . $this->randomSalt(8) );
+                break;
+
+            case 'md5crypt':
+                if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 ) {return FALSE;} //Your system crypt library does not support md5crypt encryption.
+                $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$1$' . $this->randomSalt(9) );
+                break;
+
+            case 'blowfish':
+                if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 ) {return FALSE;} //Your system crypt library does not support blowfish encryption.
+                $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$2a$12$' . $this->randomSalt(13) ); // hardcoded to second blowfish version and set number of rounds
+                break;
+
+            case 'md5':
+                $cryptedPassword = '{MD5}' . base64_encode( pack( 'H*' , md5( $passwordClear) ) );
+                break;
+
+            case 'sha':
+                if( function_exists('sha1') ) {
+                    // use php 4.3.0+ sha1 function, if it is available.
+                    $cryptedPassword = '{SHA}' . base64_encode( pack( 'H*' , sha1( $passwordClear) ) );
+                } elseif( function_exists( 'mhash' ) ) {
+                    $cryptedPassword = '{SHA}' . base64_encode( mhash( MHASH_SHA1, $passwordClear) );
+                } else {
+                    return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes.
+                }
+                break;
+
+            case 'ssha':
+                if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) {
+                    mt_srand( (double) microtime() * 1000000 );
+                    $salt = mhash_keygen_s2k( MHASH_SHA1, $passwordClear, substr( pack( "h*", md5( mt_rand() ) ), 0, 8 ), 4 );
+                    $cryptedPassword = "{SSHA}".base64_encode( mhash( MHASH_SHA1, $passwordClear.$salt ).$salt );
+                } else {
+                    return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes.
+                }
+                break;
+
+            case 'smd5':
+                if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) {
+                    mt_srand( (double) microtime() * 1000000 );
+                    $salt = mhash_keygen_s2k( MHASH_MD5, $passwordClear, substr( pack( "h*", md5( mt_rand() ) ), 0, 8 ), 4 );
+                    $cryptedPassword = "{SMD5}".base64_encode( mhash( MHASH_MD5, $passwordClear.$salt ).$salt );
+                } else {
+                    return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes.
+                }
+                break;
+
+            case 'ad':
+                $cryptedPassword = '';
+                $passwordClear = "\"" . $passwordClear . "\"";
+                $len = strlen($passwordClear);
+                for ($i = 0; $i < $len; $i++) {
+                    $cryptedPassword .= "{$passwordClear{$i}}\000";
+                }
+
+            case 'clear':
+            default:
+                $cryptedPassword = $passwordClear;
+        }
+
+        return $cryptedPassword;
+    }
+
+    /**
+     * Code originaly from the phpLDAPadmin development team
+     * http://phpldapadmin.sourceforge.net/
+     *
+     * Used to generate a random salt for crypt-style passwords. Salt strings are used
+     * to make pre-built hash cracking dictionaries difficult to use as the hash algorithm uses
+     * not only the user's password but also a randomly generated string. The string is
+     * stored as the first N characters of the hash for reference of hashing algorithms later.
+     *
+     * --- added 20021125 by bayu irawan <bayuir@divnet.telkom.co.id> ---
+     * --- ammended 20030625 by S C Rigler <srigler@houston.rr.com> ---
+     *
+     * @param int $length The length of the salt string to generate.
+     * @return string The generated salt string.
+     */
+     
+    function randomSalt( $length ) 
+    {
+        $possible = '0123456789'.
+            'abcdefghijklmnopqrstuvwxyz'.
+            'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
+            './';
+        $str = "";
+        mt_srand((double)microtime() * 1000000);
+
+        while( strlen( $str ) < $length )
+            $str .= substr( $possible, ( rand() % strlen( $possible ) ), 1 );
+
+        return $str;
+    }
+
+}
+
+class LdapInvalidCredentialsException extends Exception
+{
+
+}
diff --git a/plugins/LdapCommon/MemcacheSchemaCache.php b/plugins/LdapCommon/MemcacheSchemaCache.php
new file mode 100644 (file)
index 0000000..6b91d17
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/** 
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Cache the LDAP schema in memcache to improve performance
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Craig Andrews http://candrews.integralblue.com
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+class MemcacheSchemaCache implements Net_LDAP2_SchemaCache
+{
+    protected $c;
+    protected $cacheKey;
+
+    /**
+    * Initialize the simple cache
+    *
+    * Config is as following:
+    *  memcache     memcache instance
+    *  cachekey  the key in the cache to look at
+    *
+    * @param array $cfg Config array
+    */
+    public function MemcacheSchemaCache($cfg)
+    {
+        $this->c = $cfg['c'];
+        $this->cacheKey = $cfg['cacheKey'];
+    }
+
+    /**
+    * Return the schema object from the cache
+    *
+    * @return Net_LDAP2_Schema|Net_LDAP2_Error|false
+    */
+    public function loadSchema()
+    {
+         return $this->c->get($this->cacheKey);
+    }
+
+    /**
+    * Store a schema object in the cache
+    *
+    * This method will be called, if Net_LDAP2 has fetched a fresh
+    * schema object from LDAP and wants to init or refresh the cache.
+    *
+    * To invalidate the cache and cause Net_LDAP2 to refresh the cache,
+    * you can call this method with null or false as value.
+    * The next call to $ldap->schema() will then refresh the caches object.
+    *
+    * @param mixed $schema The object that should be cached
+    * @return true|Net_LDAP2_Error|false
+    */
+    public function storeSchema($schema) {
+        return $this->c->set($this->cacheKey, $schema);
+    }
+}
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2.php b/plugins/LdapCommon/extlib/Net/LDAP2.php
new file mode 100644 (file)
index 0000000..26f5e75
--- /dev/null
@@ -0,0 +1,1791 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2 interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Tarjej Huse <tarjei@bergfald.no>
+* @author    Jan Wagner <wagner@netsols.de>
+* @author    Del <del@babel.com.au>
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: LDAP2.php 286788 2009-08-04 06:05:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Package includes.
+*/
+require_once 'PEAR.php';
+require_once 'Net/LDAP2/RootDSE.php';
+require_once 'Net/LDAP2/Schema.php';
+require_once 'Net/LDAP2/Entry.php';
+require_once 'Net/LDAP2/Search.php';
+require_once 'Net/LDAP2/Util.php';
+require_once 'Net/LDAP2/Filter.php';
+require_once 'Net/LDAP2/LDIF.php';
+require_once 'Net/LDAP2/SchemaCache.interface.php';
+require_once 'Net/LDAP2/SimpleFileSchemaCache.php';
+
+/**
+*  Error constants for errors that are not LDAP errors.
+*/
+define('NET_LDAP2_ERROR', 1000);
+
+/**
+* Net_LDAP2 Version
+*/
+define('NET_LDAP2_VERSION', '2.0.7');
+
+/**
+* Net_LDAP2 - manipulate LDAP servers the right way!
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Tarjej Huse <tarjei@bergfald.no>
+* @author    Jan Wagner <wagner@netsols.de>
+* @author    Del <del@babel.com.au>
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger
+* @license   http://www.gnu.org/copyleft/lesser.html LGPL
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+class Net_LDAP2 extends PEAR
+{
+    /**
+    * Class configuration array
+    *
+    * host     = the ldap host to connect to
+    *            (may be an array of several hosts to try)
+    * port     = the server port
+    * version  = ldap version (defaults to v 3)
+    * starttls = when set, ldap_start_tls() is run after connecting.
+    * bindpw   = no explanation needed
+    * binddn   = the DN to bind as.
+    * basedn   = ldap base
+    * options  = hash of ldap options to set (opt => val)
+    * filter   = default search filter
+    * scope    = default search scope
+    *
+    * Newly added in 2.0.0RC4, for auto-reconnect:
+    * auto_reconnect  = if set to true then the class will automatically
+    *                   attempt to reconnect to the LDAP server in certain
+    *                   failure conditionswhen attempting a search, or other
+    *                   LDAP operation.  Defaults to false.  Note that if you
+    *                   set this to true, calls to search() may block
+    *                   indefinitely if there is a catastrophic server failure.
+    * min_backoff     = minimum reconnection delay period (in seconds).
+    * current_backoff = initial reconnection delay period (in seconds).
+    * max_backoff     = maximum reconnection delay period (in seconds).
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_config = array('host'            => 'localhost',
+                               'port'            => 389,
+                               'version'         => 3,
+                               'starttls'        => false,
+                               'binddn'          => '',
+                               'bindpw'          => '',
+                               'basedn'          => '',
+                               'options'         => array(),
+                               'filter'          => '(objectClass=*)',
+                               'scope'           => 'sub',
+                               'auto_reconnect'  => false,
+                               'min_backoff'     => 1,
+                               'current_backoff' => 1,
+                               'max_backoff'     => 32);
+
+    /**
+    * List of hosts we try to establish a connection to
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_host_list = array();
+
+    /**
+    * List of hosts that are known to be down.
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_down_host_list = array();
+
+    /**
+    * LDAP resource link.
+    *
+    * @access protected
+    * @var resource
+    */
+    protected $_link = false;
+
+    /**
+    * Net_LDAP2_Schema object
+    *
+    * This gets set and returned by {@link schema()}
+    *
+    * @access protected
+    * @var object Net_LDAP2_Schema
+    */
+    protected $_schema = null;
+
+    /**
+    * Schema cacher function callback
+    *
+    * @see registerSchemaCache()
+    * @var string
+    */
+    protected $_schema_cache = null;
+
+    /**
+    * Cache for attribute encoding checks
+    *
+    * @access protected
+    * @var array Hash with attribute names as key and boolean value
+    *            to determine whether they should be utf8 encoded or not.
+    */
+    protected $_schemaAttrs = array();
+
+    /**
+    * Cache for rootDSE objects
+    *
+    * Hash with requested rootDSE attr names as key and rootDSE object as value
+    *
+    * Since the RootDSE object itself may request a rootDSE object,
+    * {@link rootDse()} caches successful requests.
+    * Internally, Net_LDAP2 needs several lookups to this object, so
+    * caching increases performance significally.
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_rootDSE_cache = array();
+
+    /**
+    * Returns the Net_LDAP2 Release version, may be called statically
+    *
+    * @static
+    * @return string Net_LDAP2 version
+    */
+    public static function getVersion()
+    {
+        return NET_LDAP2_VERSION;
+    }
+
+    /**
+    * Configure Net_LDAP2, connect and bind
+    *
+    * Use this method as starting point of using Net_LDAP2
+    * to establish a connection to your LDAP server.
+    *
+    * Static function that returns either an error object or the new Net_LDAP2
+    * object. Something like a factory. Takes a config array with the needed
+    * parameters.
+    *
+    * @param array $config Configuration array
+    *
+    * @access public
+    * @return Net_LDAP2_Error|Net_LDAP2   Net_LDAP2_Error or Net_LDAP2 object
+    */
+    public static function &connect($config = array())
+    {
+        $ldap_check = self::checkLDAPExtension();
+        if (self::iserror($ldap_check)) {
+            return $ldap_check;
+        }
+
+        @$obj = new Net_LDAP2($config);
+
+        // todo? better errorhandling for setConfig()?
+
+        // connect and bind with credentials in config
+        $err = $obj->bind();
+        if (self::isError($err)) {
+            return $err;
+        }
+
+        return $obj;
+    }
+
+    /**
+    * Net_LDAP2 constructor
+    *
+    * Sets the config array
+    *
+    * Please note that the usual way of getting Net_LDAP2 to work is
+    * to call something like:
+    * <code>$ldap = Net_LDAP2::connect($ldap_config);</code>
+    *
+    * @param array $config Configuration array
+    *
+    * @access protected
+    * @return void
+    * @see $_config
+    */
+    public function __construct($config = array())
+    {
+        $this->PEAR('Net_LDAP2_Error');
+        $this->setConfig($config);
+    }
+
+    /**
+    * Sets the internal configuration array
+    *
+    * @param array $config Configuration array
+    *
+    * @access protected
+    * @return void
+    */
+    protected function setConfig($config)
+    {
+        //
+        // Parameter check -- probably should raise an error here if config
+        // is not an array.
+        //
+        if (! is_array($config)) {
+            return;
+        }
+
+        foreach ($config as $k => $v) {
+            if (isset($this->_config[$k])) {
+                $this->_config[$k] = $v;
+            } else {
+                // map old (Net_LDAP2) parms to new ones
+                switch($k) {
+                case "dn":
+                    $this->_config["binddn"] = $v;
+                    break;
+                case "password":
+                    $this->_config["bindpw"] = $v;
+                    break;
+                case "tls":
+                    $this->_config["starttls"] = $v;
+                    break;
+                case "base":
+                    $this->_config["basedn"] = $v;
+                    break;
+                }
+            }
+        }
+
+        //
+        // Ensure the host list is an array.
+        //
+        if (is_array($this->_config['host'])) {
+            $this->_host_list = $this->_config['host'];
+        } else {
+            if (strlen($this->_config['host']) > 0) {
+                $this->_host_list = array($this->_config['host']);
+            } else {
+                $this->_host_list = array();
+                // ^ this will cause an error in performConnect(),
+                // so the user is notified about the failure
+            }
+        }
+
+        //
+        // Reset the down host list, which seems like a sensible thing to do
+        // if the config is being reset for some reason.
+        //
+        $this->_down_host_list = array();
+    }
+
+    /**
+    * Bind or rebind to the ldap-server
+    *
+    * This function binds with the given dn and password to the server. In case
+    * no connection has been made yet, it will be started and startTLS issued
+    * if appropiate.
+    *
+    * The internal bind configuration is not being updated, so if you call
+    * bind() without parameters, you can rebind with the credentials
+    * provided at first connecting to the server.
+    *
+    * @param string $dn       Distinguished name for binding
+    * @param string $password Password for binding
+    *
+    * @access public
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    */
+    public function bind($dn = null, $password = null)
+    {
+        // fetch current bind credentials
+        if (is_null($dn)) {
+            $dn = $this->_config["binddn"];
+        }
+        if (is_null($password)) {
+            $password = $this->_config["bindpw"];
+        }
+
+        // Connect first, if we haven't so far.
+        // This will also bind us to the server.
+        if ($this->_link === false) {
+            // store old credentials so we can revert them later
+            // then overwrite config with new bind credentials
+            $olddn = $this->_config["binddn"];
+            $oldpw = $this->_config["bindpw"];
+
+            // overwrite bind credentials in config
+            // so performConnect() knows about them
+            $this->_config["binddn"] = $dn;
+            $this->_config["bindpw"] = $password;
+
+            // try to connect with provided credentials
+            $msg = $this->performConnect();
+
+            // reset to previous config
+            $this->_config["binddn"] = $olddn;
+            $this->_config["bindpw"] = $oldpw;
+
+            // see if bind worked
+            if (self::isError($msg)) {
+                return $msg;
+            }
+        } else {
+            // do the requested bind as we are
+            // asked to bind manually
+            if (is_null($dn)) {
+                // anonymous bind
+                $msg = @ldap_bind($this->_link);
+            } else {
+                // privileged bind
+                $msg = @ldap_bind($this->_link, $dn, $password);
+            }
+            if (false === $msg) {
+                return PEAR::raiseError("Bind failed: " .
+                                        @ldap_error($this->_link),
+                                        @ldap_errno($this->_link));
+            }
+        }
+        return true;
+    }
+
+    /**
+    * Connect to the ldap-server
+    *
+    * This function connects to the LDAP server specified in
+    * the configuration, binds and set up the LDAP protocol as needed.
+    *
+    * @access protected
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    */
+    protected function performConnect()
+    {
+        // Note: Connecting is briefly described in RFC1777.
+        // Basicly it works like this:
+        //  1. set up TCP connection
+        //  2. secure that connection if neccessary
+        //  3a. setLDAPVersion to tell server which version we want to speak
+        //  3b. perform bind
+        //  3c. setLDAPVersion to tell server which version we want to speak
+        //      together with a test for supported versions
+        //  4. set additional protocol options
+
+        // Return true if we are already connected.
+        if ($this->_link !== false) {
+            return true;
+        }
+
+        // Connnect to the LDAP server if we are not connected.  Note that
+        // with some LDAP clients, ldapperformConnect returns a link value even
+        // if no connection is made.  We need to do at least one anonymous
+        // bind to ensure that a connection is actually valid.
+        //
+        // Ref: http://www.php.net/manual/en/function.ldap-connect.php
+
+        // Default error message in case all connection attempts
+        // fail but no message is set
+        $current_error = new PEAR_Error('Unknown connection error');
+
+        // Catch empty $_host_list arrays.
+        if (!is_array($this->_host_list) || count($this->_host_list) == 0) {
+            $current_error = PEAR::raiseError('No Servers configured! Please '.
+               'pass in an array of servers to Net_LDAP2');
+            return $current_error;
+        }
+
+        // Cycle through the host list.
+        foreach ($this->_host_list as $host) {
+
+            // Ensure we have a valid string for host name
+            if (is_array($host)) {
+                $current_error = PEAR::raiseError('No Servers configured! '.
+                   'Please pass in an one dimensional array of servers to '.
+                   'Net_LDAP2! (multidimensional array detected!)');
+                continue;
+            }
+
+            // Skip this host if it is known to be down.
+            if (in_array($host, $this->_down_host_list)) {
+                continue;
+            }
+
+            // Record the host that we are actually connecting to in case
+            // we need it later.
+            $this->_config['host'] = $host;
+
+            // Attempt a connection.
+            $this->_link = @ldap_connect($host, $this->_config['port']);
+            if (false === $this->_link) {
+                $current_error = PEAR::raiseError('Could not connect to ' .
+                    $host . ':' . $this->_config['port']);
+                $this->_down_host_list[] = $host;
+                continue;
+            }
+
+            // If we're supposed to use TLS, do so before we try to bind,
+            // as some strict servers only allow binding via secure connections
+            if ($this->_config["starttls"] === true) {
+                if (self::isError($msg = $this->startTLS())) {
+                    $current_error           = $msg;
+                    $this->_link             = false;
+                    $this->_down_host_list[] = $host;
+                    continue;
+                }
+            }
+
+            // Try to set the configured LDAP version on the connection if LDAP
+            // server needs that before binding (eg OpenLDAP).
+            // This could be necessary since rfc-1777 states that the protocol version
+            // has to be set at the bind request.
+            // We use force here which means that the test in the rootDSE is skipped;
+            // this is neccessary, because some strict LDAP servers only allow to
+            // read the LDAP rootDSE (which tells us the supported protocol versions)
+            // with authenticated clients.
+            // This may fail in which case we try again after binding.
+            // In this case, most probably the bind() or setLDAPVersion()-call
+            // below will also fail, providing error messages.
+            $version_set = false;
+            $ignored_err = $this->setLDAPVersion(0, true);
+            if (!self::isError($ignored_err)) {
+                $version_set = true;
+            }
+
+            // Attempt to bind to the server. If we have credentials configured,
+            // we try to use them, otherwise its an anonymous bind.
+            // As stated by RFC-1777, the bind request should be the first
+            // operation to be performed after the connection is established.
+            // This may give an protocol error if the server does not support
+            // V2 binds and the above call to setLDAPVersion() failed.
+            // In case the above call failed, we try an V2 bind here and set the
+            // version afterwards (with checking to the rootDSE).
+            $msg = $this->bind();
+            if (self::isError($msg)) {
+                // The bind failed, discard link and save error msg.
+                // Then record the host as down and try next one
+                if ($msg->getCode() == 0x02 && !$version_set) {
+                    // provide a finer grained error message
+                    // if protocol error arieses because of invalid version
+                    $msg = new Net_LDAP2_Error($msg->getMessage().
+                        " (could not set LDAP protocol version to ".
+                        $this->_config['version'].")",
+                        $msg->getCode());
+                }
+                $this->_link             = false;
+                $current_error           = $msg;
+                $this->_down_host_list[] = $host;
+                continue;
+            }
+
+            // Set desired LDAP version if not successfully set before.
+            // Here, a check against the rootDSE is performed, so we get a
+            // error message if the server does not support the version.
+            // The rootDSE entry should tell us which LDAP versions are
+            // supported. However, some strict LDAP servers only allow
+            // bound suers to read the rootDSE.
+            if (!$version_set) {
+                if (self::isError($msg = $this->setLDAPVersion())) {
+                    $current_error           = $msg;
+                    $this->_link             = false;
+                    $this->_down_host_list[] = $host;
+                    continue;
+                }
+            }
+
+            // Set LDAP parameters, now we know we have a valid connection.
+            if (isset($this->_config['options']) &&
+                is_array($this->_config['options']) &&
+                count($this->_config['options'])) {
+                foreach ($this->_config['options'] as $opt => $val) {
+                    $err = $this->setOption($opt, $val);
+                    if (self::isError($err)) {
+                        $current_error           = $err;
+                        $this->_link             = false;
+                        $this->_down_host_list[] = $host;
+                        continue 2;
+                    }
+                }
+            }
+
+            // At this stage we have connected, bound, and set up options,
+            // so we have a known good LDAP server.  Time to go home.
+            return true;
+        }
+
+
+        // All connection attempts have failed, return the last error.
+        return $current_error;
+    }
+
+    /**
+    * Reconnect to the ldap-server.
+    *
+    * In case the connection to the LDAP
+    * service has dropped out for some reason, this function will reconnect,
+    * and re-bind if a bind has been attempted in the past.  It is probably
+    * most useful when the server list provided to the new() or connect()
+    * function is an array rather than a single host name, because in that
+    * case it will be able to connect to a failover or secondary server in
+    * case the primary server goes down.
+    *
+    * This doesn't return anything, it just tries to re-establish
+    * the current connection.  It will sleep for the current backoff
+    * period (seconds) before attempting the connect, and if the
+    * connection fails it will double the backoff period, but not
+    * try again.  If you want to ensure a reconnection during a
+    * transient period of server downtime then you need to call this
+    * function in a loop.
+    *
+    * @access protected
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    */
+    protected function performReconnect()
+    {
+
+        // Return true if we are already connected.
+        if ($this->_link !== false) {
+            return true;
+        }
+
+        // Default error message in case all connection attempts
+        // fail but no message is set
+        $current_error = new PEAR_Error('Unknown connection error');
+
+        // Sleep for a backoff period in seconds.
+        sleep($this->_config['current_backoff']);
+
+        // Retry all available connections.
+        $this->_down_host_list = array();
+        $msg = $this->performConnect();
+
+        // Bail out if that fails.
+        if (self::isError($msg)) {
+            $this->_config['current_backoff'] =
+               $this->_config['current_backoff'] * 2;
+            if ($this->_config['current_backoff'] > $this->_config['max_backoff']) {
+                $this->_config['current_backoff'] = $this->_config['max_backoff'];
+            }
+            return $msg;
+        }
+
+        // Now we should be able to safely (re-)bind.
+        $msg = $this->bind();
+        if (self::isError($msg)) {
+            $this->_config['current_backoff'] = $this->_config['current_backoff'] * 2;
+            if ($this->_config['current_backoff'] > $this->_config['max_backoff']) {
+                $this->_config['current_backoff'] = $this->_config['max_backoff'];
+            }
+
+            // _config['host'] should have had the last connected host stored in it
+            // by performConnect().  Since we are unable to bind to that host we can safely
+            // assume that it is down or has some other problem.
+            $this->_down_host_list[] = $this->_config['host'];
+            return $msg;
+        }
+
+        // At this stage we have connected, bound, and set up options,
+        // so we have a known good LDAP server. Time to go home.
+        $this->_config['current_backoff'] = $this->_config['min_backoff'];
+        return true;
+    }
+
+    /**
+    * Starts an encrypted session
+    *
+    * @access public
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    */
+    public function startTLS()
+    {
+        // Test to see if the server supports TLS first.
+        // This is done via testing the extensions offered by the server.
+        // The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported.
+        $rootDSE = $this->rootDse();
+        if (self::isError($rootDSE)) {
+            return $this->raiseError("Unable to fetch rootDSE entry ".
+            "to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode());
+        }
+
+        $supported_extensions = $rootDSE->getValue('supportedExtension');
+        if (self::isError($supported_extensions)) {
+            return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ".
+            "to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode());
+        }
+
+        if (in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) {
+            if (false === @ldap_start_tls($this->_link)) {
+                return $this->raiseError("TLS not started: " .
+                                        @ldap_error($this->_link),
+                                        @ldap_errno($this->_link));
+            }
+            return true;
+        } else {
+            return $this->raiseError("Server reports that it does not support TLS");
+        }
+    }
+
+    /**
+    * alias function of startTLS() for perl-ldap interface
+    *
+    * @return void
+    * @see startTLS()
+    */
+    public function start_tls()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array( &$this, 'startTLS' ), $args);
+    }
+
+    /**
+    * Close LDAP connection.
+    *
+    * Closes the connection. Use this when the session is over.
+    *
+    * @return void
+    */
+    public function done()
+    {
+        $this->_Net_LDAP2();
+    }
+
+    /**
+    * Alias for {@link done()}
+    *
+    * @return void
+    * @see done()
+    */
+    public function disconnect()
+    {
+        $this->done();
+    }
+
+    /**
+    * Destructor
+    *
+    * @access protected
+    */
+    public function _Net_LDAP2()
+    {
+        @ldap_close($this->_link);
+    }
+
+    /**
+    * Add a new entryobject to a directory.
+    *
+    * Use add to add a new Net_LDAP2_Entry object to the directory.
+    * This also links the entry to the connection used for the add,
+    * if it was a fresh entry ({@link Net_LDAP2_Entry::createFresh()})
+    *
+    * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry
+    *
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    */
+    public function add(&$entry)
+    {
+        if (!$entry instanceof Net_LDAP2_Entry) {
+            return PEAR::raiseError('Parameter to Net_LDAP2::add() must be a Net_LDAP2_Entry object.');
+        }
+
+        // Continue attempting the add operation in a loop until we
+        // get a success, a definitive failure, or the world ends.
+        $foo = 0;
+        while (true) {
+            $link = $this->getLink();
+
+            if ($link === false) {
+                // We do not have a successful connection yet.  The call to
+                // getLink() would have kept trying if we wanted one.  Go
+                // home now.
+                return PEAR::raiseError("Could not add entry " . $entry->dn() .
+                       " no valid LDAP connection could be found.");
+            }
+
+            if (@ldap_add($link, $entry->dn(), $entry->getValues())) {
+                // entry successfully added, we should update its $ldap reference
+                // in case it is not set so far (fresh entry)
+                if (!$entry->getLDAP() instanceof Net_LDAP2) {
+                    $entry->setLDAP($this);
+                }
+                // store, that the entry is present inside the directory
+                $entry->markAsNew(false);
+                return true;
+            } else {
+                // We have a failure.  What type?  We may be able to reconnect
+                // and try again.
+                $error_code = @ldap_errno($link);
+                $error_name = $this->errorMessage($error_code);
+
+                if (($error_name === 'LDAP_OPERATIONS_ERROR') &&
+                    ($this->_config['auto_reconnect'])) {
+
+                    // The server has become disconnected before trying the
+                    // operation.  We should try again, possibly with a different
+                    // server.
+                    $this->_link = false;
+                    $this->performReconnect();
+                } else {
+                    // Errors other than the above catched are just passed
+                    // back to the user so he may react upon them.
+                    return PEAR::raiseError("Could not add entry " . $entry->dn() . " " .
+                                            $error_name,
+                                            $error_code);
+                }
+            }
+        }
+    }
+
+    /**
+    * Delete an entry from the directory
+    *
+    * The object may either be a string representing the dn or a Net_LDAP2_Entry
+    * object. When the boolean paramter recursive is set, all subentries of the
+    * entry will be deleted as well.
+    *
+    * @param string|Net_LDAP2_Entry $dn        DN-string or Net_LDAP2_Entry
+    * @param boolean                $recursive Should we delete all children recursive as well?
+    *
+    * @access public
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    */
+    public function delete($dn, $recursive = false)
+    {
+        if ($dn instanceof Net_LDAP2_Entry) {
+             $dn = $dn->dn();
+        }
+        if (false === is_string($dn)) {
+            return PEAR::raiseError("Parameter is not a string nor an entry object!");
+        }
+        // Recursive delete searches for children and calls delete for them
+        if ($recursive) {
+            $result = @ldap_list($this->_link, $dn, '(objectClass=*)', array(null), 0, 0);
+            if (@ldap_count_entries($this->_link, $result)) {
+                $subentry = @ldap_first_entry($this->_link, $result);
+                $this->delete(@ldap_get_dn($this->_link, $subentry), true);
+                while ($subentry = @ldap_next_entry($this->_link, $subentry)) {
+                    $this->delete(@ldap_get_dn($this->_link, $subentry), true);
+                }
+            }
+        }
+
+        // Continue attempting the delete operation in a loop until we
+        // get a success, a definitive failure, or the world ends.
+        while (true) {
+            $link = $this->getLink();
+
+            if ($link === false) {
+                // We do not have a successful connection yet.  The call to
+                // getLink() would have kept trying if we wanted one.  Go
+                // home now.
+                return PEAR::raiseError("Could not add entry " . $dn .
+                       " no valid LDAP connection could be found.");
+            }
+
+            if (@ldap_delete($link, $dn)) {
+                // entry successfully deleted.
+                return true;
+            } else {
+                // We have a failure.  What type?
+                // We may be able to reconnect and try again.
+                $error_code = @ldap_errno($link);
+                $error_name = $this->errorMessage($error_code);
+
+                if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
+                    ($this->_config['auto_reconnect'])) {
+                    // The server has become disconnected before trying the
+                    // operation.  We should try again, possibly with a 
+                    // different server.
+                    $this->_link = false;
+                    $this->performReconnect();
+
+                } elseif ($error_code == 66) {
+                    // Subentries present, server refused to delete.
+                    // Deleting subentries is the clients responsibility, but
+                    // since the user may not know of the subentries, we do not
+                    // force that here but instead notify the developer so he
+                    // may take actions himself.
+                    return PEAR::raiseError("Could not delete entry $dn because of subentries. Use the recursive parameter to delete them.");
+
+                } else {
+                    // Errors other than the above catched are just passed
+                    // back to the user so he may react upon them.
+                    return PEAR::raiseError("Could not delete entry " . $dn . " " .
+                                            $error_name,
+                                            $error_code);
+                }
+            }
+        }
+    }
+
+    /**
+    * Modify an ldapentry directly on the server
+    *
+    * This one takes the DN or a Net_LDAP2_Entry object and an array of actions.
+    * This array should be something like this:
+    *
+    * array('add' => array('attribute1' => array('val1', 'val2'),
+    *                      'attribute2' => array('val1')),
+    *       'delete' => array('attribute1'),
+    *       'replace' => array('attribute1' => array('val1')),
+    *       'changes' => array('add' => ...,
+    *                          'replace' => ...,
+    *                          'delete' => array('attribute1', 'attribute2' => array('val1')))
+    *
+    * The changes array is there so the order of operations can be influenced
+    * (the operations are done in order of appearance).
+    * The order of execution is as following:
+    *   1. adds from 'add' array
+    *   2. deletes from 'delete' array
+    *   3. replaces from 'replace' array
+    *   4. changes (add, replace, delete) in order of appearance
+    * All subarrays (add, replace, delete, changes) may be given at the same time.
+    *
+    * The function calls the corresponding functions of an Net_LDAP2_Entry
+    * object. A detailed description of array structures can be found there.
+    *
+    * Unlike the modification methods provided by the Net_LDAP2_Entry object,
+    * this method will instantly carry out an update() after each operation,
+    * thus modifying "directly" on the server.
+    *
+    * @param string|Net_LDAP2_Entry $entry DN-string or Net_LDAP2_Entry
+    * @param array                  $parms Array of changes
+    *
+    * @access public
+    * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true
+    */
+    public function modify($entry, $parms = array())
+    {
+        if (is_string($entry)) {
+            $entry = $this->getEntry($entry);
+            if (self::isError($entry)) {
+                return $entry;
+            }
+        }
+        if (!$entry instanceof Net_LDAP2_Entry) {
+            return PEAR::raiseError("Parameter is not a string nor an entry object!");
+        }
+
+        // Perform changes mentioned separately
+        foreach (array('add', 'delete', 'replace') as $action) {
+            if (isset($parms[$action])) {
+                $msg = $entry->$action($parms[$action]);
+                if (self::isError($msg)) {
+                    return $msg;
+                }
+                $entry->setLDAP($this);
+
+                // Because the @ldap functions are called inside Net_LDAP2_Entry::update(),
+                // we have to trap the error codes issued from that if we want to support
+                // reconnection.
+                while (true) {
+                    $msg = $entry->update();
+
+                    if (self::isError($msg)) {
+                        // We have a failure.  What type?  We may be able to reconnect
+                        // and try again.
+                        $error_code = $msg->getCode();
+                        $error_name = $this->errorMessage($error_code);
+
+                        if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
+                            ($this->_config['auto_reconnect'])) {
+
+                            // The server has become disconnected before trying the
+                            // operation.  We should try again, possibly with a different
+                            // server.
+                            $this->_link = false;
+                            $this->performReconnect();
+
+                        } else {
+
+                            // Errors other than the above catched are just passed
+                            // back to the user so he may react upon them.
+                            return PEAR::raiseError("Could not modify entry: ".$msg->getMessage());
+                        }
+                    } else {
+                        // modification succeedet, evaluate next change
+                        break;
+                    }
+                }
+            }
+        }
+
+        // perform combined changes in 'changes' array
+        if (isset($parms['changes']) && is_array($parms['changes'])) {
+            foreach ($parms['changes'] as $action => $value) {
+
+                // Because the @ldap functions are called inside Net_LDAP2_Entry::update,
+                // we have to trap the error codes issued from that if we want to support
+                // reconnection.
+                while (true) {
+                    $msg = $this->modify($entry, array($action => $value));
+
+                    if (self::isError($msg)) {
+                        // We have a failure.  What type?  We may be able to reconnect
+                        // and try again.
+                        $error_code = $msg->getCode();
+                        $error_name = $this->errorMessage($error_code);
+
+                        if (($this->errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') &&
+                            ($this->_config['auto_reconnect'])) {
+
+                            // The server has become disconnected before trying the
+                            // operation.  We should try again, possibly with a different
+                            // server.
+                            $this->_link = false;
+                            $this->performReconnect();
+
+                        } else {
+                            // Errors other than the above catched are just passed
+                            // back to the user so he may react upon them.
+                            return $msg;
+                        }
+                    } else {
+                        // modification succeedet, evaluate next change
+                        break;
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+    * Run a ldap search query
+    *
+    * Search is used to query the ldap-database.
+    * $base and $filter may be ommitted. The one from config will
+    * then be used. $base is either a DN-string or an Net_LDAP2_Entry
+    * object in which case its DN willb e used.
+    *
+    * Params may contain:
+    *
+    * scope: The scope which will be used for searching
+    *        base - Just one entry
+    *        sub  - The whole tree
+    *        one  - Immediately below $base
+    * sizelimit: Limit the number of entries returned (default: 0 = unlimited),
+    * timelimit: Limit the time spent for searching (default: 0 = unlimited),
+    * attrsonly: If true, the search will only return the attribute names,
+    * attributes: Array of attribute names, which the entry should contain.
+    *             It is good practice to limit this to just the ones you need.
+    * [NOT IMPLEMENTED]
+    * deref: By default aliases are dereferenced to locate the base object for the search, but not when
+    *        searching subordinates of the base object. This may be changed by specifying one of the
+    *        following values:
+    *
+    *        never  - Do not dereference aliases in searching or in locating the base object of the search.
+    *        search - Dereference aliases in subordinates of the base object in searching, but not in
+    *                locating the base object of the search.
+    *        find
+    *        always
+    *
+    * Please note, that you cannot override server side limitations to sizelimit
+    * and timelimit: You can always only lower a given limit.
+    *
+    * @param string|Net_LDAP2_Entry  $base   LDAP searchbase
+    * @param string|Net_LDAP2_Filter $filter LDAP search filter or a Net_LDAP2_Filter object
+    * @param array                   $params Array of options
+    *
+    * @access public
+    * @return Net_LDAP2_Search|Net_LDAP2_Error Net_LDAP2_Search object or Net_LDAP2_Error object
+    * @todo implement search controls (sorting etc)
+    */
+    public function search($base = null, $filter = null, $params = array())
+    {
+        if (is_null($base)) {
+            $base = $this->_config['basedn'];
+        }
+        if ($base instanceof Net_LDAP2_Entry) {
+            $base = $base->dn(); // fetch DN of entry, making searchbase relative to the entry
+        }
+        if (is_null($filter)) {
+            $filter = $this->_config['filter'];
+        }
+        if ($filter instanceof Net_LDAP2_Filter) {
+            $filter = $filter->asString(); // convert Net_LDAP2_Filter to string representation
+        }
+        if (PEAR::isError($filter)) {
+            return $filter;
+        }
+        if (PEAR::isError($base)) {
+            return $base;
+        }
+
+        /* setting searchparameters  */
+        (isset($params['sizelimit']))  ? $sizelimit  = $params['sizelimit']  : $sizelimit = 0;
+        (isset($params['timelimit']))  ? $timelimit  = $params['timelimit']  : $timelimit = 0;
+        (isset($params['attrsonly']))  ? $attrsonly  = $params['attrsonly']  : $attrsonly = 0;
+        (isset($params['attributes'])) ? $attributes = $params['attributes'] : $attributes = array();
+
+        // Ensure $attributes to be an array in case only one
+        // attribute name was given as string
+        if (!is_array($attributes)) {
+            $attributes = array($attributes);
+        }
+
+        // reorganize the $attributes array index keys
+        // sometimes there are problems with not consecutive indexes
+        $attributes = array_values($attributes);
+
+        // scoping makes searches faster!
+        $scope = (isset($params['scope']) ? $params['scope'] : $this->_config['scope']);
+
+        switch ($scope) {
+        case 'one':
+            $search_function = 'ldap_list';
+            break;
+        case 'base':
+            $search_function = 'ldap_read';
+            break;
+        default:
+            $search_function = 'ldap_search';
+        }
+
+        // Continue attempting the search operation until we get a success
+        // or a definitive failure.
+        while (true) {
+            $link = $this->getLink();
+            $search = @call_user_func($search_function,
+                                      $link,
+                                      $base,
+                                      $filter,
+                                      $attributes,
+                                      $attrsonly,
+                                      $sizelimit,
+                                      $timelimit);
+
+            if ($err = @ldap_errno($link)) {
+                if ($err == 32) {
+                    // Errorcode 32 = no such object, i.e. a nullresult.
+                    return $obj = new Net_LDAP2_Search ($search, $this, $attributes);
+                } elseif ($err == 4) {
+                    // Errorcode 4 = sizelimit exeeded.
+                    return $obj = new Net_LDAP2_Search ($search, $this, $attributes);
+                } elseif ($err == 87) {
+                    // bad search filter
+                    return $this->raiseError($this->errorMessage($err) . "($filter)", $err);
+                } elseif (($err == 1) && ($this->_config['auto_reconnect'])) {
+                    // Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect.
+                    $this->_link = false;
+                    $this->performReconnect();
+                } else {
+                    $msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope";
+                    return $this->raiseError($this->errorMessage($err) . $msg, $err);
+                }
+            } else {
+                return $obj = new Net_LDAP2_Search($search, $this, $attributes);
+            }
+        }
+    }
+
+    /**
+    * Set an LDAP option
+    *
+    * @param string $option Option to set
+    * @param mixed  $value  Value to set Option to
+    *
+    * @access public
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    */
+    public function setOption($option, $value)
+    {
+        if ($this->_link) {
+            if (defined($option)) {
+                if (@ldap_set_option($this->_link, constant($option), $value)) {
+                    return true;
+                } else {
+                    $err = @ldap_errno($this->_link);
+                    if ($err) {
+                        $msg = @ldap_err2str($err);
+                    } else {
+                        $err = NET_LDAP2_ERROR;
+                        $msg = $this->errorMessage($err);
+                    }
+                    return $this->raiseError($msg, $err);
+                }
+            } else {
+                return $this->raiseError("Unkown Option requested");
+            }
+        } else {
+            return $this->raiseError("Could not set LDAP option: No LDAP connection");
+        }
+    }
+
+    /**
+    * Get an LDAP option value
+    *
+    * @param string $option Option to get
+    *
+    * @access public
+    * @return Net_LDAP2_Error|string Net_LDAP2_Error or option value
+    */
+    public function getOption($option)
+    {
+        if ($this->_link) {
+            if (defined($option)) {
+                if (@ldap_get_option($this->_link, constant($option), $value)) {
+                    return $value;
+                } else {
+                    $err = @ldap_errno($this->_link);
+                    if ($err) {
+                        $msg = @ldap_err2str($err);
+                    } else {
+                        $err = NET_LDAP2_ERROR;
+                        $msg = $this->errorMessage($err);
+                    }
+                    return $this->raiseError($msg, $err);
+                }
+            } else {
+                $this->raiseError("Unkown Option requested");
+            }
+        } else {
+            $this->raiseError("No LDAP connection");
+        }
+    }
+
+    /**
+    * Get the LDAP_PROTOCOL_VERSION that is used on the connection.
+    *
+    * A lot of ldap functionality is defined by what protocol version the ldap server speaks.
+    * This might be 2 or 3.
+    *
+    * @return int
+    */
+    public function getLDAPVersion()
+    {
+        if ($this->_link) {
+            $version = $this->getOption("LDAP_OPT_PROTOCOL_VERSION");
+        } else {
+            $version = $this->_config['version'];
+        }
+        return $version;
+    }
+
+    /**
+    * Set the LDAP_PROTOCOL_VERSION that is used on the connection.
+    *
+    * @param int     $version LDAP-version that should be used
+    * @param boolean $force   If set to true, the check against the rootDSE will be skipped
+    *
+    * @return Net_LDAP2_Error|true    Net_LDAP2_Error object or true
+    * @todo Checking via the rootDSE takes much time - why? fetching and instanciation is quick!
+    */
+    public function setLDAPVersion($version = 0, $force = false)
+    {
+        if (!$version) {
+            $version = $this->_config['version'];
+        }
+
+        //
+        // Check to see if the server supports this version first.
+        //
+        // Todo: Why is this so horribly slow?
+        // $this->rootDse() is very fast, as well as Net_LDAP2_RootDSE::fetch()
+        // seems like a problem at copiyng the object inside PHP??
+        // Additionally, this is not always reproducable...
+        //
+        if (!$force) {
+            $rootDSE = $this->rootDse();
+            if ($rootDSE instanceof Net_LDAP2_Error) {
+                return $rootDSE;
+            } else {
+                $supported_versions = $rootDSE->getValue('supportedLDAPVersion');
+                if (is_string($supported_versions)) {
+                    $supported_versions = array($supported_versions);
+                }
+                $check_ok = in_array($version, $supported_versions);
+            }
+        }
+
+        if ($force || $check_ok) {
+            return $this->setOption("LDAP_OPT_PROTOCOL_VERSION", $version);
+        } else {
+            return $this->raiseError("LDAP Server does not support protocol version " . $version);
+        }
+    }
+
+
+    /**
+    * Tells if a DN does exist in the directory
+    *
+    * @param string|Net_LDAP2_Entry $dn The DN of the object to test
+    *
+    * @return boolean|Net_LDAP2_Error
+    */
+    public function dnExists($dn)
+    {
+        if (PEAR::isError($dn)) {
+            return $dn;
+        }
+        if ($dn instanceof Net_LDAP2_Entry) {
+             $dn = $dn->dn();
+        }
+        if (false === is_string($dn)) {
+            return PEAR::raiseError('Parameter $dn is not a string nor an entry object!');
+        }
+
+        // make dn relative to parent
+        $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false));
+        if (self::isError($base)) {
+            return $base;
+        }
+        $entry_rdn = array_shift($base);
+        if (is_array($entry_rdn)) {
+            // maybe the dn consist of a multivalued RDN, we must build the dn in this case
+            // because the $entry_rdn is an array!
+            $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn);
+        }
+        $base = Net_LDAP2_Util::canonical_dn($base);
+
+        $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1);
+        if (@ldap_count_entries($this->_link, $result)) {
+            return true;
+        }
+        if (ldap_errno($this->_link) == 32) {
+            return false;
+        }
+        if (ldap_errno($this->_link) != 0) {
+            return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link));
+        }
+        return false;
+    }
+
+
+    /**
+    * Get a specific entry based on the DN
+    *
+    * @param string $dn   DN of the entry that should be fetched
+    * @param array  $attr Array of Attributes to select. If ommitted, all attributes are fetched.
+    *
+    * @return Net_LDAP2_Entry|Net_LDAP2_Error    Reference to a Net_LDAP2_Entry object or Net_LDAP2_Error object
+    * @todo Maybe check against the shema should be done to be sure the attribute type exists
+    */
+    public function &getEntry($dn, $attr = array())
+    {
+        if (!is_array($attr)) {
+            $attr = array($attr);
+        }
+        $result = $this->search($dn, '(objectClass=*)',
+                                array('scope' => 'base', 'attributes' => $attr));
+        if (self::isError($result)) {
+            return $result;
+        } elseif ($result->count() == 0) {
+            return PEAR::raiseError('Could not fetch entry '.$dn.': no entry found');
+        }
+        $entry = $result->shiftEntry();
+        if (false == $entry) {
+            return PEAR::raiseError('Could not fetch entry (error retrieving entry from search result)');
+        }
+        return $entry;
+    }
+
+    /**
+    * Rename or move an entry
+    *
+    * This method will instantly carry out an update() after the move,
+    * so the entry is moved instantly.
+    * You can pass an optional Net_LDAP2 object. In this case, a cross directory
+    * move will be performed which deletes the entry in the source (THIS) directory
+    * and adds it in the directory $target_ldap.
+    * A cross directory move will switch the Entrys internal LDAP reference so
+    * updates to the entry will go to the new directory.
+    *
+    * Note that if you want to do a cross directory move, you need to
+    * pass an Net_LDAP2_Entry object, otherwise the attributes will be empty.
+    *
+    * @param string|Net_LDAP2_Entry $entry       Entry DN or Entry object
+    * @param string                 $newdn       New location
+    * @param Net_LDAP2              $target_ldap (optional) Target directory for cross server move; should be passed via reference
+    *
+    * @return Net_LDAP2_Error|true
+    */
+    public function move($entry, $newdn, $target_ldap = null)
+    {
+        if (is_string($entry)) {
+            $entry_o = $this->getEntry($entry);
+        } else {
+            $entry_o =& $entry;
+        }
+        if (!$entry_o instanceof Net_LDAP2_Entry) {
+            return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object! (If DN was passed, conversion failed)');
+        }
+        if (null !== $target_ldap && !$target_ldap instanceof Net_LDAP2) {
+            return PEAR::raiseError('Parameter $target_ldap is expected to be a Net_LDAP2 object!');
+        }
+
+        if ($target_ldap && $target_ldap !== $this) {
+            // cross directory move
+            if (is_string($entry)) {
+                return PEAR::raiseError('Unable to perform cross directory move: operation requires a Net_LDAP2_Entry object');
+            }
+            if ($target_ldap->dnExists($newdn)) {
+                return PEAR::raiseError('Unable to perform cross directory move: entry does exist in target directory');
+            }
+            $entry_o->dn($newdn);
+            $res = $target_ldap->add($entry_o);
+            if (self::isError($res)) {
+                return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in target directory');
+            }
+            $res = $this->delete($entry_o->currentDN());
+            if (self::isError($res)) {
+                $res2 = $target_ldap->delete($entry_o); // undo add
+                if (self::isError($res2)) {
+                    $add_error_string = 'Additionally, the deletion (undo add) of $entry in target directory failed.';
+                }
+                return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in source directory. '.$add_error_string);
+            }
+            $entry_o->setLDAP($target_ldap);
+            return true;
+        } else {
+            // local move
+            $entry_o->dn($newdn);
+            $entry_o->setLDAP($this);
+            return $entry_o->update();
+        }
+    }
+
+    /**
+    * Copy an entry to a new location
+    *
+    * The entry will be immediately copied.
+    * Please note that only attributes you have
+    * selected will be copied.
+    *
+    * @param Net_LDAP2_Entry &$entry Entry object
+    * @param string          $newdn  New FQF-DN of the entry
+    *
+    * @return Net_LDAP2_Error|Net_LDAP2_Entry Error Message or reference to the copied entry
+    */
+    public function &copy(&$entry, $newdn)
+    {
+        if (!$entry instanceof Net_LDAP2_Entry) {
+            return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object!');
+        }
+
+        $newentry = Net_LDAP2_Entry::createFresh($newdn, $entry->getValues());
+        $result   = $this->add($newentry);
+
+        if ($result instanceof Net_LDAP2_Error) {
+            return $result;
+        } else {
+            return $newentry;
+        }
+    }
+
+
+    /**
+    * Returns the string for an ldap errorcode.
+    *
+    * Made to be able to make better errorhandling
+    * Function based on DB::errorMessage()
+    * Tip: The best description of the errorcodes is found here:
+    * http://www.directory-info.com/LDAP2/LDAPErrorCodes.html
+    *
+    * @param int $errorcode Error code
+    *
+    * @return string The errorstring for the error.
+    */
+    public function errorMessage($errorcode)
+    {
+        $errorMessages = array(
+                              0x00 => "LDAP_SUCCESS",
+                              0x01 => "LDAP_OPERATIONS_ERROR",
+                              0x02 => "LDAP_PROTOCOL_ERROR",
+                              0x03 => "LDAP_TIMELIMIT_EXCEEDED",
+                              0x04 => "LDAP_SIZELIMIT_EXCEEDED",
+                              0x05 => "LDAP_COMPARE_FALSE",
+                              0x06 => "LDAP_COMPARE_TRUE",
+                              0x07 => "LDAP_AUTH_METHOD_NOT_SUPPORTED",
+                              0x08 => "LDAP_STRONG_AUTH_REQUIRED",
+                              0x09 => "LDAP_PARTIAL_RESULTS",
+                              0x0a => "LDAP_REFERRAL",
+                              0x0b => "LDAP_ADMINLIMIT_EXCEEDED",
+                              0x0c => "LDAP_UNAVAILABLE_CRITICAL_EXTENSION",
+                              0x0d => "LDAP_CONFIDENTIALITY_REQUIRED",
+                              0x0e => "LDAP_SASL_BIND_INPROGRESS",
+                              0x10 => "LDAP_NO_SUCH_ATTRIBUTE",
+                              0x11 => "LDAP_UNDEFINED_TYPE",
+                              0x12 => "LDAP_INAPPROPRIATE_MATCHING",
+                              0x13 => "LDAP_CONSTRAINT_VIOLATION",
+                              0x14 => "LDAP_TYPE_OR_VALUE_EXISTS",
+                              0x15 => "LDAP_INVALID_SYNTAX",
+                              0x20 => "LDAP_NO_SUCH_OBJECT",
+                              0x21 => "LDAP_ALIAS_PROBLEM",
+                              0x22 => "LDAP_INVALID_DN_SYNTAX",
+                              0x23 => "LDAP_IS_LEAF",
+                              0x24 => "LDAP_ALIAS_DEREF_PROBLEM",
+                              0x30 => "LDAP_INAPPROPRIATE_AUTH",
+                              0x31 => "LDAP_INVALID_CREDENTIALS",
+                              0x32 => "LDAP_INSUFFICIENT_ACCESS",
+                              0x33 => "LDAP_BUSY",
+                              0x34 => "LDAP_UNAVAILABLE",
+                              0x35 => "LDAP_UNWILLING_TO_PERFORM",
+                              0x36 => "LDAP_LOOP_DETECT",
+                              0x3C => "LDAP_SORT_CONTROL_MISSING",
+                              0x3D => "LDAP_INDEX_RANGE_ERROR",
+                              0x40 => "LDAP_NAMING_VIOLATION",
+                              0x41 => "LDAP_OBJECT_CLASS_VIOLATION",
+                              0x42 => "LDAP_NOT_ALLOWED_ON_NONLEAF",
+                              0x43 => "LDAP_NOT_ALLOWED_ON_RDN",
+                              0x44 => "LDAP_ALREADY_EXISTS",
+                              0x45 => "LDAP_NO_OBJECT_CLASS_MODS",
+                              0x46 => "LDAP_RESULTS_TOO_LARGE",
+                              0x47 => "LDAP_AFFECTS_MULTIPLE_DSAS",
+                              0x50 => "LDAP_OTHER",
+                              0x51 => "LDAP_SERVER_DOWN",
+                              0x52 => "LDAP_LOCAL_ERROR",
+                              0x53 => "LDAP_ENCODING_ERROR",
+                              0x54 => "LDAP_DECODING_ERROR",
+                              0x55 => "LDAP_TIMEOUT",
+                              0x56 => "LDAP_AUTH_UNKNOWN",
+                              0x57 => "LDAP_FILTER_ERROR",
+                              0x58 => "LDAP_USER_CANCELLED",
+                              0x59 => "LDAP_PARAM_ERROR",
+                              0x5a => "LDAP_NO_MEMORY",
+                              0x5b => "LDAP_CONNECT_ERROR",
+                              0x5c => "LDAP_NOT_SUPPORTED",
+                              0x5d => "LDAP_CONTROL_NOT_FOUND",
+                              0x5e => "LDAP_NO_RESULTS_RETURNED",
+                              0x5f => "LDAP_MORE_RESULTS_TO_RETURN",
+                              0x60 => "LDAP_CLIENT_LOOP",
+                              0x61 => "LDAP_REFERRAL_LIMIT_EXCEEDED",
+                              1000 => "Unknown Net_LDAP2 Error"
+                              );
+
+         return isset($errorMessages[$errorcode]) ?
+            $errorMessages[$errorcode] :
+            $errorMessages[NET_LDAP2_ERROR] . ' (' . $errorcode . ')';
+    }
+
+    /**
+    * Gets a rootDSE object
+    *
+    * This either fetches a fresh rootDSE object or returns it from
+    * the internal cache for performance reasons, if possible.
+    *
+    * @param array $attrs Array of attributes to search for
+    *
+    * @access public
+    * @return Net_LDAP2_Error|Net_LDAP2_RootDSE Net_LDAP2_Error or Net_LDAP2_RootDSE object
+    */
+    public function &rootDse($attrs = null)
+    {
+        if ($attrs !== null && !is_array($attrs)) {
+            return PEAR::raiseError('Parameter $attr is expected to be an array!');
+        }
+
+        $attrs_signature = serialize($attrs);
+
+        // see if we need to fetch a fresh object, or if we already
+        // requested this object with the same attributes
+        if (true || !array_key_exists($attrs_signature, $this->_rootDSE_cache)) {
+            $rootdse =& Net_LDAP2_RootDSE::fetch($this, $attrs);
+            if ($rootdse instanceof Net_LDAP2_Error) {
+                return $rootdse;
+            }
+
+            // search was ok, store rootDSE in cache
+            $this->_rootDSE_cache[$attrs_signature] = $rootdse;
+        }
+        return $this->_rootDSE_cache[$attrs_signature];
+    }
+
+    /**
+    * Alias function of rootDse() for perl-ldap interface
+    *
+    * @access public
+    * @see rootDse()
+    * @return Net_LDAP2_Error|Net_LDAP2_RootDSE
+    */
+    public function &root_dse()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array(&$this, 'rootDse'), $args);
+    }
+
+    /**
+    * Get a schema object
+    *
+    * @param string $dn (optional) Subschema entry dn
+    *
+    * @access public
+    * @return Net_LDAP2_Schema|Net_LDAP2_Error  Net_LDAP2_Schema or Net_LDAP2_Error object
+    */
+    public function &schema($dn = null)
+    {
+        // Schema caching by Knut-Olav Hoven
+        // If a schema caching object is registered, we use that to fetch
+        // a schema object.
+        // See registerSchemaCache() for more info on this.
+        if ($this->_schema === null) {
+            if ($this->_schema_cache) {
+               $cached_schema = $this->_schema_cache->loadSchema();
+               if ($cached_schema instanceof Net_LDAP2_Error) {
+                   return $cached_schema; // route error to client
+               } else {
+                   if ($cached_schema instanceof Net_LDAP2_Schema) {
+                       $this->_schema = $cached_schema;
+                   }
+               }
+            }
+        }
+
+        // Fetch schema, if not tried before and no cached version available.
+        // If we are already fetching the schema, we will skip fetching.
+        if ($this->_schema === null) {
+            // store a temporary error message so subsequent calls to schema() can
+            // detect, that we are fetching the schema already.
+            // Otherwise we will get an infinite loop at Net_LDAP2_Schema::fetch()
+            $this->_schema = new Net_LDAP2_Error('Schema not initialized');
+            $this->_schema = Net_LDAP2_Schema::fetch($this, $dn);
+
+            // If schema caching is active, advise the cache to store the schema
+            if ($this->_schema_cache) {
+                $caching_result = $this->_schema_cache->storeSchema($this->_schema);
+                if ($caching_result instanceof Net_LDAP2_Error) {
+                    return $caching_result; // route error to client
+                }
+            }
+        }
+        return $this->_schema;
+    }
+
+    /**
+    * Enable/disable persistent schema caching
+    *
+    * Sometimes it might be useful to allow your scripts to cache
+    * the schema information on disk, so the schema is not fetched
+    * every time the script runs which could make your scripts run
+    * faster.
+    *
+    * This method allows you to register a custom object that
+    * implements your schema cache. Please see the SchemaCache interface
+    * (SchemaCache.interface.php) for informations on how to implement this.
+    * To unregister the cache, pass null as $cache parameter.
+    *
+    * For ease of use, Net_LDAP2 provides a simple file based cache
+    * which is used in the example below. You may use this, for example,
+    * to store the schema in a linux tmpfs which results in the schema
+    * beeing cached inside the RAM which allows nearly instant access.
+    * <code>
+    *    // Create the simple file cache object that comes along with Net_LDAP2
+    *    $mySchemaCache_cfg = array(
+    *      'path'    =>  '/tmp/Net_LDAP2_Schema.cache',
+    *      'max_age' =>  86400   // max age is 24 hours (in seconds)
+    *    );
+    *    $mySchemaCache = new Net_LDAP2_SimpleFileSchemaCache($mySchemaCache_cfg);
+    *    $ldap = new Net_LDAP2::connect(...);
+    *    $ldap->registerSchemaCache($mySchemaCache); // enable caching
+    *    // now each call to $ldap->schema() will get the schema from disk!
+    * </code>
+    *
+    * @param Net_LDAP2_SchemaCache|null $cache Object implementing the Net_LDAP2_SchemaCache interface
+    *
+    * @return true|Net_LDAP2_Error
+    */
+    public function registerSchemaCache($cache) {
+        if (is_null($cache)
+        || (is_object($cache) && in_array('Net_LDAP2_SchemaCache', class_implements($cache))) ) {
+            $this->_schema_cache = $cache;
+            return true;
+        } else {
+            return new Net_LDAP2_Error('Custom schema caching object is either no '.
+                'valid object or does not implement the Net_LDAP2_SchemaCache interface!');
+        }
+    }
+
+
+    /**
+    * Checks if phps ldap-extension is loaded
+    *
+    * If it is not loaded, it tries to load it manually using PHPs dl().
+    * It knows both windows-dll and *nix-so.
+    *
+    * @static
+    * @return Net_LDAP2_Error|true
+    */
+    public static function checkLDAPExtension()
+    {
+        if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) {
+            return new Net_LDAP2_Error("It seems that you do not have the ldap-extension installed. Please install it before using the Net_LDAP2 package.");
+        } else {
+            return true;
+        }
+    }
+
+    /**
+    * Encodes given attributes to UTF8 if needed by schema
+    *
+    * This function takes attributes in an array and then checks against the schema if they need
+    * UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and
+    * can be used for adding or modifying.
+    *
+    * $attributes is expected to be an array with keys describing
+    * the attribute names and the values as the value of this attribute:
+    * <code>$attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2'));</code>
+    *
+    * @param array $attributes Array of attributes
+    *
+    * @access public
+    * @return array|Net_LDAP2_Error Array of UTF8 encoded attributes or Error
+    */
+    public function utf8Encode($attributes)
+    {
+        return $this->utf8($attributes, 'utf8_encode');
+    }
+
+    /**
+    * Decodes the given attribute values if needed by schema
+    *
+    * $attributes is expected to be an array with keys describing
+    * the attribute names and the values as the value of this attribute:
+    * <code>$attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2'));</code>
+    *
+    * @param array $attributes Array of attributes
+    *
+    * @access public
+    * @see utf8Encode()
+    * @return array|Net_LDAP2_Error Array with decoded attribute values or Error
+    */
+    public function utf8Decode($attributes)
+    {
+        return $this->utf8($attributes, 'utf8_decode');
+    }
+
+    /**
+    * Encodes or decodes attribute values if needed
+    *
+    * @param array $attributes Array of attributes
+    * @param array $function   Function to apply to attribute values
+    *
+    * @access protected
+    * @return array|Net_LDAP2_Error Array of attributes with function applied to values or Error
+    */
+    protected function utf8($attributes, $function)
+    {
+        if (!is_array($attributes) || array_key_exists(0, $attributes)) {
+            return PEAR::raiseError('Parameter $attributes is expected to be an associative array');
+        }
+
+        if (!$this->_schema) {
+            $this->_schema = $this->schema();
+        }
+
+        if (!$this->_link || self::isError($this->_schema) || !function_exists($function)) {
+            return $attributes;
+        }
+
+        if (is_array($attributes) && count($attributes) > 0) {
+
+            foreach ($attributes as $k => $v) {
+
+                if (!isset($this->_schemaAttrs[$k])) {
+
+                    $attr = $this->_schema->get('attribute', $k);
+                    if (self::isError($attr)) {
+                        continue;
+                    }
+
+                    if (false !== strpos($attr['syntax'], '1.3.6.1.4.1.1466.115.121.1.15')) {
+                        $encode = true;
+                    } else {
+                        $encode = false;
+                    }
+                    $this->_schemaAttrs[$k] = $encode;
+
+                } else {
+                    $encode = $this->_schemaAttrs[$k];
+                }
+
+                if ($encode) {
+                    if (is_array($v)) {
+                        foreach ($v as $ak => $av) {
+                            $v[$ak] = call_user_func($function, $av);
+                        }
+                    } else {
+                        $v = call_user_func($function, $v);
+                    }
+                }
+                $attributes[$k] = $v;
+            }
+        }
+        return $attributes;
+    }
+
+    /**
+    * Get the LDAP link resource.  It will loop attempting to
+    * re-establish the connection if the connection attempt fails and
+    * auto_reconnect has been turned on (see the _config array documentation).
+    *
+    * @access public
+    * @return resource LDAP link
+    */
+    public function &getLink()
+    {
+        if ($this->_config['auto_reconnect']) {
+            while (true) {
+                //
+                // Return the link handle if we are already connected.  Otherwise
+                // try to reconnect.
+                //
+                if ($this->_link !== false) {
+                    return $this->_link;
+                } else {
+                    $this->performReconnect();
+                }
+            }
+        }
+        return $this->_link;
+    }
+}
+
+/**
+* Net_LDAP2_Error implements a class for reporting portable LDAP error messages.
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Tarjej Huse <tarjei@bergfald.no>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP22/
+*/
+class Net_LDAP2_Error extends PEAR_Error
+{
+    /**
+     * Net_LDAP2_Error constructor.
+     *
+     * @param string  $message   String with error message.
+     * @param integer $code      Net_LDAP2 error code
+     * @param integer $mode      what "error mode" to operate in
+     * @param mixed   $level     what error level to use for $mode & PEAR_ERROR_TRIGGER
+     * @param mixed   $debuginfo additional debug info, such as the last query
+     *
+     * @access public
+     * @see PEAR_Error
+     */
+    public function __construct($message = 'Net_LDAP2_Error', $code = NET_LDAP2_ERROR, $mode = PEAR_ERROR_RETURN,
+                         $level = E_USER_NOTICE, $debuginfo = null)
+    {
+        if (is_int($code)) {
+            $this->PEAR_Error($message . ': ' . Net_LDAP2::errorMessage($code), $code, $mode, $level, $debuginfo);
+        } else {
+            $this->PEAR_Error("$message: $code", NET_LDAP2_ERROR, $mode, $level, $debuginfo);
+        }
+    }
+}
+
+?>
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Entry.php b/plugins/LdapCommon/extlib/Net/LDAP2/Entry.php
new file mode 100644 (file)
index 0000000..66de966
--- /dev/null
@@ -0,0 +1,1055 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_Entry interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Jan Wagner <wagner@netsols.de>
+* @author    Tarjej Huse <tarjei@bergfald.no>
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Tarjej Huse, Jan Wagner, Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: Entry.php 286787 2009-08-04 06:03:12Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Includes
+*/
+require_once 'PEAR.php';
+require_once 'Util.php';
+
+/**
+* Object representation of a directory entry
+*
+* This class represents a directory entry. You can add, delete, replace
+* attributes and their values, rename the entry, delete the entry.
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Jan Wagner <wagner@netsols.de>
+* @author   Tarjej Huse <tarjei@bergfald.no>
+* @author   Benedikt Hallinger <beni@php.net>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP2/
+*/
+class Net_LDAP2_Entry extends PEAR
+{
+    /**
+    * Entry ressource identifier
+    *
+    * @access protected
+    * @var ressource
+    */
+    protected $_entry = null;
+
+    /**
+    * LDAP ressource identifier
+    *
+    * @access protected
+    * @var ressource
+    */
+    protected $_link = null;
+
+    /**
+    * Net_LDAP2 object
+    *
+    * This object will be used for updating and schema checking
+    *
+    * @access protected
+    * @var object Net_LDAP2
+    */
+    protected $_ldap = null;
+
+    /**
+    * Distinguished name of the entry
+    *
+    * @access protected
+    * @var string
+    */
+    protected $_dn = null;
+
+    /**
+    * Attributes
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_attributes = array();
+
+    /**
+    * Original attributes before any modification
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_original = array();
+
+
+    /**
+    * Map of attribute names
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_map = array();
+
+
+    /**
+    * Is this a new entry?
+    *
+    * @access protected
+    * @var boolean
+    */
+    protected $_new = true;
+
+    /**
+    * New distinguished name
+    *
+    * @access protected
+    * @var string
+    */
+    protected $_newdn = null;
+
+    /**
+    * Shall the entry be deleted?
+    *
+    * @access protected
+    * @var boolean
+    */
+    protected $_delete = false;
+
+    /**
+    * Map with changes to the entry
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_changes = array("add"     => array(),
+                                "delete"  => array(),
+                                "replace" => array()
+                               );
+    /**
+    * Internal Constructor
+    *
+    * Constructor of the entry. Sets up the distinguished name and the entries
+    * attributes.
+    * You should not call this method manually! Use {@link Net_LDAP2_Entry::createFresh()}
+    * or {@link Net_LDAP2_Entry::createConnected()} instead!
+    *
+    * @param Net_LDAP2|ressource|array &$ldap Net_LDAP2 object, ldap-link ressource or array of attributes
+    * @param string|ressource          $entry Either a DN or a LDAP-Entry ressource
+    *
+    * @access protected
+    * @return none
+    */
+    protected function __construct(&$ldap, $entry = null)
+    {
+        $this->PEAR('Net_LDAP2_Error');
+
+        // set up entry resource or DN
+        if (is_resource($entry)) {
+            $this->_entry = &$entry;
+        } else {
+            $this->_dn = $entry;
+        }
+
+        // set up LDAP link
+        if ($ldap instanceof Net_LDAP2) {
+            $this->_ldap = &$ldap;
+            $this->_link = $ldap->getLink();
+        } elseif (is_resource($ldap)) {
+            $this->_link = $ldap;
+        } elseif (is_array($ldap)) {
+            // Special case: here $ldap is an array of attributes,
+            // this means, we have no link. This is a "virtual" entry.
+            // We just set up the attributes so one can work with the object
+            // as expected, but an update() fails unless setLDAP() is called.
+            $this->setAttributes($ldap);
+        }
+
+        // if this is an entry existing in the directory,
+        // then set up as old and fetch attrs
+        if (is_resource($this->_entry) && is_resource($this->_link)) {
+            $this->_new = false;
+            $this->_dn  = @ldap_get_dn($this->_link, $this->_entry);
+            $this->setAttributes();  // fetch attributes from server
+        }
+    }
+
+    /**
+    * Creates a fresh entry that may be added to the directory later on
+    *
+    * Use this method, if you want to initialize a fresh entry.
+    *
+    * The method should be called statically: $entry = Net_LDAP2_Entry::createFresh();
+    * You should put a 'objectClass' attribute into the $attrs so the directory server
+    * knows which object you want to create. However, you may omit this in case you
+    * don't want to add this entry to a directory server.
+    *
+    * The attributes parameter is as following:
+    * <code>
+    * $attrs = array( 'attribute1' => array('value1', 'value2'),
+    *                 'attribute2' => 'single value'
+    *          );
+    * </code>
+    *
+    * @param string $dn    DN of the Entry
+    * @param array  $attrs Attributes of the entry
+    *
+    * @static
+    * @return Net_LDAP2_Entry|Net_LDAP2_Error
+    */
+    public static function createFresh($dn, $attrs = array())
+    {
+        if (!is_array($attrs)) {
+            return PEAR::raiseError("Unable to create fresh entry: Parameter \$attrs needs to be an array!");
+        }
+
+        $entry = new Net_LDAP2_Entry($attrs, $dn);
+        return $entry;
+    }
+
+    /**
+    * Creates a Net_LDAP2_Entry object out of an ldap entry resource
+    *
+    * Use this method, if you want to initialize an entry object that is
+    * already present in some directory and that you have read manually.
+    *
+    * Please note, that if you want to create an entry object that represents
+    * some already existing entry, you should use {@link createExisting()}.
+    *
+    * The method should be called statically: $entry = Net_LDAP2_Entry::createConnected();
+    *
+    * @param Net_LDAP2 $ldap  Net_LDA2 object
+    * @param resource  $entry PHP LDAP entry resource
+    *
+    * @static
+    * @return Net_LDAP2_Entry|Net_LDAP2_Error
+    */
+    public static function createConnected($ldap, $entry)
+    {
+        if (!$ldap instanceof Net_LDAP2) {
+            return PEAR::raiseError("Unable to create connected entry: Parameter \$ldap needs to be a Net_LDAP2 object!");
+        }
+        if (!is_resource($entry)) {
+            return PEAR::raiseError("Unable to create connected entry: Parameter \$entry needs to be a ldap entry resource!");
+        }
+
+        $entry = new Net_LDAP2_Entry($ldap, $entry);
+        return $entry;
+    }
+
+    /**
+    * Creates an Net_LDAP2_Entry object that is considered already existing
+    *
+    * Use this method, if you want to modify an already existing entry
+    * without fetching it first.
+    * In most cases however, it is better to fetch the entry via Net_LDAP2->getEntry()!
+    *
+    * Please note that you should take care if you construct entries manually with this
+    * because you may get weird synchronisation problems.
+    * The attributes and values as well as the entry itself are considered existent
+    * which may produce errors if you try to modify an entry which doesn't really exist
+    * or if you try to overwrite some attribute with an value already present.
+    *
+    * This method is equal to calling createFresh() and after that markAsNew(FALSE).
+    *
+    * The method should be called statically: $entry = Net_LDAP2_Entry::createExisting();
+    *
+    * The attributes parameter is as following:
+    * <code>
+    * $attrs = array( 'attribute1' => array('value1', 'value2'),
+    *                 'attribute2' => 'single value'
+    *          );
+    * </code>
+    *
+    * @param string $dn    DN of the Entry
+    * @param array  $attrs Attributes of the entry
+    *
+    * @static
+    * @return Net_LDAP2_Entry|Net_LDAP2_Error
+    */
+    public static function createExisting($dn, $attrs = array())
+    {
+        if (!is_array($attrs)) {
+            return PEAR::raiseError("Unable to create entry object: Parameter \$attrs needs to be an array!");
+        }
+
+        $entry = Net_LDAP2_Entry::createFresh($dn, $attrs);
+        if ($entry instanceof Net_LDAP2_Error) {
+            return $entry;
+        } else {
+            $entry->markAsNew(false);
+            return $entry;
+        }
+    }
+
+    /**
+    * Get or set the distinguished name of the entry
+    *
+    * If called without an argument the current (or the new DN if set) DN gets returned.
+    * If you provide an DN, this entry is moved to the new location specified if a DN existed.
+    * If the DN was not set, the DN gets initialized. Call {@link update()} to actually create
+    * the new Entry in the directory.
+    * To fetch the current active DN after setting a new DN but before an update(), you can use
+    * {@link currentDN()} to retrieve the DN that is currently active.
+    *
+    * Please note that special characters (eg german umlauts) should be encoded using utf8_encode().
+    * You may use {@link Net_LDAP2_Util::canonical_dn()} for properly encoding of the DN.
+    *
+    * @param string $dn New distinguished name
+    *
+    * @access public
+    * @return string|true Distinguished name (or true if a new DN was provided)
+    */
+    public function dn($dn = null)
+    {
+        if (false == is_null($dn)) {
+            if (is_null($this->_dn)) {
+                $this->_dn = $dn;
+            } else {
+                $this->_newdn = $dn;
+            }
+            return true;
+        }
+        return (isset($this->_newdn) ? $this->_newdn : $this->currentDN());
+    }
+
+    /**
+    * Renames or moves the entry
+    *
+    * This is just a convinience alias to {@link dn()}
+    * to make your code more meaningful.
+    *
+    * @param string $newdn The new DN
+    *
+    * @return true
+    */
+    public function move($newdn)
+    {
+        return $this->dn($newdn);
+    }
+
+    /**
+    * Sets the internal attributes array
+    *
+    * This fetches the values for the attributes from the server.
+    * The attribute Syntax will be checked so binary attributes will be returned
+    * as binary values.
+    *
+    * Attributes may be passed directly via the $attributes parameter to setup this
+    * entry manually. This overrides attribute fetching from the server.
+    *
+    * @param array $attributes Attributes to set for this entry
+    *
+    * @access protected
+    * @return void
+    */
+    protected function setAttributes($attributes = null)
+    {
+        /*
+        * fetch attributes from the server
+        */
+        if (is_null($attributes) && is_resource($this->_entry) && is_resource($this->_link)) {
+            // fetch schema
+            if ($this->_ldap instanceof Net_LDAP2) {
+                $schema =& $this->_ldap->schema();
+            }
+            // fetch attributes
+            $attributes = array();
+            do {
+                if (empty($attr)) {
+                    $ber  = null;
+                    $attr = @ldap_first_attribute($this->_link, $this->_entry, $ber);
+                } else {
+                    $attr = @ldap_next_attribute($this->_link, $this->_entry, $ber);
+                }
+                if ($attr) {
+                    $func = 'ldap_get_values'; // standard function to fetch value
+
+                    // Try to get binary values as binary data
+                    if ($schema instanceof Net_LDAP2_Schema) {
+                        if ($schema->isBinary($attr)) {
+                             $func = 'ldap_get_values_len';
+                        }
+                    }
+                    // fetch attribute value (needs error checking?)
+                    $attributes[$attr] = $func($this->_link, $this->_entry, $attr);
+                }
+            } while ($attr);
+        }
+
+        /*
+        * set attribute data directly, if passed
+        */
+        if (is_array($attributes) && count($attributes) > 0) {
+            if (isset($attributes["count"]) && is_numeric($attributes["count"])) {
+                unset($attributes["count"]);
+            }
+            foreach ($attributes as $k => $v) {
+                // attribute names should not be numeric
+                if (is_numeric($k)) {
+                    continue;
+                }
+                // map generic attribute name to real one
+                $this->_map[strtolower($k)] = $k;
+                // attribute values should be in an array
+                if (false == is_array($v)) {
+                    $v = array($v);
+                }
+                // remove the value count (comes from ldap server)
+                if (isset($v["count"])) {
+                    unset($v["count"]);
+                }
+                $this->_attributes[$k] = $v;
+            }
+        }
+
+        // save a copy for later use
+        $this->_original = $this->_attributes;
+    }
+
+    /**
+    * Get the values of all attributes in a hash
+    *
+    * The returned hash has the form
+    * <code>array('attributename' => 'single value',
+    *       'attributename' => array('value1', value2', value3'))</code>
+    *
+    * @access public
+    * @return array Hash of all attributes with their values
+    */
+    public function getValues()
+    {
+        $attrs = array();
+        foreach ($this->_attributes as $attr => $value) {
+            $attrs[$attr] = $this->getValue($attr);
+        }
+        return $attrs;
+    }
+
+    /**
+    * Get the value of a specific attribute
+    *
+    * The first parameter is the name of the attribute
+    * The second parameter influences the way the value is returned:
+    * 'single': only the first value is returned as string
+    * 'all': all values including the value count are returned in an
+    *               array
+    * 'default': in all other cases an attribute value with a single value is
+    *            returned as string, if it has multiple values it is returned
+    *            as an array (without value count)
+    *
+    * @param string $attr   Attribute name
+    * @param string $option Option
+    *
+    * @access public
+    * @return string|array|PEAR_Error string, array or PEAR_Error
+    */
+    public function getValue($attr, $option = null)
+    {
+        $attr = $this->getAttrName($attr);
+
+        if (false == array_key_exists($attr, $this->_attributes)) {
+            return PEAR::raiseError("Unknown attribute ($attr) requested");
+        }
+
+        $value = $this->_attributes[$attr];
+
+        if ($option == "single" || (count($value) == 1 && $option != 'all')) {
+            $value = array_shift($value);
+        }
+
+        return $value;
+    }
+
+    /**
+    * Alias function of getValue for perl-ldap interface
+    *
+    * @see getValue()
+    * @return string|array|PEAR_Error
+    */
+    public function get_value()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array( &$this, 'getValue' ), $args);
+    }
+
+    /**
+    * Returns an array of attributes names
+    *
+    * @access public
+    * @return array Array of attribute names
+    */
+    public function attributes()
+    {
+        return array_keys($this->_attributes);
+    }
+
+    /**
+    * Returns whether an attribute exists or not
+    *
+    * @param string $attr Attribute name
+    *
+    * @access public
+    * @return boolean
+    */
+    public function exists($attr)
+    {
+        $attr = $this->getAttrName($attr);
+        return array_key_exists($attr, $this->_attributes);
+    }
+
+    /**
+    * Adds a new attribute or a new value to an existing attribute
+    *
+    * The paramter has to be an array of the form:
+    * array('attributename' => 'single value',
+    *       'attributename' => array('value1', 'value2))
+    * When the attribute already exists the values will be added, else the
+    * attribute will be created. These changes are local to the entry and do
+    * not affect the entry on the server until update() is called.
+    *
+    * Note, that you can add values of attributes that you haven't selected, but if
+    * you do so, {@link getValue()} and {@link getValues()} will only return the
+    * values you added, _NOT_ all values present on the server. To avoid this, just refetch
+    * the entry after calling {@link update()} or select the attribute.
+    *
+    * @param array $attr Attributes to add
+    *
+    * @access public
+    * @return true|Net_LDAP2_Error
+    */
+    public function add($attr = array())
+    {
+        if (false == is_array($attr)) {
+            return PEAR::raiseError("Parameter must be an array");
+        }
+        foreach ($attr as $k => $v) {
+            $k = $this->getAttrName($k);
+            if (false == is_array($v)) {
+                // Do not add empty values
+                if ($v == null) {
+                    continue;
+                } else {
+                    $v = array($v);
+                }
+            }
+            // add new values to existing attribute or add new attribute
+            if ($this->exists($k)) {
+                $this->_attributes[$k] = array_unique(array_merge($this->_attributes[$k], $v));
+            } else {
+                $this->_map[strtolower($k)] = $k;
+                $this->_attributes[$k]      = $v;
+            }
+            // save changes for update()
+            if (empty($this->_changes["add"][$k])) {
+                $this->_changes["add"][$k] = array();
+            }
+            $this->_changes["add"][$k] = array_unique(array_merge($this->_changes["add"][$k], $v));
+        }
+        $return = true;
+        return $return;
+    }
+
+    /**
+    * Deletes an whole attribute or a value or the whole entry
+    *
+    * The parameter can be one of the following:
+    *
+    * "attributename" - The attribute as a whole will be deleted
+    * array("attributename1", "attributename2) - All given attributes will be
+    *                                            deleted
+    * array("attributename" => "value") - The value will be deleted
+    * array("attributename" => array("value1", "value2") - The given values
+    *                                                      will be deleted
+    * If $attr is null or omitted , then the whole Entry will be deleted!
+    *
+    * These changes are local to the entry and do
+    * not affect the entry on the server until {@link update()} is called.
+    *
+    * Please note that you must select the attribute (at $ldap->search() for example)
+    * to be able to delete values of it, Otherwise {@link update()} will silently fail
+    * and remove nothing.
+    *
+    * @param string|array $attr Attributes to delete (NULL or missing to delete whole entry)
+    *
+    * @access public
+    * @return true
+    */
+    public function delete($attr = null)
+    {
+        if (is_null($attr)) {
+            $this->_delete = true;
+            return true;
+        }
+        if (is_string($attr)) {
+            $attr = array($attr);
+        }
+        // Make the assumption that attribute names cannot be numeric,
+        // therefore this has to be a simple list of attribute names to delete
+        if (is_numeric(key($attr))) {
+            foreach ($attr as $name) {
+                if (is_array($name)) {
+                    // someone mixed modes (list mode but specific values given!)
+                    $del_attr_name = array_search($name, $attr);
+                    $this->delete(array($del_attr_name => $name));
+                } else {
+                    // mark for update() if this attr was not marked before
+                    $name = $this->getAttrName($name);
+                    if ($this->exists($name)) {
+                        $this->_changes["delete"][$name] = null;
+                        unset($this->_attributes[$name]);
+                    }
+                }
+            }
+        } else {
+            // Here we have a hash with "attributename" => "value to delete"
+            foreach ($attr as $name => $values) {
+                if (is_int($name)) {
+                    // someone mixed modes and gave us just an attribute name
+                    $this->delete($values);
+                } else {
+                    // mark for update() if this attr was not marked before;
+                    // this time it must consider the selected values also
+                    $name = $this->getAttrName($name);
+                    if ($this->exists($name)) {
+                        if (false == is_array($values)) {
+                            $values = array($values);
+                        }
+                        // save values to be deleted
+                        if (empty($this->_changes["delete"][$name])) {
+                            $this->_changes["delete"][$name] = array();
+                        }
+                        $this->_changes["delete"][$name] =
+                            array_unique(array_merge($this->_changes["delete"][$name], $values));
+                        foreach ($values as $value) {
+                            // find the key for the value that should be deleted
+                            $key = array_search($value, $this->_attributes[$name]);
+                            if (false !== $key) {
+                                // delete the value
+                                unset($this->_attributes[$name][$key]);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        $return = true;
+        return $return;
+    }
+
+    /**
+    * Replaces attributes or its values
+    *
+    * The parameter has to an array of the following form:
+    * array("attributename" => "single value",
+    *       "attribute2name" => array("value1", "value2"),
+    *       "deleteme1" => null,
+    *       "deleteme2" => "")
+    * If the attribute does not yet exist it will be added instead (see also $force).
+    * If the attribue value is null, the attribute will de deleted.
+    *
+    * These changes are local to the entry and do
+    * not affect the entry on the server until {@link update()} is called.
+    *
+    * In some cases you are not allowed to read the attributes value (for
+    * example the ActiveDirectory attribute unicodePwd) but are allowed to
+    * replace the value. In this case replace() would assume that the attribute
+    * is not in the directory yet and tries to add it which will result in an
+    * LDAP_TYPE_OR_VALUE_EXISTS error.
+    * To force replace mode instead of add, you can set $force to true.
+    *
+    * @param array $attr  Attributes to replace
+    * @param bool  $force Force replacing mode in case we can't read the attr value but are allowed to replace it
+    *
+    * @access public
+    * @return true|Net_LDAP2_Error
+    */
+    public function replace($attr = array(), $force = false)
+    {
+        if (false == is_array($attr)) {
+            return PEAR::raiseError("Parameter must be an array");
+        }
+        foreach ($attr as $k => $v) {
+            $k = $this->getAttrName($k);
+            if (false == is_array($v)) {
+                // delete attributes with empty values; treat ints as string
+                if (is_int($v)) {
+                    $v = "$v";
+                }
+                if ($v == null) {
+                    $this->delete($k);
+                    continue;
+                } else {
+                    $v = array($v);
+                }
+            }
+            // existing attributes will get replaced
+            if ($this->exists($k) || $force) {
+                $this->_changes["replace"][$k] = $v;
+                $this->_attributes[$k]         = $v;
+            } else {
+                // new ones just get added
+                $this->add(array($k => $v));
+            }
+        }
+        $return = true;
+        return $return;
+    }
+
+    /**
+    * Update the entry on the directory server
+    *
+    * This will evaluate all changes made so far and send them
+    * to the directory server.
+    * Please note, that if you make changes to objectclasses wich
+    * have mandatory attributes set, update() will currently fail.
+    * Remove the entry from the server and readd it as new in such cases.
+    * This also will deal with problems with setting structural object classes.
+    *
+    * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance
+    *
+    * @access public
+    * @return true|Net_LDAP2_Error
+    * @todo Entry rename with a DN containing special characters needs testing!
+    */
+    public function update($ldap = null)
+    {
+        if ($ldap) {
+            $msg = $this->setLDAP($ldap);
+            if (Net_LDAP2::isError($msg)) {
+                return PEAR::raiseError('You passed an invalid $ldap variable to update()');
+            }
+        }
+
+        // ensure we have a valid LDAP object
+        $ldap =& $this->getLDAP();
+        if (!$ldap instanceof Net_LDAP2) {
+            return PEAR::raiseError("The entries LDAP object is not valid");
+        }
+
+        // Get and check link
+        $link = $ldap->getLink();
+        if (!is_resource($link)) {
+            return PEAR::raiseError("Could not update entry: internal LDAP link is invalid");
+        }
+
+        /*
+        * Delete the entry
+        */
+        if (true === $this->_delete) {
+            return $ldap->delete($this);
+        }
+
+        /*
+        * New entry
+        */
+        if (true === $this->_new) {
+            $msg = $ldap->add($this);
+            if (Net_LDAP2::isError($msg)) {
+                return $msg;
+            }
+            $this->_new                = false;
+            $this->_changes['add']     = array();
+            $this->_changes['delete']  = array();
+            $this->_changes['replace'] = array();
+            $this->_original           = $this->_attributes;
+
+            $return = true;
+            return $return;
+        }
+
+        /*
+        * Rename/move entry
+        */
+        if (false == is_null($this->_newdn)) {
+            if ($ldap->getLDAPVersion() !== 3) {
+                return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3");
+            }
+            // make dn relative to parent (needed for ldap rename)
+            $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false));
+            if (Net_LDAP2::isError($parent)) {
+                return $parent;
+            }
+            $child = array_shift($parent);
+            // maybe the dn consist of a multivalued RDN, we must build the dn in this case
+            // because the $child-RDN is an array!
+            if (is_array($child)) {
+                $child = Net_LDAP2_Util::canonical_dn($child);
+            }
+            $parent = Net_LDAP2_Util::canonical_dn($parent);
+
+            // rename/move
+            if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) {
+                return PEAR::raiseError("Entry not renamed: " .
+                                        @ldap_error($link), @ldap_errno($link));
+            }
+            // reflect changes to local copy
+            $this->_dn    = $this->_newdn;
+            $this->_newdn = null;
+        }
+
+        /*
+        * Carry out modifications to the entry
+        */
+        // ADD
+        foreach ($this->_changes["add"] as $attr => $value) {
+            // if attribute exists, add new values
+            if ($this->exists($attr)) {
+                if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) {
+                    return PEAR::raiseError("Could not add new values to attribute $attr: " .
+                                            @ldap_error($link), @ldap_errno($link));
+                }
+            } else {
+                // new attribute
+                if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
+                    return PEAR::raiseError("Could not add new attribute $attr: " .
+                                            @ldap_error($link), @ldap_errno($link));
+                }
+            }
+            // all went well here, I guess
+            unset($this->_changes["add"][$attr]);
+        }
+
+        // DELETE
+        foreach ($this->_changes["delete"] as $attr => $value) {
+            // In LDAPv3 you need to specify the old values for deleting
+            if (is_null($value) && $ldap->getLDAPVersion() === 3) {
+                $value = $this->_original[$attr];
+            }
+            if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) {
+                return PEAR::raiseError("Could not delete attribute $attr: " .
+                                        @ldap_error($link), @ldap_errno($link));
+            }
+            unset($this->_changes["delete"][$attr]);
+        }
+
+        // REPLACE
+        foreach ($this->_changes["replace"] as $attr => $value) {
+            if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
+                return PEAR::raiseError("Could not replace attribute $attr values: " .
+                                        @ldap_error($link), @ldap_errno($link));
+            }
+            unset($this->_changes["replace"][$attr]);
+        }
+
+        // all went well, so _original (server) becomes _attributes (local copy)
+        $this->_original = $this->_attributes;
+
+        $return = true;
+        return $return;
+    }
+
+    /**
+    * Returns the right attribute name
+    *
+    * @param string $attr Name of attribute
+    *
+    * @access protected
+    * @return string The right name of the attribute
+    */
+    protected function getAttrName($attr)
+    {
+        $name = strtolower($attr);
+        if (array_key_exists($name, $this->_map)) {
+            $attr = $this->_map[$name];
+        }
+        return $attr;
+    }
+
+    /**
+    * Returns a reference to the LDAP-Object of this entry
+    *
+    * @access public
+    * @return Net_LDAP2|Net_LDAP2_Error   Reference to the Net_LDAP2 Object (the connection) or Net_LDAP2_Error
+    */
+    public function &getLDAP()
+    {
+        if (!$this->_ldap instanceof Net_LDAP2) {
+            $err = new PEAR_Error('LDAP is not a valid Net_LDAP2 object');
+            return $err;
+        } else {
+            return $this->_ldap;
+        }
+    }
+
+    /**
+    * Sets a reference to the LDAP-Object of this entry
+    *
+    * After setting a Net_LDAP2 object, calling update() will use that object for
+    * updating directory contents. Use this to dynamicly switch directorys.
+    *
+    * @param Net_LDAP2 &$ldap Net_LDAP2 object that this entry should be connected to
+    *
+    * @access public
+    * @return true|Net_LDAP2_Error
+    */
+    public function setLDAP(&$ldap)
+    {
+        if (!$ldap instanceof Net_LDAP2) {
+            return PEAR::raiseError("LDAP is not a valid Net_LDAP2 object");
+        } else {
+            $this->_ldap =& $ldap;
+            return true;
+        }
+    }
+
+    /**
+    * Marks the entry as new/existing.
+    *
+    * If an Entry is marked as new, it will be added to the directory
+    * when calling {@link update()}.
+    * If the entry is marked as old ($mark = false), then the entry is
+    * assumed to be present in the directory server wich results in
+    * modification when calling {@link update()}.
+    *
+    * @param boolean $mark Value to set, defaults to "true"
+    *
+    * @return void
+    */
+    public function markAsNew($mark = true)
+    {
+        $this->_new = ($mark)? true : false;
+    }
+
+    /**
+    * Applies a regular expression onto a single- or multivalued attribute (like preg_match())
+    *
+    * This method behaves like PHPs preg_match() but with some exceptions.
+    * If you want to retrieve match information, then you MUST pass the
+    * $matches parameter via reference! otherwise you will get no matches.
+    * Since it is possible to have multi valued attributes the $matches
+    * array will have a additionally numerical dimension (one for each value):
+    * <code>
+    * $matches = array(
+    *         0 => array (usual preg_match() returnarray),
+    *         1 => array (usual preg_match() returnarray)
+    *     )
+    * </code>
+    * Please note, that $matches will be initialized to an empty array inside.
+    *
+    * Usage example:
+    * <code>
+    * $result = $entry->preg_match('/089(\d+)/', 'telephoneNumber', &$matches);
+    * if ( $result === true ){
+    *     echo "First match: ".$matches[0][1];   // Match of value 1, content of first bracket
+    * } else {
+    *     if ( Net_LDAP2::isError($result) ) {
+    *         echo "Error: ".$result->getMessage();
+    *     } else {
+    *         echo "No match found.";
+    *     }
+    * }
+    * </code>
+    *
+    * Please note that it is important to test for an Net_LDAP2_Error, because objects are
+    * evaluating to true by default, thus if an error occured, and you only check using "==" then
+    * you get misleading results. Use the "identical" (===) operator to test for matches to
+    * avoid this as shown above.
+    *
+    * @param string $regex     The regular expression
+    * @param string $attr_name The attribute to search in
+    * @param array  $matches   (optional, PASS BY REFERENCE!) Array to store matches in
+    *
+    * @return boolean|Net_LDAP2_Error  TRUE, if we had a match in one of the values, otherwise false. Net_LDAP2_Error in case something went wrong
+    */
+    public function pregMatch($regex, $attr_name, $matches = array())
+    {
+        $matches = array();
+
+        // fetch attribute values
+        $attr = $this->getValue($attr_name, 'all');
+        if (Net_LDAP2::isError($attr)) {
+            return $attr;
+        } else {
+            unset($attr['count']);
+        }
+
+        // perform preg_match() on all values
+        $match = false;
+        foreach ($attr as $thisvalue) {
+            $matches_int = array();
+            if (preg_match($regex, $thisvalue, $matches_int)) {
+                $match = true;
+                array_push($matches, $matches_int); // store matches in reference
+            }
+        }
+        return $match;
+    }
+
+    /**
+    * Alias of {@link pregMatch()} for compatibility to Net_LDAP 1
+    *
+    * @see pregMatch()
+    * @return boolean|Net_LDAP2_Error
+    */
+    public function preg_match()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array( &$this, 'pregMatch' ), $args);
+    }
+
+    /**
+    * Tells if the entry is consiedered as new (not present in the server)
+    *
+    * Please note, that this doesn't tell you if the entry is present on the server.
+    * Use {@link Net_LDAP2::dnExists()} to see if an entry is already there.
+    *
+    * @return boolean
+    */
+    public function isNew()
+    {
+        return $this->_new;
+    }
+
+
+    /**
+    * Is this entry going to be deleted once update() is called?
+    *
+    * @return boolean
+    */
+    public function willBeDeleted()
+    {
+        return $this->_delete;
+    }
+
+    /**
+    * Is this entry going to be moved once update() is called?
+    *
+    * @return boolean
+    */
+    public function willBeMoved()
+    {
+        return ($this->dn() !== $this->currentDN());
+    }
+
+    /**
+    * Returns always the original DN
+    *
+    * If an entry will be moved but {@link update()} was not called,
+    * {@link dn()} will return the new DN. This method however, returns
+    * always the current active DN.
+    *
+    * @return string
+    */
+    public function currentDN()
+    {
+        return $this->_dn;
+    }
+
+    /**
+    * Returns the attribute changes to be carried out once update() is called
+    *
+    * @return array
+    */
+    public function getChanges()
+    {
+        return $this->_changes;
+    }
+}
+?>
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Filter.php b/plugins/LdapCommon/extlib/Net/LDAP2/Filter.php
new file mode 100644 (file)
index 0000000..0723eda
--- /dev/null
@@ -0,0 +1,514 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_Filter interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: Filter.php 289978 2009-10-27 09:56:41Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Includes
+*/
+require_once 'PEAR.php';
+require_once 'Util.php';
+
+/**
+* Object representation of a part of a LDAP filter.
+*
+* This Class is not completely compatible to the PERL interface!
+*
+* The purpose of this class is, that users can easily build LDAP filters
+* without having to worry about right escaping etc.
+* A Filter is built using several independent filter objects
+* which are combined afterwards. This object works in two
+* modes, depending how the object is created.
+* If the object is created using the {@link create()} method, then this is a leaf-object.
+* If the object is created using the {@link combine()} method, then this is a container object.
+*
+* LDAP filters are defined in RFC-2254 and can be found under
+* {@link http://www.ietf.org/rfc/rfc2254.txt}
+*
+* Here a quick copy&paste example:
+* <code>
+* $filter0 = Net_LDAP2_Filter::create('stars', 'equals', '***');
+* $filter_not0 = Net_LDAP2_Filter::combine('not', $filter0);
+*
+* $filter1 = Net_LDAP2_Filter::create('gn', 'begins', 'bar');
+* $filter2 = Net_LDAP2_Filter::create('gn', 'ends', 'baz');
+* $filter_comp = Net_LDAP2_Filter::combine('or',array($filter_not0, $filter1, $filter2));
+*
+* echo $filter_comp->asString();
+* // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz))
+* // The stars in $filter0 are treaten as real stars unless you disable escaping.
+* </code>
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Benedikt Hallinger <beni@php.net>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP2/
+*/
+class Net_LDAP2_Filter extends PEAR
+{
+    /**
+    * Storage for combination of filters
+    *
+    * This variable holds a array of filter objects
+    * that should be combined by this filter object.
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_subfilters = array();
+
+    /**
+    * Match of this filter
+    *
+    * If this is a leaf filter, then a matching rule is stored,
+    * if it is a container, then it is a logical operator
+    *
+    * @access protected
+    * @var string
+    */
+    protected $_match;
+
+    /**
+    * Single filter
+    *
+    * If we operate in leaf filter mode,
+    * then the constructing method stores
+    * the filter representation here
+    *
+    * @acces private
+    * @var string
+    */
+    protected $_filter;
+
+    /**
+    * Create a new Net_LDAP2_Filter object and parse $filter.
+    *
+    * This is for PERL Net::LDAP interface.
+    * Construction of Net_LDAP2_Filter objects should happen through either
+    * {@link create()} or {@link combine()} which give you more control.
+    * However, you may use the perl iterface if you already have generated filters.
+    *
+    * @param string $filter LDAP filter string
+    *
+    * @see parse()
+    */
+    public function __construct($filter = false)
+    {
+        // The optional parameter must remain here, because otherwise create() crashes
+        if (false !== $filter) {
+            $filter_o = self::parse($filter);
+            if (PEAR::isError($filter_o)) {
+                $this->_filter = $filter_o; // assign error, so asString() can report it
+            } else {
+                $this->_filter = $filter_o->asString();
+            }
+        }
+    }
+
+    /**
+    * Constructor of a new part of a LDAP filter.
+    *
+    * The following matching rules exists:
+    *    - equals:         One of the attributes values is exactly $value
+    *                      Please note that case sensitiviness is depends on the
+    *                      attributes syntax configured in the server.
+    *    - begins:         One of the attributes values must begin with $value
+    *    - ends:           One of the attributes values must end with $value
+    *    - contains:       One of the attributes values must contain $value
+    *    - present | any:  The attribute can contain any value but must be existent
+    *    - greater:        The attributes value is greater than $value
+    *    - less:           The attributes value is less than $value
+    *    - greaterOrEqual: The attributes value is greater or equal than $value
+    *    - lessOrEqual:    The attributes value is less or equal than $value
+    *    - approx:         One of the attributes values is similar to $value
+    *
+    * If $escape is set to true (default) then $value will be escaped
+    * properly. If it is set to false then $value will be treaten as raw filter value string.
+    * You should escape yourself using {@link Net_LDAP2_Util::escape_filter_value()}!
+    *
+    * Examples:
+    * <code>
+    *   // This will find entries that contain an attribute "sn" that ends with "foobar":
+    *   $filter = new Net_LDAP2_Filter('sn', 'ends', 'foobar');
+    *
+    *   // This will find entries that contain an attribute "sn" that has any value set:
+    *   $filter = new Net_LDAP2_Filter('sn', 'any');
+    * </code>
+    *
+    * @param string  $attr_name Name of the attribute the filter should apply to
+    * @param string  $match     Matching rule (equals, begins, ends, contains, greater, less, greaterOrEqual, lessOrEqual, approx, any)
+    * @param string  $value     (optional) if given, then this is used as a filter
+    * @param boolean $escape    Should $value be escaped? (default: yes, see {@link Net_LDAP2_Util::escape_filter_value()} for detailed information)
+    *
+    * @return Net_LDAP2_Filter|Net_LDAP2_Error
+    */
+    public static function &create($attr_name, $match, $value = '', $escape = true)
+    {
+        $leaf_filter = new Net_LDAP2_Filter();
+        if ($escape) {
+            $array = Net_LDAP2_Util::escape_filter_value(array($value));
+            $value = $array[0];
+        }
+        switch (strtolower($match)) {
+        case 'equals':
+            $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')';
+            break;
+        case 'begins':
+            $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)';
+            break;
+        case 'ends':
+            $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')';
+            break;
+        case 'contains':
+            $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)';
+            break;
+        case 'greater':
+            $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')';
+            break;
+        case 'less':
+            $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')';
+            break;
+        case 'greaterorequal':
+        case '>=':
+            $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')';
+            break;
+        case 'lessorequal':
+        case '<=':
+            $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')';
+            break;
+        case 'approx':
+        case '~=':
+            $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')';
+            break;
+        case 'any':
+        case 'present': // alias that may improve user code readability
+            $leaf_filter->_filter = '(' . $attr_name . '=*)';
+            break;
+        default:
+            return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!');
+        }
+        return $leaf_filter;
+    }
+
+    /**
+    * Combine two or more filter objects using a logical operator
+    *
+    * This static method combines two or more filter objects and returns one single
+    * filter object that contains all the others.
+    * Call this method statically: $filter = Net_LDAP2_Filter('or', array($filter1, $filter2))
+    * If the array contains filter strings instead of filter objects, we will try to parse them.
+    *
+    * @param string                 $log_op  The locicall operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!"
+    * @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects
+    *
+    * @return Net_LDAP2_Filter|Net_LDAP2_Error
+    * @static
+    */
+    public static function &combine($log_op, $filters)
+    {
+        if (PEAR::isError($filters)) {
+            return $filters;
+        }
+
+        // substitude named operators to logical operators
+        if ($log_op == 'and') $log_op = '&';
+        if ($log_op == 'or')  $log_op = '|';
+        if ($log_op == 'not') $log_op = '!';
+
+        // tests for sane operation
+        if ($log_op == '!') {
+            // Not-combination, here we only accept one filter object or filter string
+            if ($filters instanceof Net_LDAP2_Filter) {
+                $filters = array($filters); // force array
+            } elseif (is_string($filters)) {
+                $filter_o = self::parse($filters);
+                if (PEAR::isError($filter_o)) {
+                    $err = PEAR::raiseError('Net_LDAP2_Filter combine error: '.$filter_o->getMessage());
+                    return $err;
+                } else {
+                    $filters = array($filter_o);
+                }
+            } elseif (is_array($filters)) {
+                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!');
+                return $err;
+            } else {
+                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!');
+                return $err;
+            }
+        } elseif ($log_op == '&' || $log_op == '|') {
+            if (!is_array($filters) || count($filters) < 2) {
+                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: parameter $filters is not an array or contains less than two Net_LDAP2_Filter objects!');
+                return $err;
+            }
+        } else {
+            $err = PEAR::raiseError('Net_LDAP2_Filter combine error: logical operator is not known!');
+            return $err;
+        }
+
+        $combined_filter = new Net_LDAP2_Filter();
+        foreach ($filters as $key => $testfilter) {     // check for errors
+            if (PEAR::isError($testfilter)) {
+                return $testfilter;
+            } elseif (is_string($testfilter)) {
+                // string found, try to parse into an filter object
+                $filter_o = self::parse($testfilter);
+                if (PEAR::isError($filter_o)) {
+                    return $filter_o;
+                } else {
+                    $filters[$key] = $filter_o;
+                }
+            } elseif (!$testfilter instanceof Net_LDAP2_Filter) {
+                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: invalid object passed in array $filters!');
+                return $err;
+            }
+        }
+
+        $combined_filter->_subfilters = $filters;
+        $combined_filter->_match      = $log_op;
+        return $combined_filter;
+    }
+
+    /**
+    * Parse FILTER into a Net_LDAP2_Filter object
+    *
+    * This parses an filter string into Net_LDAP2_Filter objects.
+    *
+    * @param string $FILTER The filter string
+    *
+    * @access static
+    * @return Net_LDAP2_Filter|Net_LDAP2_Error
+    * @todo Leaf-mode: Do we need to escape at all? what about *-chars?check for the need of encoding values, tackle problems (see code comments)
+    */
+    public static function parse($FILTER)
+    {
+        if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) {
+            if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) {
+                // Subfilter processing: pass subfilters to parse() and combine
+                // the objects using the logical operator detected
+                // we have now something like "&(...)(...)(...)" but at least one part ("!(...)").
+                // Each subfilter could be an arbitary complex subfilter.
+
+                // extract logical operator and filter arguments
+                $log_op              = substr($matches[1], 0, 1);
+                $remaining_component = substr($matches[1], 1);
+
+                // split $remaining_component into individual subfilters
+                // we cannot use split() for this, because we do not know the
+                // complexiness of the subfilter. Thus, we look trough the filter
+                // string and just recognize ending filters at the first level.
+                // We record the index number of the char and use that information
+                // later to split the string.
+                $sub_index_pos = array();
+                $prev_char     = ''; // previous character looked at
+                $level         = 0;  // denotes the current bracket level we are,
+                                     //   >1 is too deep, 1 is ok, 0 is outside any
+                                     //   subcomponent
+                for ($curpos = 0; $curpos < strlen($remaining_component); $curpos++) {
+                    $cur_char = substr($remaining_component, $curpos, 1);
+
+                    // rise/lower bracket level
+                    if ($cur_char == '(' && $prev_char != '\\') {
+                        $level++;
+                    } elseif  ($cur_char == ')' && $prev_char != '\\') {
+                        $level--;
+                    }
+
+                    if ($cur_char == '(' && $prev_char == ')' && $level == 1) {
+                        array_push($sub_index_pos, $curpos); // mark the position for splitting
+                    }
+                    $prev_char = $cur_char;
+                }
+
+                // now perform the splits. To get also the last part, we
+                // need to add the "END" index to the split array
+                array_push($sub_index_pos, strlen($remaining_component));
+                $subfilters = array();
+                $oldpos = 0;
+                foreach ($sub_index_pos as $s_pos) {
+                    $str_part = substr($remaining_component, $oldpos, $s_pos - $oldpos);
+                    array_push($subfilters, $str_part);
+                    $oldpos = $s_pos;
+                }
+
+                // some error checking...
+                if (count($subfilters) == 1) {
+                    // only one subfilter found
+                } elseif (count($subfilters) > 1) {
+                    // several subfilters found
+                    if ($log_op == "!") {
+                        return PEAR::raiseError("Filter parsing error: invalid filter syntax - NOT operator detected but several arguments given!");
+                    }
+                } else {
+                    // this should not happen unless the user specified a wrong filter
+                    return PEAR::raiseError("Filter parsing error: invalid filter syntax - got operator '$log_op' but no argument!");
+                }
+
+                // Now parse the subfilters into objects and combine them using the operator
+                $subfilters_o = array();
+                foreach ($subfilters as $s_s) {
+                    $o = self::parse($s_s);
+                    if (PEAR::isError($o)) {
+                        return $o;
+                    } else {
+                        array_push($subfilters_o, self::parse($s_s));
+                    }
+                }
+
+                $filter_o = self::combine($log_op, $subfilters_o);
+                return $filter_o;
+
+            } else {
+                // This is one leaf filter component, do some syntax checks, then escape and build filter_o
+                // $matches[1] should be now something like "foo=bar"
+
+                // detect multiple leaf components
+                // [TODO] Maybe this will make problems with filters containing brackets inside the value
+                if (stristr($matches[1], ')(')) {
+                    return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!");
+                } else {
+                    $filter_parts = preg_split('/(?<!\\\\)(=|=~|>|<|>=|<=)/', $matches[1], 2, PREG_SPLIT_DELIM_CAPTURE);
+                    if (count($filter_parts) != 3) {
+                        return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used");
+                    } else {
+                        $filter_o          = new Net_LDAP2_Filter();
+                        // [TODO]: Do we need to escape at all? what about *-chars user provide and that should remain special?
+                        //         I think, those prevent escaping! We need to check against PERL Net::LDAP!
+                        // $value_arr         = Net_LDAP2_Util::escape_filter_value(array($filter_parts[2]));
+                        // $value             = $value_arr[0];
+                        $value             = $filter_parts[2];
+                        $filter_o->_filter = '('.$filter_parts[0].$filter_parts[1].$value.')';
+                        return $filter_o;
+                    }
+                }
+            }
+        } else {
+               // ERROR: Filter components must be enclosed in round brackets
+               return PEAR::raiseError("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets");
+        }
+    }
+
+    /**
+    * Get the string representation of this filter
+    *
+    * This method runs through all filter objects and creates
+    * the string representation of the filter. If this
+    * filter object is a leaf filter, then it will return
+    * the string representation of this filter.
+    *
+    * @return string|Net_LDAP2_Error
+    */
+    public function asString()
+    {
+        if ($this->isLeaf()) {
+            $return = $this->_filter;
+        } else {
+            $return = '';
+            foreach ($this->_subfilters as $filter) {
+                $return = $return.$filter->asString();
+            }
+            $return = '(' . $this->_match . $return . ')';
+        }
+        return $return;
+    }
+
+    /**
+    * Alias for perl interface as_string()
+    *
+    * @see asString()
+    * @return string|Net_LDAP2_Error
+    */
+    public function as_string()
+    {
+        return $this->asString();
+    }
+
+    /**
+    * Print the text representation of the filter to FH, or the currently selected output handle if FH is not given
+    *
+    * This method is only for compatibility to the perl interface.
+    * However, the original method was called "print" but due to PHP language restrictions,
+    * we can't have a print() method.
+    *
+    * @param resource $FH (optional) A filehandle resource
+    *
+    * @return true|Net_LDAP2_Error
+    */
+    public function printMe($FH = false)
+    {
+        if (!is_resource($FH)) {
+            if (PEAR::isError($FH)) {
+                return $FH;
+            }
+            $filter_str = $this->asString();
+            if (PEAR::isError($filter_str)) {
+                return $filter_str;
+            } else {
+                print($filter_str);
+            }
+        } else {
+            $filter_str = $this->asString();
+            if (PEAR::isError($filter_str)) {
+                return $filter_str;
+            } else {
+                $res = @fwrite($FH, $this->asString());
+                if ($res == false) {
+                    return PEAR::raiseError("Unable to write filter string to filehandle \$FH!");
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+    * This can be used to escape a string to provide a valid LDAP-Filter.
+    *
+    * LDAP will only recognise certain characters as the
+    * character istself if they are properly escaped. This is
+    * what this method does.
+    * The method can be called statically, so you can use it outside
+    * for your own purposes (eg for escaping only parts of strings)
+    *
+    * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}.
+    * For upward compatibiliy reasons you are strongly encouraged to use the escape
+    * methods provided by the Net_LDAP2_Util class.
+    *
+    * @param string $value Any string who should be escaped
+    *
+    * @static
+    * @return string         The string $string, but escaped
+    * @deprecated  Do not use this method anymore, instead use Net_LDAP2_Util::escape_filter_value() directly
+    */
+    public static function escape($value)
+    {
+        $return = Net_LDAP2_Util::escape_filter_value(array($value));
+        return $return[0];
+    }
+
+    /**
+    * Is this a container or a leaf filter object?
+    *
+    * @access protected
+    * @return boolean
+    */
+    protected function isLeaf()
+    {
+        if (count($this->_subfilters) > 0) {
+            return false; // Container!
+        } else {
+            return true; // Leaf!
+        }
+    }
+}
+?>
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php b/plugins/LdapCommon/extlib/Net/LDAP2/LDIF.php
new file mode 100644 (file)
index 0000000..34f3e75
--- /dev/null
@@ -0,0 +1,922 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_LDIF interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: LDIF.php 286718 2009-08-03 07:30:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Includes
+*/
+require_once 'PEAR.php';
+require_once 'Net/LDAP2.php';
+require_once 'Net/LDAP2/Entry.php';
+require_once 'Net/LDAP2/Util.php';
+
+/**
+* LDIF capabilitys for Net_LDAP2, closely taken from PERLs Net::LDAP
+*
+* It provides a means to convert between Net_LDAP2_Entry objects and LDAP entries
+* represented in LDIF format files. Reading and writing are supported and may
+* manipulate single entries or lists of entries.
+*
+* Usage example:
+* <code>
+* // Read and parse an ldif-file into Net_LDAP2_Entry objects
+* // and print out the DNs. Store the entries for later use.
+* require 'Net/LDAP2/LDIF.php';
+* $options = array(
+*       'onerror' => 'die'
+* );
+* $entries = array();
+* $ldif = new Net_LDAP2_LDIF('test.ldif', 'r', $options);
+* do {
+*       $entry = $ldif->read_entry();
+*       $dn    = $entry->dn();
+*       echo " done building entry: $dn\n";
+*       array_push($entries, $entry);
+* } while (!$ldif->eof());
+* $ldif->done();
+*
+*
+* // write those entries to another file
+* $ldif = new Net_LDAP2_LDIF('test.out.ldif', 'w', $options);
+* $ldif->write_entry($entries);
+* $ldif->done();
+* </code>
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Benedikt Hallinger <beni@php.net>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP22/
+* @see      http://www.ietf.org/rfc/rfc2849.txt
+* @todo     Error handling should be PEARified
+* @todo     LDAPv3 controls are not implemented yet
+*/
+class Net_LDAP2_LDIF extends PEAR
+{
+    /**
+    * Options
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_options = array('encode'    => 'base64',
+                                'onerror'   => null,
+                                'change'    => 0,
+                                'lowercase' => 0,
+                                'sort'      => 0,
+                                'version'   => null,
+                                'wrap'      => 78,
+                                'raw'       => ''
+                               );
+
+    /**
+    * Errorcache
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_error = array('error' => null,
+                              'line'  => 0
+                             );
+
+    /**
+    * Filehandle for read/write
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_FH = null;
+
+    /**
+    * Says, if we opened the filehandle ourselves
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_FH_opened = false;
+
+    /**
+    * Linecounter for input file handle
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_input_line = 0;
+
+    /**
+    * counter for processed entries
+    *
+    * @access protected
+    * @var int
+    */
+    protected $_entrynum = 0;
+
+    /**
+    * Mode we are working in
+    *
+    * Either 'r', 'a' or 'w'
+    *
+    * @access protected
+    * @var string
+    */
+    protected $_mode = false;
+
+    /**
+    * Tells, if the LDIF version string was already written
+    *
+    * @access protected
+    * @var boolean
+    */
+    protected $_version_written = false;
+
+    /**
+    * Cache for lines that have build the current entry
+    *
+    * @access protected
+    * @var boolean
+    */
+    protected $_lines_cur = array();
+
+    /**
+    * Cache for lines that will build the next entry
+    *
+    * @access protected
+    * @var boolean
+    */
+    protected $_lines_next = array();
+
+    /**
+    * Open LDIF file for reading or for writing
+    *
+    * new (FILE):
+    * Open the file read-only. FILE may be the name of a file
+    * or an already open filehandle.
+    * If the file doesn't exist, it will be created if in write mode.
+    *
+    * new (FILE, MODE, OPTIONS):
+    *     Open the file with the given MODE (see PHPs fopen()), eg "w" or "a".
+    *     FILE may be the name of a file or an already open filehandle.
+    *     PERLs Net_LDAP2 "FILE|" mode does not work curently.
+    *
+    *     OPTIONS is an associative array and may contain:
+    *       encode => 'none' | 'canonical' | 'base64'
+    *         Some DN values in LDIF cannot be written verbatim and have to be encoded in some way:
+    *         'none'       No encoding.
+    *         'canonical'  See "canonical_dn()" in Net::LDAP::Util.
+    *         'base64'     Use base64. (default, this differs from the Perl interface.
+    *                                   The perl default is "none"!)
+    *
+    *       onerror => 'die' | 'warn' | NULL
+    *         Specify what happens when an error is detected.
+    *         'die'  Net_LDAP2_LDIF will croak with an appropriate message.
+    *         'warn' Net_LDAP2_LDIF will warn (echo) with an appropriate message.
+    *         NULL   Net_LDAP2_LDIF will not warn (default), use error().
+    *
+    *       change => 1
+    *         Write entry changes to the LDIF file instead of the entries itself. I.e. write LDAP
+    *         operations acting on the entries to the file instead of the entries contents.
+    *         This writes the changes usually carried out by an update() to the LDIF file.
+    *
+    *       lowercase => 1
+    *         Convert attribute names to lowercase when writing.
+    *
+    *       sort => 1
+    *         Sort attribute names when writing entries according to the rule:
+    *         objectclass first then all other attributes alphabetically sorted by attribute name
+    *
+    *       version => '1'
+    *         Set the LDIF version to write to the resulting LDIF file.
+    *         According to RFC 2849 currently the only legal value for this option is 1.
+    *         When this option is set Net_LDAP2_LDIF tries to adhere more strictly to
+    *         the LDIF specification in RFC2489 in a few places.
+    *         The default is NULL meaning no version information is written to the LDIF file.
+    *
+    *       wrap => 78
+    *         Number of columns where output line wrapping shall occur.
+    *         Default is 78. Setting it to 40 or lower inhibits wrapping.
+    *
+    *       raw => REGEX
+    *         Use REGEX to denote the names of attributes that are to be
+    *         considered binary in search results if writing entries.
+    *         Example: raw => "/(?i:^jpegPhoto|;binary)/i"
+    *
+    * @param string|ressource $file    Filename or filehandle
+    * @param string           $mode    Mode to open filename
+    * @param array            $options Options like described above
+    */
+    public function __construct($file, $mode = 'r', $options = array())
+    {
+        $this->PEAR('Net_LDAP2_Error'); // default error class
+
+        // First, parse options
+        // todo: maybe implement further checks on possible values
+        foreach ($options as $option => $value) {
+            if (!array_key_exists($option, $this->_options)) {
+                $this->dropError('Net_LDAP2_LDIF error: option '.$option.' not known!');
+                return;
+            } else {
+                $this->_options[$option] = strtolower($value);
+            }
+        }
+
+        // setup LDIF class
+        $this->version($this->_options['version']);
+
+        // setup file mode
+        if (!preg_match('/^[rwa]\+?$/', $mode)) {
+            $this->dropError('Net_LDAP2_LDIF error: file mode '.$mode.' not supported!');
+        } else {
+            $this->_mode = $mode;
+
+            // setup filehandle
+            if (is_resource($file)) {
+                // TODO: checks on mode possible?
+                $this->_FH =& $file;
+            } else {
+                $imode = substr($this->_mode, 0, 1);
+                if ($imode == 'r') {
+                    if (!file_exists($file)) {
+                        $this->dropError('Unable to open '.$file.' for read: file not found');
+                        $this->_mode = false;
+                    }
+                    if (!is_readable($file)) {
+                        $this->dropError('Unable to open '.$file.' for read: permission denied');
+                        $this->_mode = false;
+                    }
+                }
+
+                if (($imode == 'w' || $imode == 'a')) {
+                    if (file_exists($file)) {
+                        if (!is_writable($file)) {
+                            $this->dropError('Unable to open '.$file.' for write: permission denied');
+                            $this->_mode = false;
+                        }
+                    } else {
+                        if (!@touch($file)) {
+                            $this->dropError('Unable to create '.$file.' for write: permission denied');
+                            $this->_mode = false;
+                        }
+                    }
+                }
+
+                if ($this->_mode) {
+                    $this->_FH = @fopen($file, $this->_mode);
+                    if (false === $this->_FH) {
+                        // Fallback; should never be reached if tests above are good enough!
+                        $this->dropError('Net_LDAP2_LDIF error: Could not open file '.$file);
+                    } else {
+                        $this->_FH_opened = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+    * Read one entry from the file and return it as a Net::LDAP::Entry object.
+    *
+    * @return Net_LDAP2_Entry
+    */
+    public function read_entry()
+    {
+        // read fresh lines, set them as current lines and create the entry
+        $attrs = $this->next_lines(true);
+        if (count($attrs) > 0) {
+            $this->_lines_cur = $attrs;
+        }
+        return $this->current_entry();
+    }
+
+    /**
+    * Returns true when the end of the file is reached.
+    *
+    * @return boolean
+    */
+    public function eof()
+    {
+        return feof($this->_FH);
+    }
+
+    /**
+    * Write the entry or entries to the LDIF file.
+    *
+    * If you want to build an LDIF file containing several entries AND
+    * you want to call write_entry() several times, you must open the filehandle
+    * in append mode ("a"), otherwise you will always get the last entry only.
+    *
+    * @param Net_LDAP2_Entry|array $entries Entry or array of entries
+    *
+    * @return void
+    * @todo implement operations on whole entries (adding a whole entry)
+    */
+    public function write_entry($entries)
+    {
+        if (!is_array($entries)) {
+            $entries = array($entries);
+        }
+
+        foreach ($entries as $entry) {
+            $this->_entrynum++;
+            if (!$entry instanceof Net_LDAP2_Entry) {
+                $this->dropError('Net_LDAP2_LDIF error: entry '.$this->_entrynum.' is not an Net_LDAP2_Entry object');
+            } else {
+                if ($this->_options['change']) {
+                    // LDIF change mode
+                    // fetch change information from entry
+                    $entry_attrs_changes = $entry->getChanges();
+                    $num_of_changes      = count($entry_attrs_changes['add'])
+                                           + count($entry_attrs_changes['replace'])
+                                           + count($entry_attrs_changes['delete']);
+
+                    $is_changed = ($num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved());
+
+                    // write version if not done yet
+                    // also write DN of entry
+                    if ($is_changed) {
+                        if (!$this->_version_written) {
+                            $this->write_version();
+                        }
+                        $this->writeDN($entry->currentDN());
+                    }
+
+                    // process changes
+                    // TODO: consider DN add!
+                    if ($entry->willBeDeleted()) {
+                        $this->writeLine("changetype: delete".PHP_EOL);
+                    } elseif ($entry->willBeMoved()) {
+                        $this->writeLine("changetype: modrdn".PHP_EOL);
+                        $olddn     = Net_LDAP2_Util::ldap_explode_dn($entry->currentDN(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs
+                        $oldrdn    = array_shift($olddn);
+                        $oldparent = implode(',', $olddn);
+                        $newdn     = Net_LDAP2_Util::ldap_explode_dn($entry->dn(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs
+                        $rdn       = array_shift($newdn);
+                        $parent    = implode(',', $newdn);
+                        $this->writeLine("newrdn: ".$rdn.PHP_EOL);
+                        $this->writeLine("deleteoldrdn: 1".PHP_EOL);
+                        if ($parent !== $oldparent) {
+                            $this->writeLine("newsuperior: ".$parent.PHP_EOL);
+                        }
+                        // TODO: What if the entry has attribute changes as well?
+                        //       I think we should check for that and make a dummy
+                        //       entry with the changes that is written to the LDIF file
+                    } elseif ($num_of_changes > 0) {
+                        // write attribute change data
+                        $this->writeLine("changetype: modify".PHP_EOL);
+                        foreach ($entry_attrs_changes as $changetype => $entry_attrs) {
+                            foreach ($entry_attrs as $attr_name => $attr_values) {
+                                $this->writeLine("$changetype: $attr_name".PHP_EOL);
+                                if ($attr_values !== null) $this->writeAttribute($attr_name, $attr_values, $changetype);
+                                $this->writeLine("-".PHP_EOL);
+                            }
+                        }
+                    }
+
+                    // finish this entrys data if we had changes
+                    if ($is_changed) {
+                        $this->finishEntry();
+                    }
+                } else {
+                    // LDIF-content mode
+                    // fetch attributes for further processing
+                    $entry_attrs = $entry->getValues();
+
+                    // sort and put objectclass-attrs to first position
+                    if ($this->_options['sort']) {
+                        ksort($entry_attrs);
+                        if (array_key_exists('objectclass', $entry_attrs)) {
+                            $oc = $entry_attrs['objectclass'];
+                            unset($entry_attrs['objectclass']);
+                            $entry_attrs = array_merge(array('objectclass' => $oc), $entry_attrs);
+                        }
+                    }
+
+                    // write data
+                    if (!$this->_version_written) {
+                        $this->write_version();
+                    }
+                    $this->writeDN($entry->dn());
+                    foreach ($entry_attrs as $attr_name => $attr_values) {
+                        $this->writeAttribute($attr_name, $attr_values);
+                    }
+                    $this->finishEntry();
+                }
+            }
+        }
+    }
+
+    /**
+    * Write version to LDIF
+    *
+    * If the object's version is defined, this method allows to explicitely write the version before an entry is written.
+    * If not called explicitely, it gets called automatically when writing the first entry.
+    *
+    * @return void
+    */
+    public function write_version()
+    {
+        $this->_version_written = true;
+        if (!is_null($this->version())) {
+            return $this->writeLine('version: '.$this->version().PHP_EOL, 'Net_LDAP2_LDIF error: unable to write version');
+        }
+    }
+
+    /**
+    * Get or set LDIF version
+    *
+    * If called without arguments it returns the version of the LDIF file or NULL if no version has been set.
+    * If called with an argument it sets the LDIF version to VERSION.
+    * According to RFC 2849 currently the only legal value for VERSION is 1.
+    *
+    * @param int $version (optional) LDIF version to set
+    *
+    * @return int
+    */
+    public function version($version = null)
+    {
+        if ($version !== null) {
+            if ($version != 1) {
+                $this->dropError('Net_LDAP2_LDIF error: illegal LDIF version set');
+            } else {
+                $this->_options['version'] = $version;
+            }
+        }
+        return $this->_options['version'];
+    }
+
+    /**
+    * Returns the file handle the Net_LDAP2_LDIF object reads from or writes to.
+    *
+    * You can, for example, use this to fetch the content of the LDIF file yourself
+    *
+    * @return null|resource
+    */
+    public function &handle()
+    {
+        if (!is_resource($this->_FH)) {
+            $this->dropError('Net_LDAP2_LDIF error: invalid file resource');
+            $null = null;
+            return $null;
+        } else {
+            return $this->_FH;
+        }
+    }
+
+    /**
+    * Clean up
+    *
+    * This method signals that the LDIF object is no longer needed.
+    * You can use this to free up some memory and close the file handle.
+    * The file handle is only closed, if it was opened from Net_LDAP2_LDIF.
+    *
+    * @return void
+    */
+    public function done()
+    {
+        // close FH if we opened it
+        if ($this->_FH_opened) {
+            fclose($this->handle());
+        }
+
+        // free variables
+        foreach (get_object_vars($this) as $name => $value) {
+            unset($this->$name);
+        }
+    }
+
+    /**
+    * Returns last error message if error was found.
+    *
+    * Example:
+    * <code>
+    *  $ldif->someAction();
+    *  if ($ldif->error()) {
+    *     echo "Error: ".$ldif->error()." at input line: ".$ldif->error_lines();
+    *  }
+    * </code>
+    *
+    * @param boolean $as_string If set to true, only the message is returned
+    *
+    * @return false|Net_LDAP2_Error
+    */
+    public function error($as_string = false)
+    {
+        if (Net_LDAP2::isError($this->_error['error'])) {
+            return ($as_string)? $this->_error['error']->getMessage() : $this->_error['error'];
+        } else {
+            return false;
+        }
+    }
+
+    /**
+    * Returns lines that resulted in error.
+    *
+    * Perl returns an array of faulty lines in list context,
+    * but we always just return an int because of PHPs language.
+    *
+    * @return int
+    */
+    public function error_lines()
+    {
+        return $this->_error['line'];
+    }
+
+    /**
+    * Returns the current Net::LDAP::Entry object.
+    *
+    * @return Net_LDAP2_Entry|false
+    */
+    public function current_entry()
+    {
+        return $this->parseLines($this->current_lines());
+    }
+
+    /**
+    * Parse LDIF lines of one entry into an Net_LDAP2_Entry object
+    *
+    * @param array $lines LDIF lines for one entry
+    *
+    * @return Net_LDAP2_Entry|false Net_LDAP2_Entry object for those lines
+    * @todo what about file inclusions and urls? "jpegphoto:< file:///usr/local/directory/photos/fiona.jpg"
+    */
+    public function parseLines($lines)
+    {
+        // parse lines into an array of attributes and build the entry
+        $attributes = array();
+        $dn = false;
+        foreach ($lines as $line) {
+            if (preg_match('/^(\w+)(:|::|:<)\s(.+)$/', $line, $matches)) {
+                $attr  =& $matches[1];
+                $delim =& $matches[2];
+                $data  =& $matches[3];
+
+                if ($delim == ':') {
+                    // normal data
+                    $attributes[$attr][] = $data;
+                } elseif ($delim == '::') {
+                    // base64 data
+                    $attributes[$attr][] = base64_decode($data);
+                } elseif ($delim == ':<') {
+                    // file inclusion
+                    // TODO: Is this the job of the LDAP-client or the server?
+                    $this->dropError('File inclusions are currently not supported');
+                    //$attributes[$attr][] = ...;
+                } else {
+                    // since the pattern above, the delimeter cannot be something else.
+                    $this->dropError('Net_LDAP2_LDIF parsing error: invalid syntax at parsing entry line: '.$line);
+                    continue;
+                }
+
+                if (strtolower($attr) == 'dn') {
+                    // DN line detected
+                    $dn = $attributes[$attr][0];  // save possibly decoded DN
+                    unset($attributes[$attr]);    // remove wrongly added "dn: " attribute
+                }
+            } else {
+                // line not in "attr: value" format -> ignore
+                // maybe we should rise an error here, but this should be covered by
+                // next_lines() already. A problem arises, if users try to feed data of
+                // several entries to this method - the resulting entry will
+                // get wrong attributes. However, this is already mentioned in the
+                // methods documentation above.
+            }
+        }
+
+        if (false === $dn) {
+            $this->dropError('Net_LDAP2_LDIF parsing error: unable to detect DN for entry');
+            return false;
+        } else {
+            $newentry = Net_LDAP2_Entry::createFresh($dn, $attributes);
+            return $newentry;
+        }
+    }
+
+    /**
+    * Returns the lines that generated the current Net::LDAP::Entry object.
+    *
+    * Note that this returns an empty array if no lines have been read so far.
+    *
+    * @return array Array of lines
+    */
+    public function current_lines()
+    {
+        return $this->_lines_cur;
+    }
+
+    /**
+    * Returns the lines that will generate the next Net::LDAP::Entry object.
+    *
+    * If you set $force to TRUE then you can iterate over the lines that build
+    * up entries manually. Otherwise, iterating is done using {@link read_entry()}.
+    * Force will move the file pointer forward, thus returning the next entries lines.
+    *
+    * Wrapped lines will be unwrapped. Comments are stripped.
+    *
+    * @param boolean $force Set this to true if you want to iterate over the lines manually
+    *
+    * @return array
+    */
+    public function next_lines($force = false)
+    {
+        // if we already have those lines, just return them, otherwise read
+        if (count($this->_lines_next) == 0 || $force) {
+            $this->_lines_next = array(); // empty in case something was left (if used $force)
+            $entry_done        = false;
+            $fh                = &$this->handle();
+            $commentmode       = false; // if we are in an comment, for wrapping purposes
+            $datalines_read    = 0;     // how many lines with data we have read
+
+            while (!$entry_done && !$this->eof()) {
+                $this->_input_line++;
+                // Read line. Remove line endings, we want only data;
+                // this is okay since ending spaces should be encoded
+                $data = rtrim(fgets($fh));
+                if ($data === false) {
+                    // error only, if EOF not reached after fgets() call
+                    if (!$this->eof()) {
+                        $this->dropError('Net_LDAP2_LDIF error: error reading from file at input line '.$this->_input_line, $this->_input_line);
+                    }
+                    break;
+                } else {
+                    if (count($this->_lines_next) > 0 && preg_match('/^$/', $data)) {
+                        // Entry is finished if we have an empty line after we had data
+                        $entry_done = true;
+
+                        // Look ahead if the next EOF is nearby. Comments and empty
+                        // lines at the file end may cause problems otherwise
+                        $current_pos = ftell($fh);
+                        $data        = fgets($fh);
+                        while (!feof($fh)) {
+                            if (preg_match('/^\s*$/', $data) || preg_match('/^#/', $data)) {
+                                // only empty lines or comments, continue to seek
+                                // TODO: Known bug: Wrappings for comments are okay but are treaten as
+                                //       error, since we do not honor comment mode here.
+                                //       This should be a very theoretically case, however
+                                //       i am willing to fix this if really necessary.
+                                $this->_input_line++;
+                                $current_pos = ftell($fh);
+                                $data        = fgets($fh);
+                            } else {
+                                // Data found if non emtpy line and not a comment!!
+                                // Rewind to position prior last read and stop lookahead
+                                fseek($fh, $current_pos);
+                                break;
+                            }
+                        }
+                        // now we have either the file pointer at the beginning of
+                        // a new data position or at the end of file causing feof() to return true
+
+                    } else {
+                        // build lines
+                        if (preg_match('/^version:\s(.+)$/', $data, $match)) {
+                            // version statement, set version
+                            $this->version($match[1]);
+                        } elseif (preg_match('/^\w+::?\s.+$/', $data)) {
+                            // normal attribute: add line
+                            $commentmode         = false;
+                            $this->_lines_next[] = trim($data);
+                            $datalines_read++;
+                        } elseif (preg_match('/^\s(.+)$/', $data, $matches)) {
+                            // wrapped data: unwrap if not in comment mode
+                            if (!$commentmode) {
+                                if ($datalines_read == 0) {
+                                    // first line of entry: wrapped data is illegal
+                                    $this->dropError('Net_LDAP2_LDIF error: illegal wrapping at input line '.$this->_input_line, $this->_input_line);
+                                } else {
+                                    $last                = array_pop($this->_lines_next);
+                                    $last                = $last.trim($matches[1]);
+                                    $this->_lines_next[] = $last;
+                                    $datalines_read++;
+                                }
+                            }
+                        } elseif (preg_match('/^#/', $data)) {
+                            // LDIF comments
+                            $commentmode = true;
+                        } elseif (preg_match('/^\s*$/', $data)) {
+                            // empty line but we had no data for this
+                            // entry, so just ignore this line
+                            $commentmode = false;
+                        } else {
+                            $this->dropError('Net_LDAP2_LDIF error: invalid syntax at input line '.$this->_input_line, $this->_input_line);
+                            continue;
+                        }
+
+                    }
+                }
+            }
+        }
+        return $this->_lines_next;
+    }
+
+    /**
+    * Convert an attribute and value to LDIF string representation
+    *
+    * It honors correct encoding of values according to RFC 2849.
+    * Line wrapping will occur at the configured maximum but only if
+    * the value is greater than 40 chars.
+    *
+    * @param string $attr_name  Name of the attribute
+    * @param string $attr_value Value of the attribute
+    *
+    * @access protected
+    * @return string LDIF string for that attribute and value
+    */
+    protected function convertAttribute($attr_name, $attr_value)
+    {
+        // Handle empty attribute or process
+        if (strlen($attr_value) == 0) {
+            $attr_value = " ";
+        } else {
+            $base64 = false;
+            // ASCII-chars that are NOT safe for the
+            // start and for being inside the value.
+            // These are the int values of those chars.
+            $unsafe_init = array(0, 10, 13, 32, 58, 60);
+            $unsafe      = array(0, 10, 13);
+
+            // Test for illegal init char
+            $init_ord = ord(substr($attr_value, 0, 1));
+            if ($init_ord > 127 || in_array($init_ord, $unsafe_init)) {
+                $base64 = true;
+            }
+
+            // Test for illegal content char
+            for ($i = 0; $i < strlen($attr_value); $i++) {
+                $char_ord = ord(substr($attr_value, $i, 1));
+                if ($char_ord > 127 || in_array($char_ord, $unsafe)) {
+                    $base64 = true;
+                }
+            }
+
+            // Test for ending space
+            if (substr($attr_value, -1) == ' ') {
+                $base64 = true;
+            }
+
+            // If converting is needed, do it
+            // Either we have some special chars or a matching "raw" regex
+            if ($base64 || ($this->_options['raw'] && preg_match($this->_options['raw'], $attr_name))) {
+                $attr_name .= ':';
+                $attr_value = base64_encode($attr_value);
+            }
+
+            // Lowercase attr names if requested
+            if ($this->_options['lowercase']) $attr_name = strtolower($attr_name);
+
+            // Handle line wrapping
+            if ($this->_options['wrap'] > 40 && strlen($attr_value) > $this->_options['wrap']) {
+                $attr_value = wordwrap($attr_value, $this->_options['wrap'], PHP_EOL." ", true);
+            }
+        }
+
+        return $attr_name.': '.$attr_value;
+    }
+
+    /**
+    * Convert an entries DN to LDIF string representation
+    *
+    * It honors correct encoding of values according to RFC 2849.
+    *
+    * @param string $dn UTF8-Encoded DN
+    *
+    * @access protected
+    * @return string LDIF string for that DN
+    * @todo I am not sure, if the UTF8 stuff is correctly handled right now
+    */
+    protected function convertDN($dn)
+    {
+        $base64 = false;
+        // ASCII-chars that are NOT safe for the
+        // start and for being inside the dn.
+        // These are the int values of those chars.
+        $unsafe_init = array(0, 10, 13, 32, 58, 60);
+        $unsafe      = array(0, 10, 13);
+
+        // Test for illegal init char
+        $init_ord = ord(substr($dn, 0, 1));
+        if ($init_ord >= 127 || in_array($init_ord, $unsafe_init)) {
+            $base64 = true;
+        }
+
+        // Test for illegal content char
+        for ($i = 0; $i < strlen($dn); $i++) {
+            $char = substr($dn, $i, 1);
+            if (ord($char) >= 127 || in_array($init_ord, $unsafe)) {
+                $base64 = true;
+            }
+        }
+
+        // Test for ending space
+        if (substr($dn, -1) == ' ') {
+            $base64 = true;
+        }
+
+        // if converting is needed, do it
+        return ($base64)? 'dn:: '.base64_encode($dn) : 'dn: '.$dn;
+    }
+
+    /**
+    * Writes an attribute to the filehandle
+    *
+    * @param string       $attr_name   Name of the attribute
+    * @param string|array $attr_values Single attribute value or array with attribute values
+    *
+    * @access protected
+    * @return void
+    */
+    protected function writeAttribute($attr_name, $attr_values)
+    {
+        // write out attribute content
+        if (!is_array($attr_values)) {
+            $attr_values = array($attr_values);
+        }
+        foreach ($attr_values as $attr_val) {
+            $line = $this->convertAttribute($attr_name, $attr_val).PHP_EOL;
+            $this->writeLine($line, 'Net_LDAP2_LDIF error: unable to write attribute '.$attr_name.' of entry '.$this->_entrynum);
+        }
+    }
+
+    /**
+    * Writes a DN to the filehandle
+    *
+    * @param string $dn DN to write
+    *
+    * @access protected
+    * @return void
+    */
+    protected function writeDN($dn)
+    {
+        // prepare DN
+        if ($this->_options['encode'] == 'base64') {
+            $dn = $this->convertDN($dn).PHP_EOL;
+        } elseif ($this->_options['encode'] == 'canonical') {
+            $dn = Net_LDAP2_Util::canonical_dn($dn, array('casefold' => 'none')).PHP_EOL;
+        } else {
+            $dn = $dn.PHP_EOL;
+        }
+        $this->writeLine($dn, 'Net_LDAP2_LDIF error: unable to write DN of entry '.$this->_entrynum);
+    }
+
+    /**
+    * Finishes an LDIF entry
+    *
+    * @access protected
+    * @return void
+    */
+    protected function finishEntry()
+    {
+        $this->writeLine(PHP_EOL, 'Net_LDAP2_LDIF error: unable to close entry '.$this->_entrynum);
+    }
+
+    /**
+    * Just write an arbitary line to the filehandle
+    *
+    * @param string $line  Content to write
+    * @param string $error If error occurs, drop this message
+    *
+    * @access protected
+    * @return true|false
+    */
+    protected function writeLine($line, $error = 'Net_LDAP2_LDIF error: unable to write to filehandle')
+    {
+        if (is_resource($this->handle()) && fwrite($this->handle(), $line, strlen($line)) === false) {
+            $this->dropError($error);
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+    * Optionally raises an error and pushes the error on the error cache
+    *
+    * @param string $msg  Errortext
+    * @param int    $line Line in the LDIF that caused the error
+    *
+    * @access protected
+    * @return void
+    */
+    protected function dropError($msg, $line = null)
+    {
+        $this->_error['error'] = new Net_LDAP2_Error($msg);
+        if ($line !== null) $this->_error['line'] = $line;
+
+        if ($this->_options['onerror'] == 'die') {
+            die($msg.PHP_EOL);
+        } elseif ($this->_options['onerror'] == 'warn') {
+            echo $msg.PHP_EOL;
+        }
+    }
+}
+?>
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php b/plugins/LdapCommon/extlib/Net/LDAP2/RootDSE.php
new file mode 100644 (file)
index 0000000..8dc81fd
--- /dev/null
@@ -0,0 +1,240 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_RootDSE interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Jan Wagner <wagner@netsols.de>
+* @copyright 2009 Jan Wagner
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: RootDSE.php 286718 2009-08-03 07:30:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Includes
+*/
+require_once 'PEAR.php';
+
+/**
+* Getting the rootDSE entry of a LDAP server
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Jan Wagner <wagner@netsols.de>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP22/
+*/
+class Net_LDAP2_RootDSE extends PEAR
+{
+    /**
+    * @access protected
+    * @var object Net_LDAP2_Entry
+    **/
+    protected $_entry;
+
+    /**
+    * Class constructor
+    *
+    * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry object of the RootDSE
+    */
+    protected function __construct(&$entry)
+    {
+        $this->_entry = $entry;
+    }
+
+    /**
+    * Fetches a RootDSE object from an LDAP connection
+    *
+    * @param Net_LDAP2 $ldap  Directory from which the RootDSE should be fetched
+    * @param array     $attrs Array of attributes to search for
+    *
+    * @access static
+    * @return Net_LDAP2_RootDSE|Net_LDAP2_Error
+    */
+    public static function fetch($ldap, $attrs = null)
+    {
+        if (!$ldap instanceof Net_LDAP2) {
+            return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!");
+        }
+
+        if (is_array($attrs) && count($attrs) > 0 ) {
+            $attributes = $attrs;
+        } else {
+            $attributes = array('vendorName',
+                                'vendorVersion',
+                                'namingContexts',
+                                'altServer',
+                                'supportedExtension',
+                                'supportedControl',
+                                'supportedSASLMechanisms',
+                                'supportedLDAPVersion',
+                                'subschemaSubentry' );
+        }
+        $result = $ldap->search('', '(objectClass=*)', array('attributes' => $attributes, 'scope' => 'base'));
+        if (self::isError($result)) {
+            return $result;
+        }
+        $entry = $result->shiftEntry();
+        if (false === $entry) {
+            return PEAR::raiseError('Could not fetch RootDSE entry');
+        }
+        $ret = new Net_LDAP2_RootDSE($entry);
+        return $ret;
+    }
+
+    /**
+    * Gets the requested attribute value
+    *
+    * Same usuage as {@link Net_LDAP2_Entry::getValue()}
+    *
+    * @param string $attr    Attribute name
+    * @param array  $options Array of options
+    *
+    * @access public
+    * @return mixed Net_LDAP2_Error object or attribute values
+    * @see Net_LDAP2_Entry::get_value()
+    */
+    public function getValue($attr = '', $options = '')
+    {
+        return $this->_entry->get_value($attr, $options);
+    }
+
+    /**
+    * Alias function of getValue() for perl-ldap interface
+    *
+    * @see getValue()
+    * @return mixed
+    */
+    public function get_value()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array( &$this, 'getValue' ), $args);
+    }
+
+    /**
+    * Determines if the extension is supported
+    *
+    * @param array $oids Array of oids to check
+    *
+    * @access public
+    * @return boolean
+    */
+    public function supportedExtension($oids)
+    {
+        return $this->checkAttr($oids, 'supportedExtension');
+    }
+
+    /**
+    * Alias function of supportedExtension() for perl-ldap interface
+    *
+    * @see supportedExtension()
+    * @return boolean
+    */
+    public function supported_extension()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array( &$this, 'supportedExtension'), $args);
+    }
+
+    /**
+    * Determines if the version is supported
+    *
+    * @param array $versions Versions to check
+    *
+    * @access public
+    * @return boolean
+    */
+    public function supportedVersion($versions)
+    {
+        return $this->checkAttr($versions, 'supportedLDAPVersion');
+    }
+
+    /**
+    * Alias function of supportedVersion() for perl-ldap interface
+    *
+    * @see supportedVersion()
+    * @return boolean
+    */
+    public function supported_version()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array(&$this, 'supportedVersion'), $args);
+    }
+
+    /**
+    * Determines if the control is supported
+    *
+    * @param array $oids Control oids to check
+    *
+    * @access public
+    * @return boolean
+    */
+    public function supportedControl($oids)
+    {
+        return $this->checkAttr($oids, 'supportedControl');
+    }
+
+    /**
+    * Alias function of supportedControl() for perl-ldap interface
+    *
+    * @see supportedControl()
+    * @return boolean
+    */
+    public function supported_control()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array(&$this, 'supportedControl' ), $args);
+    }
+
+    /**
+    * Determines if the sasl mechanism is supported
+    *
+    * @param array $mechlist SASL mechanisms to check
+    *
+    * @access public
+    * @return boolean
+    */
+    public function supportedSASLMechanism($mechlist)
+    {
+        return $this->checkAttr($mechlist, 'supportedSASLMechanisms');
+    }
+
+    /**
+    * Alias function of supportedSASLMechanism() for perl-ldap interface
+    *
+    * @see supportedSASLMechanism()
+    * @return boolean
+    */
+    public function supported_sasl_mechanism()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array(&$this, 'supportedSASLMechanism'), $args);
+    }
+
+    /**
+    * Checks for existance of value in attribute
+    *
+    * @param array  $values values to check
+    * @param string $attr   attribute name
+    *
+    * @access protected
+    * @return boolean
+    */
+    protected function checkAttr($values, $attr)
+    {
+        if (!is_array($values)) $values = array($values);
+
+        foreach ($values as $value) {
+            if (!@in_array($value, $this->get_value($attr, 'all'))) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
+
+?>
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Schema.php b/plugins/LdapCommon/extlib/Net/LDAP2/Schema.php
new file mode 100644 (file)
index 0000000..b590eab
--- /dev/null
@@ -0,0 +1,516 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_Schema interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Jan Wagner <wagner@netsols.de>
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Jan Wagner, Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: Schema.php 286718 2009-08-03 07:30:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+* @todo see the comment at the end of the file
+*/
+
+/**
+* Includes
+*/
+require_once 'PEAR.php';
+
+/**
+* Syntax definitions
+*
+* Please don't forget to add binary attributes to isBinary() below
+* to support proper value fetching from Net_LDAP2_Entry
+*/
+define('NET_LDAP2_SYNTAX_BOOLEAN',            '1.3.6.1.4.1.1466.115.121.1.7');
+define('NET_LDAP2_SYNTAX_DIRECTORY_STRING',   '1.3.6.1.4.1.1466.115.121.1.15');
+define('NET_LDAP2_SYNTAX_DISTINGUISHED_NAME', '1.3.6.1.4.1.1466.115.121.1.12');
+define('NET_LDAP2_SYNTAX_INTEGER',            '1.3.6.1.4.1.1466.115.121.1.27');
+define('NET_LDAP2_SYNTAX_JPEG',               '1.3.6.1.4.1.1466.115.121.1.28');
+define('NET_LDAP2_SYNTAX_NUMERIC_STRING',     '1.3.6.1.4.1.1466.115.121.1.36');
+define('NET_LDAP2_SYNTAX_OID',                '1.3.6.1.4.1.1466.115.121.1.38');
+define('NET_LDAP2_SYNTAX_OCTET_STRING',       '1.3.6.1.4.1.1466.115.121.1.40');
+
+/**
+* Load an LDAP Schema and provide information
+*
+* This class takes a Subschema entry, parses this information
+* and makes it available in an array. Most of the code has been
+* inspired by perl-ldap( http://perl-ldap.sourceforge.net).
+* You will find portions of their implementation in here.
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Jan Wagner <wagner@netsols.de>
+* @author   Benedikt Hallinger <beni@php.net>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP22/
+*/
+class Net_LDAP2_Schema extends PEAR
+{
+    /**
+    * Map of entry types to ldap attributes of subschema entry
+    *
+    * @access public
+    * @var array
+    */
+    public $types = array(
+            'attribute'        => 'attributeTypes',
+            'ditcontentrule'   => 'dITContentRules',
+            'ditstructurerule' => 'dITStructureRules',
+            'matchingrule'     => 'matchingRules',
+            'matchingruleuse'  => 'matchingRuleUse',
+            'nameform'         => 'nameForms',
+            'objectclass'      => 'objectClasses',
+            'syntax'           => 'ldapSyntaxes'
+        );
+
+    /**
+    * Array of entries belonging to this type
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_attributeTypes    = array();
+    protected $_matchingRules     = array();
+    protected $_matchingRuleUse   = array();
+    protected $_ldapSyntaxes      = array();
+    protected $_objectClasses     = array();
+    protected $_dITContentRules   = array();
+    protected $_dITStructureRules = array();
+    protected $_nameForms         = array();
+
+
+    /**
+    * hash of all fetched oids
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_oids = array();
+
+    /**
+    * Tells if the schema is initialized
+    *
+    * @access protected
+    * @var boolean
+    * @see parse(), get()
+    */
+    protected $_initialized = false;
+
+
+    /**
+    * Constructor of the class
+    *
+    * @access protected
+    */
+    protected function __construct()
+    {
+        $this->PEAR('Net_LDAP2_Error'); // default error class
+    }
+
+    /**
+    * Fetch the Schema from an LDAP connection
+    *
+    * @param Net_LDAP2 $ldap LDAP connection
+    * @param string    $dn   (optional) Subschema entry dn
+    *
+    * @access public
+    * @return Net_LDAP2_Schema|NET_LDAP2_Error
+    */
+    public function fetch($ldap, $dn = null)
+    {
+        if (!$ldap instanceof Net_LDAP2) {
+            return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!");
+        }
+
+        $schema_o = new Net_LDAP2_Schema();
+
+        if (is_null($dn)) {
+            // get the subschema entry via root dse
+            $dse = $ldap->rootDSE(array('subschemaSubentry'));
+            if (false == Net_LDAP2::isError($dse)) {
+                $base = $dse->getValue('subschemaSubentry', 'single');
+                if (!Net_LDAP2::isError($base)) {
+                    $dn = $base;
+                }
+            }
+        }
+
+        // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that incorrectly
+        // call this entry subSchemaSubentry instead of subschemaSubentry.
+        // Note the correct case/spelling as per RFC 2251.
+        if (is_null($dn)) {
+            // get the subschema entry via root dse
+            $dse = $ldap->rootDSE(array('subSchemaSubentry'));
+            if (false == Net_LDAP2::isError($dse)) {
+                $base = $dse->getValue('subSchemaSubentry', 'single');
+                if (!Net_LDAP2::isError($base)) {
+                    $dn = $base;
+                }
+            }
+        }
+
+        // Final fallback case where there is no subschemaSubentry attribute
+        // in the root DSE (this is a bug for an LDAP v3 server so report this
+        // to your LDAP vendor if you get this far).
+        if (is_null($dn)) {
+            $dn = 'cn=Subschema';
+        }
+
+        // fetch the subschema entry
+        $result = $ldap->search($dn, '(objectClass=*)',
+                                array('attributes' => array_values($schema_o->types),
+                                        'scope' => 'base'));
+        if (Net_LDAP2::isError($result)) {
+            return $result;
+        }
+
+        $entry = $result->shiftEntry();
+        if (!$entry instanceof Net_LDAP2_Entry) {
+            return PEAR::raiseError('Could not fetch Subschema entry');
+        }
+
+        $schema_o->parse($entry);
+        return $schema_o;
+    }
+
+    /**
+    * Return a hash of entries for the given type
+    *
+    * Returns a hash of entry for th givene type. Types may be:
+    * objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules,
+    * matchingruleuses, nameforms, syntaxes
+    *
+    * @param string $type Type to fetch
+    *
+    * @access public
+    * @return array|Net_LDAP2_Error Array or Net_LDAP2_Error
+    */
+    public function &getAll($type)
+    {
+        $map = array('objectclasses'     => &$this->_objectClasses,
+                     'attributes'        => &$this->_attributeTypes,
+                     'ditcontentrules'   => &$this->_dITContentRules,
+                     'ditstructurerules' => &$this->_dITStructureRules,
+                     'matchingrules'     => &$this->_matchingRules,
+                     'matchingruleuses'  => &$this->_matchingRuleUse,
+                     'nameforms'         => &$this->_nameForms,
+                     'syntaxes'          => &$this->_ldapSyntaxes );
+
+        $key = strtolower($type);
+        $ret = ((key_exists($key, $map)) ? $map[$key] : PEAR::raiseError("Unknown type $type"));
+        return $ret;
+    }
+
+    /**
+    * Return a specific entry
+    *
+    * @param string $type Type of name
+    * @param string $name Name or OID to fetch
+    *
+    * @access public
+    * @return mixed Entry or Net_LDAP2_Error
+    */
+    public function &get($type, $name)
+    {
+        if ($this->_initialized) {
+            $type = strtolower($type);
+            if (false == key_exists($type, $this->types)) {
+                return PEAR::raiseError("No such type $type");
+            }
+
+            $name     = strtolower($name);
+            $type_var = &$this->{'_' . $this->types[$type]};
+
+            if (key_exists($name, $type_var)) {
+                return $type_var[$name];
+            } elseif (key_exists($name, $this->_oids) && $this->_oids[$name]['type'] == $type) {
+                return $this->_oids[$name];
+            } else {
+                return PEAR::raiseError("Could not find $type $name");
+            }
+        } else {
+            $return = null;
+            return $return;
+        }
+    }
+
+
+    /**
+    * Fetches attributes that MAY be present in the given objectclass
+    *
+    * @param string $oc Name or OID of objectclass
+    *
+    * @access public
+    * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error
+    */
+    public function may($oc)
+    {
+        return $this->_getAttr($oc, 'may');
+    }
+
+    /**
+    * Fetches attributes that MUST be present in the given objectclass
+    *
+    * @param string $oc Name or OID of objectclass
+    *
+    * @access public
+    * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error
+    */
+    public function must($oc)
+    {
+        return $this->_getAttr($oc, 'must');
+    }
+
+    /**
+    * Fetches the given attribute from the given objectclass
+    *
+    * @param string $oc   Name or OID of objectclass
+    * @param string $attr Name of attribute to fetch
+    *
+    * @access protected
+    * @return array|Net_LDAP2_Error The attribute or Net_LDAP2_Error
+    */
+    protected function _getAttr($oc, $attr)
+    {
+        $oc = strtolower($oc);
+        if (key_exists($oc, $this->_objectClasses) && key_exists($attr, $this->_objectClasses[$oc])) {
+            return $this->_objectClasses[$oc][$attr];
+        } elseif (key_exists($oc, $this->_oids) &&
+                $this->_oids[$oc]['type'] == 'objectclass' &&
+                key_exists($attr, $this->_oids[$oc])) {
+            return $this->_oids[$oc][$attr];
+        } else {
+            return PEAR::raiseError("Could not find $attr attributes for $oc ");
+        }
+    }
+
+    /**
+    * Returns the name(s) of the immediate superclass(es)
+    *
+    * @param string $oc Name or OID of objectclass
+    *
+    * @access public
+    * @return array|Net_LDAP2_Error  Array of names or Net_LDAP2_Error
+    */
+    public function superclass($oc)
+    {
+        $o = $this->get('objectclass', $oc);
+        if (Net_LDAP2::isError($o)) {
+            return $o;
+        }
+        return (key_exists('sup', $o) ? $o['sup'] : array());
+    }
+
+    /**
+    * Parses the schema of the given Subschema entry
+    *
+    * @param Net_LDAP2_Entry &$entry Subschema entry
+    *
+    * @access public
+    * @return void
+    */
+    public function parse(&$entry)
+    {
+        foreach ($this->types as $type => $attr) {
+            // initialize map type to entry
+            $type_var          = '_' . $attr;
+            $this->{$type_var} = array();
+
+            // get values for this type
+            if ($entry->exists($attr)) {
+                $values = $entry->getValue($attr);
+                if (is_array($values)) {
+                    foreach ($values as $value) {
+
+                        unset($schema_entry); // this was a real mess without it
+
+                        // get the schema entry
+                        $schema_entry = $this->_parse_entry($value);
+
+                        // set the type
+                        $schema_entry['type'] = $type;
+
+                        // save a ref in $_oids
+                        $this->_oids[$schema_entry['oid']] = &$schema_entry;
+
+                        // save refs for all names in type map
+                        $names = $schema_entry['aliases'];
+                        array_push($names, $schema_entry['name']);
+                        foreach ($names as $name) {
+                            $this->{$type_var}[strtolower($name)] = &$schema_entry;
+                        }
+                    }
+                }
+            }
+        }
+        $this->_initialized = true;
+    }
+
+    /**
+    * Parses an attribute value into a schema entry
+    *
+    * @param string $value Attribute value
+    *
+    * @access protected
+    * @return array|false Schema entry array or false
+    */
+    protected function &_parse_entry($value)
+    {
+        // tokens that have no value associated
+        $noValue = array('single-value',
+                         'obsolete',
+                         'collective',
+                         'no-user-modification',
+                         'abstract',
+                         'structural',
+                         'auxiliary');
+
+        // tokens that can have multiple values
+        $multiValue = array('must', 'may', 'sup');
+
+        $schema_entry = array('aliases' => array()); // initilization
+
+        $tokens = $this->_tokenize($value); // get an array of tokens
+
+        // remove surrounding brackets
+        if ($tokens[0] == '(') array_shift($tokens);
+        if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); // -1 doesnt work on arrays :-(
+
+        $schema_entry['oid'] = array_shift($tokens); // first token is the oid
+
+        // cycle over the tokens until none are left
+        while (count($tokens) > 0) {
+            $token = strtolower(array_shift($tokens));
+            if (in_array($token, $noValue)) {
+                $schema_entry[$token] = 1; // single value token
+            } else {
+                // this one follows a string or a list if it is multivalued
+                if (($schema_entry[$token] = array_shift($tokens)) == '(') {
+                    // this creates the list of values and cycles through the tokens
+                    // until the end of the list is reached ')'
+                    $schema_entry[$token] = array();
+                    while ($tmp = array_shift($tokens)) {
+                        if ($tmp == ')') break;
+                        if ($tmp != '$') array_push($schema_entry[$token], $tmp);
+                    }
+                }
+                // create a array if the value should be multivalued but was not
+                if (in_array($token, $multiValue) && !is_array($schema_entry[$token])) {
+                    $schema_entry[$token] = array($schema_entry[$token]);
+                }
+            }
+        }
+        // get max length from syntax
+        if (key_exists('syntax', $schema_entry)) {
+            if (preg_match('/{(\d+)}/', $schema_entry['syntax'], $matches)) {
+                $schema_entry['max_length'] = $matches[1];
+            }
+        }
+        // force a name
+        if (empty($schema_entry['name'])) {
+            $schema_entry['name'] = $schema_entry['oid'];
+        }
+        // make one name the default and put the other ones into aliases
+        if (is_array($schema_entry['name'])) {
+            $aliases                 = $schema_entry['name'];
+            $schema_entry['name']    = array_shift($aliases);
+            $schema_entry['aliases'] = $aliases;
+        }
+        return $schema_entry;
+    }
+
+    /**
+    * Tokenizes the given value into an array of tokens
+    *
+    * @param string $value String to parse
+    *
+    * @access protected
+    * @return array Array of tokens
+    */
+    protected function _tokenize($value)
+    {
+        $tokens  = array();       // array of tokens
+        $matches = array();       // matches[0] full pattern match, [1,2,3] subpatterns
+
+        // this one is taken from perl-ldap, modified for php
+        $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x";
+
+        /**
+         * This one matches one big pattern wherin only one of the three subpatterns matched
+         * We are interested in the subpatterns that matched. If it matched its value will be
+         * non-empty and so it is a token. Tokens may be round brackets, a string, or a string
+         * enclosed by '
+         */
+        preg_match_all($pattern, $value, $matches);
+
+        for ($i = 0; $i < count($matches[0]); $i++) {     // number of tokens (full pattern match)
+            for ($j = 1; $j < 4; $j++) {                  // each subpattern
+                if (null != trim($matches[$j][$i])) {     // pattern match in this subpattern
+                    $tokens[$i] = trim($matches[$j][$i]); // this is the token
+                }
+            }
+        }
+        return $tokens;
+    }
+
+    /**
+    * Returns wether a attribute syntax is binary or not
+    *
+    * This method gets used by Net_LDAP2_Entry to decide which
+    * PHP function needs to be used to fetch the value in the
+    * proper format (e.g. binary or string)
+    *
+    * @param string $attribute The name of the attribute (eg.: 'sn')
+    *
+    * @access public
+    * @return boolean
+    */
+    public function isBinary($attribute)
+    {
+        $return = false; // default to false
+
+        // This list contains all syntax that should be treaten as
+        // containing binary values
+        // The Syntax Definitons go into constants at the top of this page
+        $syntax_binary = array(
+                           NET_LDAP2_SYNTAX_OCTET_STRING,
+                           NET_LDAP2_SYNTAX_JPEG
+                         );
+
+        // Check Syntax
+        $attr_s = $this->get('attribute', $attribute);
+        if (Net_LDAP2::isError($attr_s)) {
+            // Attribute not found in schema
+            $return = false; // consider attr not binary
+        } elseif (isset($attr_s['syntax']) && in_array($attr_s['syntax'], $syntax_binary)) {
+            // Syntax is defined as binary in schema
+            $return = true;
+        } else {
+            // Syntax not defined as binary, or not found
+            // if attribute is a subtype, check superior attribute syntaxes
+            if (isset($attr_s['sup'])) {
+                foreach ($attr_s['sup'] as $superattr) {
+                    $return = $this->isBinary($superattr);
+                    if ($return) {
+                        break; // stop checking parents since we are binary
+                    }
+                }
+            }
+        }
+
+        return $return;
+    }
+
+    // [TODO] add method that allows us to see to which objectclasses a certain attribute belongs to
+    // it should return the result structured, e.g. sorted in "may" and "must". Optionally it should
+    // be able to return it just "flat", e.g. array_merge()d.
+    // We could use get_all() to achieve this easily, i think
+}
+?>
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/SchemaCache.interface.php b/plugins/LdapCommon/extlib/Net/LDAP2/SchemaCache.interface.php
new file mode 100644 (file)
index 0000000..e0c3094
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_SchemaCache interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: SchemaCache.interface.php 286718 2009-08-03 07:30:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Interface describing a custom schema cache object
+*
+* To implement a custom schema cache, one must implement this interface and
+* pass the instanciated object to Net_LDAP2s registerSchemaCache() method.
+*/
+interface Net_LDAP2_SchemaCache
+{
+    /**
+    * Return the schema object from the cache
+    *
+    * Net_LDAP2 will consider anything returned invalid, except
+    * a valid Net_LDAP2_Schema object.
+    * In case you return a Net_LDAP2_Error, this error will be routed
+    * to the return of the $ldap->schema() call.
+    * If you return something else, Net_LDAP2 will
+    * fetch a fresh Schema object from the LDAP server.
+    *
+    * You may want to implement a cache aging mechanism here too.
+    *
+    * @return Net_LDAP2_Schema|Net_LDAP2_Error|false
+    */
+    public function loadSchema();
+
+    /**
+    * Store a schema object in the cache
+    *
+    * This method will be called, if Net_LDAP2 has fetched a fresh
+    * schema object from LDAP and wants to init or refresh the cache.
+    *
+    * In case of errors you may return a Net_LDAP2_Error which will
+    * be routet to the client.
+    * Note that doing this prevents, that the schema object fetched from LDAP
+    * will be given back to the client, so only return errors if storing
+    * of the cache is something crucial (e.g. for doing something else with it).
+    * Normaly you dont want to give back errors in which case Net_LDAP2 needs to
+    * fetch the schema once per script run and instead use the error
+    * returned from loadSchema().
+    *
+    * @return true|Net_LDAP2_Error
+    */
+    public function storeSchema($schema);
+}
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Search.php b/plugins/LdapCommon/extlib/Net/LDAP2/Search.php
new file mode 100644 (file)
index 0000000..de4fde1
--- /dev/null
@@ -0,0 +1,614 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_Search interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Tarjej Huse <tarjei@bergfald.no>
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Tarjej Huse, Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: Search.php 286718 2009-08-03 07:30:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Includes
+*/
+require_once 'PEAR.php';
+
+/**
+* Result set of an LDAP search
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Tarjej Huse <tarjei@bergfald.no>
+* @author   Benedikt Hallinger <beni@php.net>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP22/
+*/
+class Net_LDAP2_Search extends PEAR implements Iterator
+{
+    /**
+    * Search result identifier
+    *
+    * @access protected
+    * @var resource
+    */
+    protected $_search;
+
+    /**
+    * LDAP resource link
+    *
+    * @access protected
+    * @var resource
+    */
+    protected $_link;
+
+    /**
+    * Net_LDAP2 object
+    *
+    * A reference of the Net_LDAP2 object for passing to Net_LDAP2_Entry
+    *
+    * @access protected
+    * @var object Net_LDAP2
+    */
+    protected $_ldap;
+
+    /**
+    * Result entry identifier
+    *
+    * @access protected
+    * @var resource
+    */
+    protected $_entry = null;
+
+    /**
+    * The errorcode the search got
+    *
+    * Some errorcodes might be of interest, but might not be best handled as errors.
+    * examples: 4 - LDAP_SIZELIMIT_EXCEEDED - indicates a huge search.
+    *               Incomplete results are returned. If you just want to check if there's anything in the search.
+    *               than this is a point to handle.
+    *           32 - no such object - search here returns a count of 0.
+    *
+    * @access protected
+    * @var int
+    */
+    protected $_errorCode = 0; // if not set - sucess!
+
+    /**
+    * Cache for all entries already fetched from iterator interface
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_iteratorCache = array();
+
+    /**
+    * What attributes we searched for
+    *
+    * The $attributes array contains the names of the searched attributes and gets
+    * passed from $Net_LDAP2->search() so the Net_LDAP2_Search object can tell
+    * what attributes was searched for ({@link searchedAttrs())
+    *
+    * This variable gets set from the constructor and returned
+    * from {@link searchedAttrs()}
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_searchedAttrs = array();
+
+    /**
+    * Cache variable for storing entries fetched internally
+    *
+    * This currently is only used by {@link pop_entry()}
+    *
+    * @access protected
+    * @var array
+    */
+    protected $_entry_cache = false;
+
+    /**
+    * Constructor
+    *
+    * @param resource           &$search    Search result identifier
+    * @param Net_LDAP2|resource &$ldap      Net_LDAP2 object or just a LDAP-Link resource
+    * @param array              $attributes (optional) Array with searched attribute names. (see {@link $_searchedAttrs})
+    *
+    * @access public
+    */
+    public function __construct(&$search, &$ldap, $attributes = array())
+    {
+        $this->PEAR('Net_LDAP2_Error');
+
+        $this->setSearch($search);
+
+        if ($ldap instanceof Net_LDAP2) {
+            $this->_ldap =& $ldap;
+            $this->setLink($this->_ldap->getLink());
+        } else {
+            $this->setLink($ldap);
+        }
+
+        $this->_errorCode = @ldap_errno($this->_link);
+
+        if (is_array($attributes) && !empty($attributes)) {
+            $this->_searchedAttrs = $attributes;
+        }
+    }
+
+    /**
+    * Returns an array of entry objects
+    *
+    * @return array Array of entry objects.
+    */
+    public function entries()
+    {
+        $entries = array();
+
+        while ($entry = $this->shiftEntry()) {
+            $entries[] = $entry;
+        }
+
+        return $entries;
+    }
+
+    /**
+    * Get the next entry in the searchresult.
+    *
+    * This will return a valid Net_LDAP2_Entry object or false, so
+    * you can use this method to easily iterate over the entries inside
+    * a while loop.
+    *
+    * @return Net_LDAP2_Entry|false  Reference to Net_LDAP2_Entry object or false
+    */
+    public function &shiftEntry()
+    {
+        if ($this->count() == 0 ) {
+            $false = false;
+            return $false;
+        }
+
+        if (is_null($this->_entry)) {
+            $this->_entry = @ldap_first_entry($this->_link, $this->_search);
+            $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
+            if ($entry instanceof Net_LDAP2_Error) $entry = false;
+        } else {
+            if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) {
+                $false = false;
+                return $false;
+            }
+            $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry);
+            if ($entry instanceof Net_LDAP2_Error) $entry = false;
+        }
+        return $entry;
+    }
+
+    /**
+    * Alias function of shiftEntry() for perl-ldap interface
+    *
+    * @see shiftEntry()
+    * @return Net_LDAP2_Entry|false
+    */
+    public function shift_entry()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array( &$this, 'shiftEntry' ), $args);
+    }
+
+    /**
+    * Retrieve the next entry in the searchresult, but starting from last entry
+    *
+    * This is the opposite to {@link shiftEntry()} and is also very useful
+    * to be used inside a while loop.
+    *
+    * @return Net_LDAP2_Entry|false
+    */
+    public function popEntry()
+    {
+        if (false === $this->_entry_cache) {
+            // fetch entries into cache if not done so far
+            $this->_entry_cache = $this->entries();
+        }
+
+        $return = array_pop($this->_entry_cache);
+        return (null === $return)? false : $return;
+    }
+
+    /**
+    * Alias function of popEntry() for perl-ldap interface
+    *
+    * @see popEntry()
+    * @return Net_LDAP2_Entry|false
+    */
+    public function pop_entry()
+    {
+        $args = func_get_args();
+        return call_user_func_array(array( &$this, 'popEntry' ), $args);
+    }
+
+    /**
+    * Return entries sorted as array
+    *
+    * This returns a array with sorted entries and the values.
+    * Sorting is done with PHPs {@link array_multisort()}.
+    * This method relies on {@link as_struct()} to fetch the raw data of the entries.
+    *
+    * Please note that attribute names are case sensitive!
+    *
+    * Usage example:
+    * <code>
+    *   // to sort entries first by location, then by surename, but descending:
+    *   $entries = $search->sorted_as_struct(array('locality','sn'), SORT_DESC);
+    * </code>
+    *
+    * @param array $attrs Array of attribute names to sort; order from left to right.
+    * @param int   $order Ordering direction, either constant SORT_ASC or SORT_DESC
+    *
+    * @return array|Net_LDAP2_Error   Array with sorted entries or error
+    * @todo what about server side sorting as specified in http://www.ietf.org/rfc/rfc2891.txt?
+    */
+    public function sorted_as_struct($attrs = array('cn'), $order = SORT_ASC)
+    {
+        /*
+        * Old Code, suitable and fast for single valued sorting
+        * This code should be used if we know that single valued sorting is desired,
+        * but we need some method to get that knowledge...
+        */
+        /*
+        $attrs = array_reverse($attrs);
+        foreach ($attrs as $attribute) {
+            if (!ldap_sort($this->_link, $this->_search, $attribute)){
+                $this->raiseError("Sorting failed for Attribute " . $attribute);
+            }
+        }
+
+        $results = ldap_get_entries($this->_link, $this->_search);
+
+        unset($results['count']); //for tidier output
+        if ($order) {
+            return array_reverse($results);
+        } else {
+            return $results;
+        }*/
+
+        /*
+        * New code: complete "client side" sorting
+        */
+        // first some parameterchecks
+        if (!is_array($attrs)) {
+            return PEAR::raiseError("Sorting failed: Parameterlist must be an array!");
+        }
+        if ($order != SORT_ASC && $order != SORT_DESC) {
+            return PEAR::raiseError("Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)");
+        }
+
+        // fetch the entries data
+        $entries = $this->as_struct();
+
+        // now sort each entries attribute values
+        // this is neccessary because later we can only sort by one value,
+        // so we need the highest or lowest attribute now, depending on the
+        // selected ordering for that specific attribute
+        foreach ($entries as $dn => $entry) {
+            foreach ($entry as $attr_name => $attr_values) {
+                sort($entries[$dn][$attr_name]);
+                if ($order == SORT_DESC) {
+                    array_reverse($entries[$dn][$attr_name]);
+                }
+            }
+        }
+
+        // reformat entrys array for later use with array_multisort()
+        $to_sort = array(); // <- will be a numeric array similar to ldap_get_entries
+        foreach ($entries as $dn => $entry_attr) {
+            $row       = array();
+            $row['dn'] = $dn;
+            foreach ($entry_attr as $attr_name => $attr_values) {
+                $row[$attr_name] = $attr_values;
+            }
+            $to_sort[] = $row;
+        }
+
+        // Build columns for array_multisort()
+        // each requested attribute is one row
+        $columns = array();
+        foreach ($attrs as $attr_name) {
+            foreach ($to_sort as $key => $row) {
+                $columns[$attr_name][$key] =& $to_sort[$key][$attr_name][0];
+            }
+        }
+
+        // sort the colums with array_multisort, if there is something
+        // to sort and if we have requested sort columns
+        if (!empty($to_sort) && !empty($columns)) {
+            $sort_params = '';
+            foreach ($attrs as $attr_name) {
+                $sort_params .= '$columns[\''.$attr_name.'\'], '.$order.', ';
+            }
+            eval("array_multisort($sort_params \$to_sort);"); // perform sorting
+        }
+
+        return $to_sort;
+    }
+
+    /**
+    * Return entries sorted as objects
+    *
+    * This returns a array with sorted Net_LDAP2_Entry objects.
+    * The sorting is actually done with {@link sorted_as_struct()}.
+    *
+    * Please note that attribute names are case sensitive!
+    * Also note, that it is (depending on server capabilitys) possible to let
+    * the server sort your results. This happens through search controls
+    * and is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt}
+    *
+    * Usage example:
+    * <code>
+    *   // to sort entries first by location, then by surename, but descending:
+    *   $entries = $search->sorted(array('locality','sn'), SORT_DESC);
+    * </code>
+    *
+    * @param array $attrs Array of sort attributes to sort; order from left to right.
+    * @param int   $order Ordering direction, either constant SORT_ASC or SORT_DESC
+    *
+    * @return array|Net_LDAP2_Error   Array with sorted Net_LDAP2_Entries or error
+    * @todo Entry object construction could be faster. Maybe we could use one of the factorys instead of fetching the entry again
+    */
+    public function sorted($attrs = array('cn'), $order = SORT_ASC)
+    {
+        $return = array();
+        $sorted = $this->sorted_as_struct($attrs, $order);
+        if (PEAR::isError($sorted)) {
+            return $sorted;
+        }
+        foreach ($sorted as $key => $row) {
+            $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttrs());
+            if (!PEAR::isError($entry)) {
+                array_push($return, $entry);
+            } else {
+                return $entry;
+            }
+        }
+        return $return;
+    }
+
+    /**
+    * Return entries as array
+    *
+    * This method returns the entries and the selected attributes values as
+    * array.
+    * The first array level contains all found entries where the keys are the
+    * DNs of the entries. The second level arrays contian the entries attributes
+    * such that the keys is the lowercased name of the attribute and the values
+    * are stored in another indexed array. Note that the attribute values are stored
+    * in an array even if there is no or just one value.
+    *
+    * The array has the following structure:
+    * <code>
+    * $return = array(
+    *           'cn=foo,dc=example,dc=com' => array(
+    *                                                'sn'       => array('foo'),
+    *                                                'multival' => array('val1', 'val2', 'valN')
+    *                                             )
+    *           'cn=bar,dc=example,dc=com' => array(
+    *                                                'sn'       => array('bar'),
+    *                                                'multival' => array('val1', 'valN')
+    *                                             )
+    *           )
+    * </code>
+    *
+    * @return array      associative result array as described above
+    */
+    public function as_struct()
+    {
+        $return  = array();
+        $entries = $this->entries();
+        foreach ($entries as $entry) {
+            $attrs            = array();
+            $entry_attributes = $entry->attributes();
+            foreach ($entry_attributes as $attr_name) {
+                $attr_values = $entry->getValue($attr_name, 'all');
+                if (!is_array($attr_values)) {
+                    $attr_values = array($attr_values);
+                }
+                $attrs[$attr_name] = $attr_values;
+            }
+            $return[$entry->dn()] = $attrs;
+        }
+        return $return;
+    }
+
+    /**
+    * Set the search objects resource link
+    *
+    * @param resource &$search Search result identifier
+    *
+    * @access public
+    * @return void
+    */
+    public function setSearch(&$search)
+    {
+        $this->_search = $search;
+    }
+
+    /**
+    * Set the ldap ressource link
+    *
+    * @param resource &$link Link identifier
+    *
+    * @access public
+    * @return void
+    */
+    public function setLink(&$link)
+    {
+        $this->_link = $link;
+    }
+
+    /**
+    * Returns the number of entries in the searchresult
+    *
+    * @return int Number of entries in search.
+    */
+    public function count()
+    {
+        // this catches the situation where OL returned errno 32 = no such object!
+        if (!$this->_search) {
+            return 0;
+        }
+        return @ldap_count_entries($this->_link, $this->_search);
+    }
+
+    /**
+    * Get the errorcode the object got in its search.
+    *
+    * @return int The ldap error number.
+    */
+    public function getErrorCode()
+    {
+        return $this->_errorCode;
+    }
+
+    /**
+    * Destructor
+    *
+    * @access protected
+    */
+    public function _Net_LDAP2_Search()
+    {
+        @ldap_free_result($this->_search);
+    }
+
+    /**
+    * Closes search result
+    *
+    * @return void
+    */
+    public function done()
+    {
+        $this->_Net_LDAP2_Search();
+    }
+
+    /**
+    * Return the attribute names this search selected
+    *
+    * @return array
+    * @see $_searchedAttrs
+    * @access protected
+    */
+    protected function searchedAttrs()
+    {
+        return $this->_searchedAttrs;
+    }
+
+    /**
+    * Tells if this search exceeds a sizelimit
+    *
+    * @return boolean
+    */
+    public function sizeLimitExceeded()
+    {
+        return ($this->getErrorCode() == 4);
+    }
+
+
+    /*
+    * SPL Iterator interface methods.
+    * This interface allows to use Net_LDAP2_Search
+    * objects directly inside a foreach loop!
+    */
+    /**
+    * SPL Iterator interface: Return the current element.
+    *
+    * The SPL Iterator interface allows you to fetch entries inside
+    * a foreach() loop: <code>foreach ($search as $dn => $entry) { ...</code>
+    *
+    * Of course, you may call {@link current()}, {@link key()}, {@link next()},
+    * {@link rewind()} and {@link valid()} yourself.
+    *
+    * If the search throwed an error, it returns false.
+    * False is also returned, if the end is reached
+    * In case no call to next() was made, we will issue one,
+    * thus returning the first entry.
+    *
+    * @return Net_LDAP2_Entry|false
+    */
+    public function current()
+    {
+        if (count($this->_iteratorCache) == 0) {
+            $this->next();
+            reset($this->_iteratorCache);
+        }
+        $entry = current($this->_iteratorCache);
+        return ($entry instanceof Net_LDAP2_Entry)? $entry : false;
+    }
+
+    /**
+    * SPL Iterator interface: Return the identifying key (DN) of the current entry.
+    *
+    * @see current()
+    * @return string|false DN of the current entry; false in case no entry is returned by current()
+    */
+    public function key()
+    {
+        $entry = $this->current();
+        return ($entry instanceof Net_LDAP2_Entry)? $entry->dn() :false;
+    }
+
+    /**
+    * SPL Iterator interface: Move forward to next entry.
+    *
+    * After a call to {@link next()}, {@link current()} will return
+    * the next entry in the result set.
+    *
+    * @see current()
+    * @return void
+    */
+    public function next()
+    {
+        // fetch next entry.
+        // if we have no entrys anymore, we add false (which is
+        // returned by shiftEntry()) so current() will complain.
+        if (count($this->_iteratorCache) - 1 <= $this->count()) {
+            $this->_iteratorCache[] = $this->shiftEntry();
+        }
+
+        // move on array pointer to current element.
+        // even if we have added all entries, this will
+        // ensure proper operation in case we rewind()
+        next($this->_iteratorCache);
+    }
+
+    /**
+    * SPL Iterator interface:  Check if there is a current element after calls to {@link rewind()} or {@link next()}.
+    *
+    * Used to check if we've iterated to the end of the collection.
+    *
+    * @see current()
+    * @return boolean FALSE if there's nothing more to iterate over
+    */
+    public function valid()
+    {
+        return ($this->current() instanceof Net_LDAP2_Entry);
+    }
+
+    /**
+    * SPL Iterator interface: Rewind the Iterator to the first element.
+    *
+    * After rewinding, {@link current()} will return the first entry in the result set.
+    *
+    * @see current()
+    * @return void
+    */
+    public function rewind()
+    {
+        reset($this->_iteratorCache);
+    }
+}
+
+?>
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/SimpleFileSchemaCache.php b/plugins/LdapCommon/extlib/Net/LDAP2/SimpleFileSchemaCache.php
new file mode 100644 (file)
index 0000000..8019654
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the example simple file based Schema Caching class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: SimpleFileSchemaCache.php 286718 2009-08-03 07:30:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* A simple file based schema cacher with cache aging.
+*
+* Once the cache is too old, the loadSchema() method will return false, so
+* Net_LDAP2 will fetch a fresh object from the LDAP server that will
+* overwrite the current (outdated) old cache.
+*/
+class Net_LDAP2_SimpleFileSchemaCache implements Net_LDAP2_SchemaCache
+{
+    /**
+    * Internal config of this cache
+    *
+    * @see Net_LDAP2_SimpleFileSchemaCache()
+    * @var array
+    */
+    protected $config = array(
+        'path'    => '/tmp/Net_LDAP_Schema.cache',
+        'max_age' => 1200
+    );
+
+    /**
+    * Initialize the simple cache
+    *
+    * Config is as following:
+    *  path     Complete path to the cache file.
+    *  max_age  Maximum age of cache in seconds, 0 means "endlessly".
+    *
+    * @param array $cfg Config array
+    */
+    public function Net_LDAP2_SimpleFileSchemaCache($cfg)
+    {
+       foreach ($cfg as $key => $value) {
+                       if (array_key_exists($key, $this->config)) {
+                               if (gettype($this->config[$key]) != gettype($value)) {
+                                       $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key does not match type ".gettype($this->config[$key])."!");
+                               }
+                               $this->config[$key] = $value;
+                       } else {
+                               $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key is not defined!");
+                       }
+               }
+    }
+
+    /**
+    * Return the schema object from the cache
+    *
+    * If file is existent and cache has not expired yet,
+    * then the cache is deserialized and returned.
+    *
+    * @return Net_LDAP2_Schema|Net_LDAP2_Error|false
+    */
+    public function loadSchema()
+    {
+         $return = false; // Net_LDAP2 will load schema from LDAP
+         if (file_exists($this->config['path'])) {
+             $cache_maxage = filemtime($this->config['path']) + $this->config['max_age'];
+             if (time() <= $cache_maxage || $this->config['max_age'] == 0) {
+                 $return = unserialize(file_get_contents($this->config['path']));
+             }
+         }
+         return $return;
+    }
+
+    /**
+    * Store a schema object in the cache
+    *
+    * This method will be called, if Net_LDAP2 has fetched a fresh
+    * schema object from LDAP and wants to init or refresh the cache.
+    *
+    * To invalidate the cache and cause Net_LDAP2 to refresh the cache,
+    * you can call this method with null or false as value.
+    * The next call to $ldap->schema() will then refresh the caches object.
+    *
+    * @param mixed $schema The object that should be cached
+    * @return true|Net_LDAP2_Error|false
+    */
+    public function storeSchema($schema) {
+        file_put_contents($this->config['path'], serialize($schema));
+        return true;
+    }
+}
diff --git a/plugins/LdapCommon/extlib/Net/LDAP2/Util.php b/plugins/LdapCommon/extlib/Net/LDAP2/Util.php
new file mode 100644 (file)
index 0000000..48b03f9
--- /dev/null
@@ -0,0 +1,572 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+* File containing the Net_LDAP2_Util interface class.
+*
+* PHP version 5
+*
+* @category  Net
+* @package   Net_LDAP2
+* @author    Benedikt Hallinger <beni@php.net>
+* @copyright 2009 Benedikt Hallinger
+* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
+* @version   SVN: $Id: Util.php 286718 2009-08-03 07:30:49Z beni $
+* @link      http://pear.php.net/package/Net_LDAP2/
+*/
+
+/**
+* Includes
+*/
+require_once 'PEAR.php';
+
+/**
+* Utility Class for Net_LDAP2
+*
+* This class servers some functionality to the other classes of Net_LDAP2 but most of
+* the methods can be used separately as well.
+*
+* @category Net
+* @package  Net_LDAP2
+* @author   Benedikt Hallinger <beni@php.net>
+* @license  http://www.gnu.org/copyleft/lesser.html LGPL
+* @link     http://pear.php.net/package/Net_LDAP22/
+*/
+class Net_LDAP2_Util extends PEAR
+{
+    /**
+     * Constructor
+     *
+     * @access public
+     */
+    public function __construct()
+    {
+         // We do nothing here, since all methods can be called statically.
+         // In Net_LDAP <= 0.7, we needed a instance of Util, because
+         // it was possible to do utf8 encoding and decoding, but this
+         // has been moved to the LDAP class. The constructor remains only
+         // here to document the downward compatibility of creating an instance.
+    }
+
+    /**
+    * Explodes the given DN into its elements
+    *
+    * {@link http://www.ietf.org/rfc/rfc2253.txt RFC 2253} says, a Distinguished Name is a sequence
+    * of Relative Distinguished Names (RDNs), which themselves
+    * are sets of Attributes. For each RDN a array is constructed where the RDN part is stored.
+    *
+    * For example, the DN 'OU=Sales+CN=J. Smith,DC=example,DC=net' is exploded to:
+    * <kbd>array( [0] => array([0] => 'OU=Sales', [1] => 'CN=J. Smith'), [2] => 'DC=example', [3] => 'DC=net' )</kbd>
+    *
+    * [NOT IMPLEMENTED] DNs might also contain values, which are the bytes of the BER encoding of
+    * the X.500 AttributeValue rather than some LDAP string syntax. These values are hex-encoded
+    * and prefixed with a #. To distinguish such BER values, ldap_explode_dn uses references to
+    * the actual values, e.g. '1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com' is exploded to:
+    * [ { '1.3.6.1.4.1.1466.0' => "\004\002Hi" }, { 'DC' => 'example' }, { 'DC' => 'com' } ];
+    * See {@link http://www.vijaymukhi.com/vmis/berldap.htm} for more information on BER.
+    *
+    *  It also performs the following operations on the given DN:
+    *   - Unescape "\" followed by ",", "+", """, "\", "<", ">", ";", "#", "=", " ", or a hexpair
+    *     and strings beginning with "#".
+    *   - Removes the leading 'OID.' characters if the type is an OID instead of a name.
+    *   - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order.
+    *
+    * OPTIONS is a list of name/value pairs, valid options are:
+    *   casefold    Controls case folding of attribute types names.
+    *               Attribute values are not affected by this option.
+    *               The default is to uppercase. Valid values are:
+    *               lower        Lowercase attribute types names.
+    *               upper        Uppercase attribute type names. This is the default.
+    *               none         Do not change attribute type names.
+    *   reverse     If TRUE, the RDN sequence is reversed.
+    *   onlyvalues  If TRUE, then only attributes values are returned ('foo' instead of 'cn=foo')
+    *
+
+    * @param string $dn      The DN that should be exploded
+    * @param array  $options Options to use
+    *
+    * @static
+    * @return array   Parts of the exploded DN
+    * @todo implement BER
+    */
+    public static function ldap_explode_dn($dn, $options = array('casefold' => 'upper'))
+    {
+        if (!isset($options['onlyvalues'])) $options['onlyvalues']  = false;
+        if (!isset($options['reverse']))    $options['reverse']     = false;
+        if (!isset($options['casefold']))   $options['casefold']    = 'upper';
+
+        // Escaping of DN and stripping of "OID."
+        $dn = self::canonical_dn($dn, array('casefold' => $options['casefold']));
+
+        // splitting the DN
+        $dn_array = preg_split('/(?<=[^\\\\]),/', $dn);
+
+        // clear wrong splitting (possibly we have split too much)
+        // /!\ Not clear, if this is neccessary here
+        //$dn_array = self::correct_dn_splitting($dn_array, ',');
+
+        // construct subarrays for multivalued RDNs and unescape DN value
+        // also convert to output format and apply casefolding
+        foreach ($dn_array as $key => $value) {
+            $value_u = self::unescape_dn_value($value);
+            $rdns    = self::split_rdn_multival($value_u[0]);
+            if (count($rdns) > 1) {
+                // MV RDN!
+                foreach ($rdns as $subrdn_k => $subrdn_v) {
+                    // Casefolding
+                    if ($options['casefold'] == 'upper') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $subrdn_v);
+                    if ($options['casefold'] == 'lower') $subrdn_v = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $subrdn_v);
+
+                    if ($options['onlyvalues']) {
+                        preg_match('/(.+?)(?<!\\\\)=(.+)/', $subrdn_v, $matches);
+                        $rdn_ocl         = $matches[1];
+                        $rdn_val         = $matches[2];
+                        $unescaped       = self::unescape_dn_value($rdn_val);
+                        $rdns[$subrdn_k] = $unescaped[0];
+                    } else {
+                        $unescaped = self::unescape_dn_value($subrdn_v);
+                        $rdns[$subrdn_k] = $unescaped[0];
+                    }
+                }
+
+                $dn_array[$key] = $rdns;
+            } else {
+                // normal RDN
+
+                // Casefolding
+                if ($options['casefold'] == 'upper') $value = preg_replace("/^(\w+=)/e", "''.strtoupper('\\1').''", $value);
+                if ($options['casefold'] == 'lower') $value = preg_replace("/^(\w+=)/e", "''.strtolower('\\1').''", $value);
+
+                if ($options['onlyvalues']) {
+                    preg_match('/(.+?)(?<!\\\\)=(.+)/', $value, $matches);
+                    $dn_ocl         = $matches[1];
+                    $dn_val         = $matches[2];
+                    $unescaped      = self::unescape_dn_value($dn_val);
+                    $dn_array[$key] = $unescaped[0];
+                } else {
+                    $unescaped = self::unescape_dn_value($value);
+                    $dn_array[$key] = $unescaped[0];
+                }
+            }
+        }
+
+        if ($options['reverse']) {
+            return array_reverse($dn_array);
+        } else {
+            return $dn_array;
+        }
+    }
+
+    /**
+    * Escapes a DN value according to RFC 2253
+    *
+    * Escapes the given VALUES according to RFC 2253 so that they can be safely used in LDAP DNs.
+    * The characters ",", "+", """, "\", "<", ">", ";", "#", "=" with a special meaning in RFC 2252
+    * are preceeded by ba backslash. Control characters with an ASCII code < 32 are represented as \hexpair.
+    * Finally all leading and trailing spaces are converted to sequences of \20.
+    *
+    * @param array $values An array containing the DN values that should be escaped
+    *
+    * @static
+    * @return array The array $values, but escaped
+    */
+    public static function escape_dn_value($values = array())
+    {
+        // Parameter validation
+        if (!is_array($values)) {
+            $values = array($values);
+        }
+
+        foreach ($values as $key => $val) {
+            // Escaping of filter meta characters
+            $val = str_replace('\\', '\\\\', $val);
+            $val = str_replace(',',    '\,', $val);
+            $val = str_replace('+',    '\+', $val);
+            $val = str_replace('"',    '\"', $val);
+            $val = str_replace('<',    '\<', $val);
+            $val = str_replace('>',    '\>', $val);
+            $val = str_replace(';',    '\;', $val);
+            $val = str_replace('#',    '\#', $val);
+            $val = str_replace('=',    '\=', $val);
+
+            // ASCII < 32 escaping
+            $val = self::asc2hex32($val);
+
+            // Convert all leading and trailing spaces to sequences of \20.
+            if (preg_match('/^(\s*)(.+?)(\s*)$/', $val, $matches)) {
+                $val = $matches[2];
+                for ($i = 0; $i < strlen($matches[1]); $i++) {
+                    $val = '\20'.$val;
+                }
+                for ($i = 0; $i < strlen($matches[3]); $i++) {
+                    $val = $val.'\20';
+                }
+            }
+
+            if (null === $val) $val = '\0';  // apply escaped "null" if string is empty
+
+            $values[$key] = $val;
+        }
+
+        return $values;
+    }
+
+    /**
+    * Undoes the conversion done by escape_dn_value().
+    *
+    * Any escape sequence starting with a baskslash - hexpair or special character -
+    * will be transformed back to the corresponding character.
+    *
+    * @param array $values Array of DN Values
+    *
+    * @return array Same as $values, but unescaped
+    * @static
+    */
+    public static function unescape_dn_value($values = array())
+    {
+        // Parameter validation
+        if (!is_array($values)) {
+            $values = array($values);
+        }
+
+        foreach ($values as $key => $val) {
+            // strip slashes from special chars
+            $val = str_replace('\\\\', '\\', $val);
+            $val = str_replace('\,',    ',', $val);
+            $val = str_replace('\+',    '+', $val);
+            $val = str_replace('\"',    '"', $val);
+            $val = str_replace('\<',    '<', $val);
+            $val = str_replace('\>',    '>', $val);
+            $val = str_replace('\;',    ';', $val);
+            $val = str_replace('\#',    '#', $val);
+            $val = str_replace('\=',    '=', $val);
+
+            // Translate hex code into ascii
+            $values[$key] = self::hex2asc($val);
+        }
+
+        return $values;
+    }
+
+    /**
+    * Returns the given DN in a canonical form
+    *
+    * Returns false if DN is not a valid Distinguished Name.
+    * DN can either be a string or an array
+    * as returned by ldap_explode_dn, which is useful when constructing a DN.
+    * The DN array may have be indexed (each array value is a OCL=VALUE pair)
+    * or associative (array key is OCL and value is VALUE).
+    *
+    * It performs the following operations on the given DN:
+    *     - Removes the leading 'OID.' characters if the type is an OID instead of a name.
+    *     - Escapes all RFC 2253 special characters (",", "+", """, "\", "<", ">", ";", "#", "="), slashes ("/"), and any other character where the ASCII code is < 32 as \hexpair.
+    *     - Converts all leading and trailing spaces in values to be \20.
+    *     - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order.
+    *
+    * OPTIONS is a list of name/value pairs, valid options are:
+    *     casefold    Controls case folding of attribute type names.
+    *                 Attribute values are not affected by this option. The default is to uppercase.
+    *                 Valid values are:
+    *                 lower        Lowercase attribute type names.
+    *                 upper        Uppercase attribute type names. This is the default.
+    *                 none         Do not change attribute type names.
+    *     [NOT IMPLEMENTED] mbcescape   If TRUE, characters that are encoded as a multi-octet UTF-8 sequence will be escaped as \(hexpair){2,*}.
+    *     reverse     If TRUE, the RDN sequence is reversed.
+    *     separator   Separator to use between RDNs. Defaults to comma (',').
+    *
+    * Note: The empty string "" is a valid DN, so be sure not to do a "$can_dn == false" test,
+    *       because an empty string evaluates to false. Use the "===" operator instead.
+    *
+    * @param array|string $dn      The DN
+    * @param array        $options Options to use
+    *
+    * @static
+    * @return false|string The canonical DN or FALSE
+    * @todo implement option mbcescape
+    */
+    public static function canonical_dn($dn, $options = array('casefold' => 'upper', 'separator' => ','))
+    {
+        if ($dn === '') return $dn;  // empty DN is valid!
+
+        // options check
+        if (!isset($options['reverse'])) {
+            $options['reverse'] = false;
+        } else {
+            $options['reverse'] = true;
+        }
+        if (!isset($options['casefold']))  $options['casefold'] = 'upper';
+        if (!isset($options['separator'])) $options['separator'] = ',';
+
+
+        if (!is_array($dn)) {
+            // It is not clear to me if the perl implementation splits by the user defined
+            // separator or if it just uses this separator to construct the new DN
+            $dn = preg_split('/(?<=[^\\\\])'.$options['separator'].'/', $dn);
+
+            // clear wrong splitting (possibly we have split too much)
+            $dn = self::correct_dn_splitting($dn, $options['separator']);
+        } else {
+            // Is array, check, if the array is indexed or associative
+            $assoc = false;
+            foreach ($dn as $dn_key => $dn_part) {
+                if (!is_int($dn_key)) {
+                    $assoc = true;
+                }
+            }
+            // convert to indexed, if associative array detected
+            if ($assoc) {
+                $newdn = array();
+                foreach ($dn as $dn_key => $dn_part) {
+                    if (is_array($dn_part)) {
+                        ksort($dn_part, SORT_STRING); // we assume here, that the rdn parts are also associative
+                        $newdn[] = $dn_part;  // copy array as-is, so we can resolve it later
+                    } else {
+                        $newdn[] = $dn_key.'='.$dn_part;
+                    }
+                }
+                $dn =& $newdn;
+            }
+        }
+
+        // Escaping and casefolding
+        foreach ($dn as $pos => $dnval) {
+            if (is_array($dnval)) {
+                // subarray detected, this means very surely, that we had
+                // a multivalued dn part, which must be resolved
+                $dnval_new = '';
+                foreach ($dnval as $subkey => $subval) {
+                    // build RDN part
+                    if (!is_int($subkey)) {
+                        $subval = $subkey.'='.$subval;
+                    }
+                    $subval_processed = self::canonical_dn($subval);
+                    if (false === $subval_processed) return false;
+                    $dnval_new .= $subval_processed.'+';
+                }
+                $dn[$pos] = substr($dnval_new, 0, -1); // store RDN part, strip last plus
+            } else {
+                // try to split multivalued RDNS into array
+                $rdns = self::split_rdn_multival($dnval);
+                if (count($rdns) > 1) {
+                    // Multivalued RDN was detected!
+                    // The RDN value is expected to be correctly split by split_rdn_multival().
+                    // It's time to sort the RDN and build the DN!
+                    $rdn_string = '';
+                    sort($rdns, SORT_STRING); // Sort RDN keys alphabetically
+                    foreach ($rdns as $rdn) {
+                        $subval_processed = self::canonical_dn($rdn);
+                        if (false === $subval_processed) return false;
+                        $rdn_string .= $subval_processed.'+';
+                    }
+
+                    $dn[$pos] = substr($rdn_string, 0, -1); // store RDN part, strip last plus
+
+                } else {
+                    // no multivalued RDN!
+                    // split at first unescaped "="
+                    $dn_comp = preg_split('/(?<=[^\\\\])=/', $rdns[0], 2);
+                    $ocl     = ltrim($dn_comp[0]);  // trim left whitespaces 'cause of "cn=foo, l=bar" syntax (whitespace after comma)
+                    $val     = $dn_comp[1];
+
+                    // strip 'OID.', otherwise apply casefolding and escaping
+                    if (substr(strtolower($ocl), 0, 4) == 'oid.') {
+                        $ocl = substr($ocl, 4);
+                    } else {
+                        if ($options['casefold'] == 'upper') $ocl = strtoupper($ocl);
+                        if ($options['casefold'] == 'lower') $ocl = strtolower($ocl);
+                        $ocl = self::escape_dn_value(array($ocl));
+                        $ocl = $ocl[0];
+                    }
+
+                    // escaping of dn-value
+                    $val = self::escape_dn_value(array($val));
+                    $val = str_replace('/', '\/', $val[0]);
+
+                    $dn[$pos] = $ocl.'='.$val;
+                }
+            }
+        }
+
+        if ($options['reverse']) $dn = array_reverse($dn);
+        return implode($options['separator'], $dn);
+    }
+
+    /**
+    * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters.
+    *
+    * Any control characters with an ACII code < 32 as well as the characters with special meaning in
+    * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a
+    * backslash followed by two hex digits representing the hexadecimal value of the character.
+    *
+    * @param array $values Array of values to escape
+    *
+    * @static
+    * @return array Array $values, but escaped
+    */
+    public static function escape_filter_value($values = array())
+    {
+        // Parameter validation
+        if (!is_array($values)) {
+            $values = array($values);
+        }
+
+        foreach ($values as $key => $val) {
+            // Escaping of filter meta characters
+            $val = str_replace('\\', '\5c', $val);
+            $val = str_replace('*',  '\2a', $val);
+            $val = str_replace('(',  '\28', $val);
+            $val = str_replace(')',  '\29', $val);
+
+            // ASCII < 32 escaping
+            $val = self::asc2hex32($val);
+
+            if (null === $val) $val = '\0';  // apply escaped "null" if string is empty
+
+            $values[$key] = $val;
+        }
+
+        return $values;
+    }
+
+    /**
+    * Undoes the conversion done by {@link escape_filter_value()}.
+    *
+    * Converts any sequences of a backslash followed by two hex digits into the corresponding character.
+    *
+    * @param array $values Array of values to escape
+    *
+    * @static
+    * @return array Array $values, but unescaped
+    */
+    public static function unescape_filter_value($values = array())
+    {
+        // Parameter validation
+        if (!is_array($values)) {
+            $values = array($values);
+        }
+
+        foreach ($values as $key => $value) {
+            // Translate hex code into ascii
+            $values[$key] = self::hex2asc($value);
+        }
+
+        return $values;
+    }
+
+    /**
+    * Converts all ASCII chars < 32 to "\HEX"
+    *
+    * @param string $string String to convert
+    *
+    * @static
+    * @return string
+    */
+    public static function asc2hex32($string)
+    {
+        for ($i = 0; $i < strlen($string); $i++) {
+            $char = substr($string, $i, 1);
+            if (ord($char) < 32) {
+                $hex = dechex(ord($char));
+                if (strlen($hex) == 1) $hex = '0'.$hex;
+                $string = str_replace($char, '\\'.$hex, $string);
+            }
+        }
+        return $string;
+    }
+
+    /**
+    * Converts all Hex expressions ("\HEX") to their original ASCII characters
+    *
+    * @param string $string String to convert
+    *
+    * @static
+    * @author beni@php.net, heavily based on work from DavidSmith@byu.net
+    * @return string
+    */
+    public static function hex2asc($string)
+    {
+        $string = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $string);
+        return $string;
+    }
+
+    /**
+    * Split an multivalued RDN value into an Array
+    *
+    * A RDN can contain multiple values, spearated by a plus sign.
+    * This function returns each separate ocl=value pair of the RDN part.
+    *
+    * If no multivalued RDN is detected, an array containing only
+    * the original rdn part is returned.
+    *
+    * For example, the multivalued RDN 'OU=Sales+CN=J. Smith' is exploded to:
+    * <kbd>array([0] => 'OU=Sales', [1] => 'CN=J. Smith')</kbd>
+    *
+    * The method trys to be smart if it encounters unescaped "+" characters, but may fail,
+    * so ensure escaped "+"es in attr names and attr values.
+    *
+    * [BUG] If you have a multivalued RDN with unescaped plus characters
+    *       and there is a unescaped plus sign at the end of an value followed by an
+    *       attribute name containing an unescaped plus, then you will get wrong splitting:
+    *         $rdn = 'OU=Sales+C+N=J. Smith';
+    *       returns:
+    *         array('OU=Sales+C', 'N=J. Smith');
+    *       The "C+" is treaten as value of the first pair instead as attr name of the second pair.
+    *       To prevent this, escape correctly.
+    *
+    * @param string $rdn Part of an (multivalued) escaped RDN (eg. ou=foo OR ou=foo+cn=bar)
+    *
+    * @static
+    * @return array Array with the components of the multivalued RDN or Error
+    */
+    public static function split_rdn_multival($rdn)
+    {
+        $rdns = preg_split('/(?<!\\\\)\+/', $rdn);
+        $rdns = self::correct_dn_splitting($rdns, '+');
+        return array_values($rdns);
+    }
+
+    /**
+    * Splits a attribute=value syntax into an array
+    *
+    * The split will occur at the first unescaped '=' character.
+    *
+    * @param string $attr Attribute and Value Syntax
+    *
+    * @return array Indexed array: 0=attribute name, 1=attribute value
+    */
+    public static function split_attribute_string($attr)
+    {
+        return preg_split('/(?<!\\\\)=/', $attr, 2);
+    }
+
+    /**
+    * Corrects splitting of dn parts
+    *
+    * @param array $dn        Raw DN array
+    * @param array $separator Separator that was used when splitting
+    *
+    * @return array Corrected array
+    * @access protected
+    */
+    protected static function correct_dn_splitting($dn = array(), $separator = ',')
+    {
+        foreach ($dn as $key => $dn_value) {
+            $dn_value = $dn[$key]; // refresh value (foreach caches!)
+            // if the dn_value is not in attr=value format, then we had an
+            // unescaped separator character inside the attr name or the value.
+            // We assume, that it was the attribute value.
+            // [TODO] To solve this, we might ask the schema. Keep in mind, that UTIL class
+            //        must remain independent from the other classes or connections.
+            if (!preg_match('/.+(?<!\\\\)=.+/', $dn_value)) {
+                unset($dn[$key]);
+                if (array_key_exists($key-1, $dn)) {
+                    $dn[$key-1] = $dn[$key-1].$separator.$dn_value; // append to previous attr value
+                } else {
+                    $dn[$key+1] = $dn_value.$separator.$dn[$key+1]; // first element: prepend to next attr name
+                }
+            }
+        }
+        return array_values($dn);
+    }
+}
+
+?>
diff --git a/plugins/LilUrl/locale/LilUrl.pot b/plugins/LilUrl/locale/LilUrl.pot
new file mode 100644 (file)
index 0000000..47ed367
--- /dev/null
@@ -0,0 +1,22 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: LilUrlPlugin.php:68
+#, php-format
+msgid "Uses <a href=\"http://%1$s/\">%1$s</a> URL-shortener service."
+msgstr ""
index 1dd5dbbcc921514b31e57ea60630117d8e94704c..764bf7b291dabf7e6c90a9073b501c34e67666bc 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,14 +16,18 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: allmap.php:71
-#, php-format
-msgid "%s friends map"
+#: MapstractionPlugin.php:182
+msgid "Map"
 msgstr ""
 
-#: allmap.php:74
-#, php-format
-msgid "%s friends map, page %d"
+#: MapstractionPlugin.php:193
+msgid "Full size"
+msgstr ""
+
+#: MapstractionPlugin.php:205
+msgid ""
+"Show maps of users' and friends' notices with <a href=\"http://www."
+"mapstraction.com/\">Mapstraction</a> JavaScript library."
 msgstr ""
 
 #: map.php:72
@@ -34,18 +38,14 @@ msgstr ""
 msgid "User has no profile."
 msgstr ""
 
-#: MapstractionPlugin.php:182
-msgid "Map"
-msgstr ""
-
-#: MapstractionPlugin.php:193
-msgid "Full size"
+#: allmap.php:71
+#, php-format
+msgid "%s friends map"
 msgstr ""
 
-#: MapstractionPlugin.php:205
-msgid ""
-"Show maps of users' and friends' notices with <a href=\"http://www."
-"mapstraction.com/\">Mapstraction</a> JavaScript library."
+#: allmap.php:74
+#, php-format
+msgid "%s friends map, page %d"
 msgstr ""
 
 #: usermap.php:71
diff --git a/plugins/Minify/locale/Minify.pot b/plugins/Minify/locale/Minify.pot
new file mode 100644 (file)
index 0000000..6f7372d
--- /dev/null
@@ -0,0 +1,23 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: MinifyPlugin.php:179
+msgid ""
+"The Minify plugin minifies your CSS and Javascript, removing whitespace and "
+"comments."
+msgstr ""
diff --git a/plugins/MobileProfile/locale/MobileProfile.pot b/plugins/MobileProfile/locale/MobileProfile.pot
new file mode 100644 (file)
index 0000000..9495e97
--- /dev/null
@@ -0,0 +1,21 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: MobileProfilePlugin.php:424
+msgid "XHTML MobileProfile output for supporting user agents."
+msgstr ""
index 7e33a0eed69382696e95a653ddfed922a6056f94..97d593eadd61c68b2dc6c908b47fc2fc2fb1683f 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,297 +16,316 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: actions/groupsalmon.php:51
-msgid "Can't accept remote posts for a remote group."
-msgstr ""
-
-#: actions/groupsalmon.php:123
-msgid "Can't read profile to set up group membership."
+#: OStatusPlugin.php:210 OStatusPlugin.php:913 actions/ostatusinit.php:99
+msgid "Subscribe"
 msgstr ""
 
-#: actions/groupsalmon.php:126 actions/groupsalmon.php:169
-msgid "Groups can't join groups."
+#: OStatusPlugin.php:228 OStatusPlugin.php:635 actions/ostatussub.php:105
+#: actions/ostatusinit.php:96
+msgid "Join"
 msgstr ""
 
-#: actions/groupsalmon.php:153
+#: OStatusPlugin.php:451
 #, php-format
-msgid "Could not join remote user %1$s to group %2$s."
+msgid "Sent from %s via OStatus"
 msgstr ""
 
-#: actions/groupsalmon.php:166
-msgid "Can't read profile to cancel group membership."
+#: OStatusPlugin.php:503
+msgid "Could not set up remote subscription."
 msgstr ""
 
-#: actions/groupsalmon.php:182
-#, php-format
-msgid "Could not remove remote user %1$s from group %2$s."
+#: OStatusPlugin.php:619
+msgid "Could not set up remote group membership."
 msgstr ""
 
-#: actions/ostatusinit.php:40
-msgid "You can use the local subscription!"
+#: OStatusPlugin.php:636
+#, php-format
+msgid "%s has joined group %s."
 msgstr ""
 
-#: actions/ostatusinit.php:61
-msgid "There was a problem with your session token. Try again, please."
+#: OStatusPlugin.php:644
+msgid "Failed joining remote group."
 msgstr ""
 
-#: actions/ostatusinit.php:79 actions/ostatussub.php:439
-msgid "Subscribe to user"
+#: OStatusPlugin.php:684
+msgid "Leave"
 msgstr ""
 
-#: actions/ostatusinit.php:97
+#: OStatusPlugin.php:685
 #, php-format
-msgid "Subscribe to %s"
+msgid "%s has left group %s."
 msgstr ""
 
-#: actions/ostatusinit.php:102
-msgid "User nickname"
+#: OStatusPlugin.php:844
+msgid "Remote"
 msgstr ""
 
-#: actions/ostatusinit.php:103
-msgid "Nickname of the user you want to follow"
+#: OStatusPlugin.php:883
+msgid "Profile update"
 msgstr ""
 
-#: actions/ostatusinit.php:106
-msgid "Profile Account"
+#: OStatusPlugin.php:884
+#, php-format
+msgid "%s has updated their profile page."
 msgstr ""
 
-#: actions/ostatusinit.php:107
-msgid "Your account id (i.e. user@identi.ca)"
+#: OStatusPlugin.php:928
+msgid ""
+"Follow people across social networks that implement <a href=\"http://ostatus."
+"org/\">OStatus</a>."
 msgstr ""
 
-#: actions/ostatusinit.php:110 actions/ostatussub.php:115
-#: OStatusPlugin.php:205
-msgid "Subscribe"
+#: classes/Ostatus_profile.php:566
+msgid "Show more"
 msgstr ""
 
-#: actions/ostatusinit.php:128
-msgid "Must provide a remote profile."
+#: classes/Ostatus_profile.php:1004
+#, php-format
+msgid "Invalid avatar URL %s"
 msgstr ""
 
-#: actions/ostatusinit.php:138
-msgid "Couldn't look up OStatus account profile."
+#: classes/Ostatus_profile.php:1014
+#, php-format
+msgid "Tried to update avatar for unsaved remote profile %s"
 msgstr ""
 
-#: actions/ostatusinit.php:153
-msgid "Couldn't confirm remote profile address."
+#: classes/Ostatus_profile.php:1022
+#, php-format
+msgid "Unable to fetch avatar from %s"
 msgstr ""
 
-#: actions/ostatusinit.php:171
-msgid "OStatus Connect"
+#: lib/salmonaction.php:41
+msgid "This method requires a POST."
 msgstr ""
 
-#: actions/ostatussub.php:68
-msgid "Address or profile URL"
+#: lib/salmonaction.php:45
+msgid "Salmon requires application/magic-envelope+xml"
 msgstr ""
 
-#: actions/ostatussub.php:70
-msgid "Enter the profile URL of a PubSubHubbub-enabled feed"
+#: lib/salmonaction.php:55
+msgid "Salmon signature verification failed."
 msgstr ""
 
-#: actions/ostatussub.php:74
-msgid "Continue"
+#: lib/salmonaction.php:67
+msgid "Salmon post must be an Atom entry."
 msgstr ""
 
-#: actions/ostatussub.php:112 OStatusPlugin.php:503
-msgid "Join"
+#: lib/salmonaction.php:115
+msgid "Unrecognized activity type."
 msgstr ""
 
-#: actions/ostatussub.php:113
-msgid "Join this group"
+#: lib/salmonaction.php:123
+msgid "This target doesn't understand posts."
 msgstr ""
 
-#: actions/ostatussub.php:116
-msgid "Subscribe to this user"
+#: lib/salmonaction.php:128
+msgid "This target doesn't understand follows."
 msgstr ""
 
-#: actions/ostatussub.php:137
-msgid "You are already subscribed to this user."
+#: lib/salmonaction.php:133
+msgid "This target doesn't understand unfollows."
 msgstr ""
 
-#: actions/ostatussub.php:165
-msgid "You are already a member of this group."
+#: lib/salmonaction.php:138
+msgid "This target doesn't understand favorites."
 msgstr ""
 
-#: actions/ostatussub.php:286
-msgid "Empty remote profile URL!"
+#: lib/salmonaction.php:143
+msgid "This target doesn't understand unfavorites."
 msgstr ""
 
-#: actions/ostatussub.php:297
-msgid "Invalid address format."
+#: lib/salmonaction.php:148
+msgid "This target doesn't understand share events."
 msgstr ""
 
-#: actions/ostatussub.php:302
-msgid "Invalid URL or could not reach server."
+#: lib/salmonaction.php:153
+msgid "This target doesn't understand joins."
 msgstr ""
 
-#: actions/ostatussub.php:304
-msgid "Cannot read feed; server returned error."
+#: lib/salmonaction.php:158
+msgid "This target doesn't understand leave events."
 msgstr ""
 
-#: actions/ostatussub.php:306
-msgid "Cannot read feed; server returned an empty page."
+#: tests/gettext-speedtest.php:57
+msgid "Feeds"
 msgstr ""
 
-#: actions/ostatussub.php:308
-msgid "Bad HTML, could not find feed link."
+#: actions/ostatusgroup.php:75
+msgid "Join group"
 msgstr ""
 
-#: actions/ostatussub.php:310
-msgid "Could not find a feed linked from this URL."
+#: actions/ostatusgroup.php:77
+msgid "OStatus group's address, like http://example.net/group/nickname"
 msgstr ""
 
-#: actions/ostatussub.php:312
-msgid "Not a recognized feed type."
+#: actions/ostatusgroup.php:81 actions/ostatussub.php:71
+msgid "Continue"
 msgstr ""
 
-#: actions/ostatussub.php:315
-#, php-format
-msgid "Bad feed URL: %s %s"
+#: actions/ostatusgroup.php:100
+msgid "You are already a member of this group."
 msgstr ""
 
 #. TRANS: OStatus remote group subscription dialog error.
-#: actions/ostatussub.php:336
+#: actions/ostatusgroup.php:135
 msgid "Already a member!"
 msgstr ""
 
 #. TRANS: OStatus remote group subscription dialog error.
-#: actions/ostatussub.php:346
+#: actions/ostatusgroup.php:146
 msgid "Remote group join failed!"
 msgstr ""
 
 #. TRANS: OStatus remote group subscription dialog error.
-#: actions/ostatussub.php:350
+#: actions/ostatusgroup.php:150
 msgid "Remote group join aborted!"
 msgstr ""
 
-#. TRANS: OStatus remote subscription dialog error.
-#: actions/ostatussub.php:356
-msgid "Already subscribed!"
+#. TRANS: Page title for OStatus remote group join form
+#: actions/ostatusgroup.php:163
+msgid "Confirm joining remote group"
 msgstr ""
 
-#. TRANS: OStatus remote subscription dialog error.
-#: actions/ostatussub.php:361
-msgid "Remote subscription failed!"
+#: actions/ostatusgroup.php:174
+msgid ""
+"You can subscribe to groups from other supported sites. Paste the group's "
+"profile URI below:"
 msgstr ""
 
-#. TRANS: Page title for OStatus remote subscription form
-#: actions/ostatussub.php:459
-msgid "Authorize subscription"
+#: actions/groupsalmon.php:51
+msgid "Can't accept remote posts for a remote group."
 msgstr ""
 
-#: actions/ostatussub.php:470
-msgid ""
-"You can subscribe to users from other supported sites. Paste their address "
-"or profile URI below:"
+#: actions/groupsalmon.php:124
+msgid "Can't read profile to set up group membership."
 msgstr ""
 
-#: classes/Ostatus_profile.php:789
-#, php-format
-msgid "Tried to update avatar for unsaved remote profile %s"
+#: actions/groupsalmon.php:127 actions/groupsalmon.php:170
+msgid "Groups can't join groups."
 msgstr ""
 
-#: classes/Ostatus_profile.php:797
+#: actions/groupsalmon.php:154
 #, php-format
-msgid "Unable to fetch avatar from %s"
+msgid "Could not join remote user %1$s to group %2$s."
 msgstr ""
 
-#: lib/salmonaction.php:41
-msgid "This method requires a POST."
+#: actions/groupsalmon.php:167
+msgid "Can't read profile to cancel group membership."
 msgstr ""
 
-#: lib/salmonaction.php:45
-msgid "Salmon requires application/magic-envelope+xml"
+#: actions/groupsalmon.php:183
+#, php-format
+msgid "Could not remove remote user %1$s from group %2$s."
 msgstr ""
 
-#: lib/salmonaction.php:55
-msgid "Salmon signature verification failed."
+#: actions/ostatussub.php:65
+msgid "Subscribe to"
 msgstr ""
 
-#: lib/salmonaction.php:67
-msgid "Salmon post must be an Atom entry."
+#: actions/ostatussub.php:67
+msgid ""
+"OStatus user's address, like nickname@example.com or http://example.net/"
+"nickname"
 msgstr ""
 
-#: lib/salmonaction.php:115
-msgid "Unrecognized activity type."
+#: actions/ostatussub.php:106
+msgid "Join this group"
 msgstr ""
 
-#: lib/salmonaction.php:123
-msgid "This target doesn't understand posts."
+#. TRANS: Page title for OStatus remote subscription form
+#: actions/ostatussub.php:108 actions/ostatussub.php:400
+msgid "Confirm"
 msgstr ""
 
-#: lib/salmonaction.php:128
-msgid "This target doesn't understand follows."
+#: actions/ostatussub.php:109
+msgid "Subscribe to this user"
 msgstr ""
 
-#: lib/salmonaction.php:133
-msgid "This target doesn't understand unfollows."
+#: actions/ostatussub.php:130
+msgid "You are already subscribed to this user."
 msgstr ""
 
-#: lib/salmonaction.php:138
-msgid "This target doesn't understand favorites."
+#: actions/ostatussub.php:247 actions/ostatussub.php:253
+#: actions/ostatussub.php:272
+msgid ""
+"Sorry, we could not reach that address. Please make sure that the OStatus "
+"address is like nickname@example.com or http://example.net/nickname"
 msgstr ""
 
-#: lib/salmonaction.php:143
-msgid "This target doesn't understand unfavorites."
+#: actions/ostatussub.php:256 actions/ostatussub.php:259
+#: actions/ostatussub.php:262 actions/ostatussub.php:265
+#: actions/ostatussub.php:268
+msgid ""
+"Sorry, we could not reach that feed. Please try that OStatus address again "
+"later."
 msgstr ""
 
-#: lib/salmonaction.php:148
-msgid "This target doesn't understand share events."
+#. TRANS: OStatus remote subscription dialog error.
+#: actions/ostatussub.php:301
+msgid "Already subscribed!"
 msgstr ""
 
-#: lib/salmonaction.php:153
-msgid "This target doesn't understand joins."
+#. TRANS: OStatus remote subscription dialog error.
+#: actions/ostatussub.php:306
+msgid "Remote subscription failed!"
 msgstr ""
 
-#: lib/salmonaction.php:158
-msgid "This target doesn't understand leave events."
+#: actions/ostatussub.php:380 actions/ostatusinit.php:81
+msgid "Subscribe to user"
 msgstr ""
 
-#: OStatusPlugin.php:319
-#, php-format
-msgid "Sent from %s via OStatus"
+#: actions/ostatussub.php:411
+msgid ""
+"You can subscribe to users from other supported sites. Paste their address "
+"or profile URI below:"
 msgstr ""
 
-#: OStatusPlugin.php:371
-msgid "Could not set up remote subscription."
+#: actions/ostatusinit.php:41
+msgid "You can use the local subscription!"
 msgstr ""
 
-#: OStatusPlugin.php:487
-msgid "Could not set up remote group membership."
+#: actions/ostatusinit.php:63
+msgid "There was a problem with your session token. Try again, please."
 msgstr ""
 
-#: OStatusPlugin.php:504
+#: actions/ostatusinit.php:95
 #, php-format
-msgid "%s has joined group %s."
+msgid "Join group %s"
 msgstr ""
 
-#: OStatusPlugin.php:512
-msgid "Failed joining remote group."
+#: actions/ostatusinit.php:98
+#, php-format
+msgid "Subscribe to %s"
 msgstr ""
 
-#: OStatusPlugin.php:553
-msgid "Leave"
+#: actions/ostatusinit.php:111
+msgid "User nickname"
 msgstr ""
 
-#: OStatusPlugin.php:554
-#, php-format
-msgid "%s has left group %s."
+#: actions/ostatusinit.php:112
+msgid "Nickname of the user you want to follow"
 msgstr ""
 
-#: OStatusPlugin.php:685
-msgid "Subscribe to remote user"
+#: actions/ostatusinit.php:116
+msgid "Profile Account"
 msgstr ""
 
-#: OStatusPlugin.php:726
-msgid "Profile update"
+#: actions/ostatusinit.php:117
+msgid "Your account id (i.e. user@identi.ca)"
 msgstr ""
 
-#: OStatusPlugin.php:727
-#, php-format
-msgid "%s has updated their profile page."
+#: actions/ostatusinit.php:138
+msgid "Must provide a remote profile."
 msgstr ""
 
-#: tests/gettext-speedtest.php:57
-msgid "Feeds"
+#: actions/ostatusinit.php:149
+msgid "Couldn't look up OStatus account profile."
+msgstr ""
+
+#: actions/ostatusinit.php:161
+msgid "Couldn't confirm remote profile address."
+msgstr ""
+
+#: actions/ostatusinit.php:202
+msgid "OStatus Connect"
 msgstr ""
diff --git a/plugins/OStatus/locale/fr/LC_MESSAGES/OStatus.po b/plugins/OStatus/locale/fr/LC_MESSAGES/OStatus.po
deleted file mode 100644 (file)
index 0956d2f..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-07 14:14-0800\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: FeedSubPlugin.php:77
-msgid "Feeds"
-msgstr "Flux"
-
-#: FeedSubPlugin.php:78
-msgid "Feed subscription options"
-msgstr "Préférences pour abonnement flux"
-
-#: feedmunger.php:215
-#, php-format
-msgid "New post: \"%1$s\" %2$s"
-msgstr "Nouveau: \"%1$s\" %2$s"
-
-#: actions/feedsubsettings.php:41
-msgid "Feed subscriptions"
-msgstr "Abonnements aux fluxes"
-
-#: actions/feedsubsettings.php:52
-msgid ""
-"You can subscribe to feeds from other sites; updates will appear in your "
-"personal timeline."
-msgstr ""
-"Abonner aux fluxes RSS ou Atom des autres sites web; les temps se trouverair"
-"en votre flux personnel."
-
-#: actions/feedsubsettings.php:96
-msgid "Subscribe"
-msgstr "Abonner"
-
-#: actions/feedsubsettings.php:98
-msgid "Continue"
-msgstr "Prochaine"
-
-#: actions/feedsubsettings.php:151
-msgid "Empty feed URL!"
-msgstr ""
-
-#: actions/feedsubsettings.php:161
-msgid "Invalid URL or could not reach server."
-msgstr ""
-
-#: actions/feedsubsettings.php:164
-msgid "Cannot read feed; server returned error."
-msgstr ""
-
-#: actions/feedsubsettings.php:167
-msgid "Cannot read feed; server returned an empty page."
-msgstr ""
-
-#: actions/feedsubsettings.php:170
-msgid "Bad HTML, could not find feed link."
-msgstr ""
-
-#: actions/feedsubsettings.php:173
-msgid "Could not find a feed linked from this URL."
-msgstr ""
-
-#: actions/feedsubsettings.php:176
-msgid "Not a recognized feed type."
-msgstr ""
-
-#: actions/feedsubsettings.php:180
-msgid "Bad feed URL."
-msgstr ""
-
-#: actions/feedsubsettings.php:188
-msgid "Feed is not PuSH-enabled; cannot subscribe."
-msgstr ""
-
-#: actions/feedsubsettings.php:208
-msgid "Feed subscription failed! Bad response from hub."
-msgstr ""
-
-#: actions/feedsubsettings.php:218
-msgid "Already subscribed!"
-msgstr ""
-
-#: actions/feedsubsettings.php:220
-msgid "Feed subscribed!"
-msgstr ""
-
-#: actions/feedsubsettings.php:222
-msgid "Feed subscription failed!"
-msgstr ""
-
-#: actions/feedsubsettings.php:231
-msgid "Previewing feed:"
-msgstr ""
-
-msgid "Confirm"
-msgstr "Confirmer"
diff --git a/plugins/OpenExternalLinkTarget/locale/OpenExternalLinkTarget.pot b/plugins/OpenExternalLinkTarget/locale/OpenExternalLinkTarget.pot
new file mode 100644 (file)
index 0000000..f9bd4af
--- /dev/null
@@ -0,0 +1,21 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: OpenExternalLinkTargetPlugin.php:60
+msgid "Opens external links (i.e., with rel=external) on a new window or tab"
+msgstr ""
index 270e2c624b57530f8e7376d39271cdcb00774cfa..6b723ad10f9fda963b009d51babfb7f19cd8e683 100644 (file)
@@ -202,16 +202,16 @@ class OpenIDPlugin extends Plugin
         if ($this->openidOnly && !common_logged_in()) {
             // TRANS: Tooltip for main menu option "Login"
             $tooltip = _m('TOOLTIP', 'Login to the site');
-            // TRANS: Main menu option when not logged in to log in
             $action->menuItem(common_local_url('openidlogin'),
+                              // TRANS: Main menu option when not logged in to log in
                               _m('MENU', 'Login'),
                               $tooltip,
                               false,
                               'nav_login');
             // TRANS: Tooltip for main menu option "Help"
             $tooltip = _m('TOOLTIP', 'Help me!');
-            // TRANS: Main menu option for help on the StatusNet site
             $action->menuItem(common_local_url('doc', array('title' => 'help')),
+                              // TRANS: Main menu option for help on the StatusNet site
                               _m('MENU', 'Help'),
                               $tooltip,
                               false,
@@ -219,8 +219,8 @@ class OpenIDPlugin extends Plugin
             if (!common_config('site', 'private')) {
                 // TRANS: Tooltip for main menu option "Search"
                 $tooltip = _m('TOOLTIP', 'Search for people or text');
-                // TRANS: Main menu option when logged in or when the StatusNet instance is not private
                 $action->menuItem(common_local_url('peoplesearch'),
+                                  // TRANS: Main menu option when logged in or when the StatusNet instance is not private
                                   _m('MENU', 'Search'), $tooltip, false, 'nav_search');
             }
             Event::handle('EndPrimaryNav', array($action));
@@ -280,7 +280,9 @@ class OpenIDPlugin extends Plugin
         $action_name = $action->trimmed('action');
 
         $action->menuItem(common_local_url('openidlogin'),
-                          _m('OpenID'),
+                          // TRANS: OpenID plugin menu item on site logon page.
+                          _m('MENU', 'OpenID'),
+                          // TRANS: OpenID plugin tooltip for logon menu item.
                           _m('Login or register with OpenID'),
                           $action_name === 'openidlogin');
     }
@@ -316,7 +318,9 @@ class OpenIDPlugin extends Plugin
         $action_name = $action->trimmed('action');
 
         $action->menuItem(common_local_url('openidsettings'),
-                          _m('OpenID'),
+                          // TRANS: OpenID plugin menu item on user settings page.
+                          _m('MENU', 'OpenID'),
+                          // TRANS: OpenID plugin tooltip for user settings menu item.
                           _m('Add or remove OpenIDs'),
                           $action_name === 'openidsettings');
 
@@ -592,6 +596,7 @@ class OpenIDPlugin extends Plugin
                             'author' => 'Evan Prodromou, Craig Andrews',
                             'homepage' => 'http://status.net/wiki/Plugin:OpenID',
                             'rawdescription' =>
+                            // TRANS: OpenID plugin description.
                             _m('Use <a href="http://openid.net/">OpenID</a> to login to the site.'));
         return true;
     }
index 991e6584ee7ce07ac3402f93f1170fbaaaaf1adf..77fcc3805d8ca66c6b8aa1fc88c1509d44f39a36 100644 (file)
@@ -64,6 +64,7 @@ class FinishaddopenidAction extends Action
     {
         parent::handle($args);
         if (!common_logged_in()) {
+            // TRANS: Client error message
             $this->clientError(_m('Not logged in.'));
         } else {
             $this->tryLogin();
@@ -85,10 +86,12 @@ class FinishaddopenidAction extends Action
         $response = $consumer->complete(common_local_url('finishaddopenid'));
 
         if ($response->status == Auth_OpenID_CANCEL) {
+            // TRANS: Status message in case the response from the OpenID provider is that the logon attempt was cancelled.
             $this->message(_m('OpenID authentication cancelled.'));
             return;
         } else if ($response->status == Auth_OpenID_FAILURE) {
-            // Authentication failed; display the error message.
+            // TRANS: OpenID authentication failed; display the error message.
+            // TRANS: %s is the error message.
             $this->message(sprintf(_m('OpenID authentication failed: %s'),
                                    $response->message));
         } else if ($response->status == Auth_OpenID_SUCCESS) {
@@ -109,8 +112,10 @@ class FinishaddopenidAction extends Action
 
             if ($other) {
                 if ($other->id == $cur->id) {
+                    // TRANS: message in case a user tries to add an OpenID that is already connected to them.
                     $this->message(_m('You already have this OpenID!'));
                 } else {
+                    // TRANS: message in case a user tries to add an OpenID that is already used by another user.
                     $this->message(_m('Someone else already has this OpenID.'));
                 }
                 return;
@@ -123,11 +128,13 @@ class FinishaddopenidAction extends Action
             $result = oid_link_user($cur->id, $canonical, $display);
 
             if (!$result) {
+                // TRANS: message in case the OpenID object cannot be connected to the user.
                 $this->message(_m('Error connecting user.'));
                 return;
             }
             if ($sreg) {
                 if (!oid_update_user($cur, $sreg)) {
+                    // TRANS: message in case the user or the user profile cannot be saved in StatusNet.
                     $this->message(_m('Error updating profile'));
                     return;
                 }
@@ -167,6 +174,7 @@ class FinishaddopenidAction extends Action
 
     function title()
     {
+        // TRANS: Title after getting the status of the OpenID authorisation request.
         return _m('OpenID Login');
     }
 
index 32b092a0bdefa896b38d18ef35c57eb552cd4c3c..5b1a7cee09610329f0d95ce80b430ae7572b0ebd 100644 (file)
@@ -31,15 +31,18 @@ class FinishopenidloginAction extends Action
     {
         parent::handle($args);
         if (common_is_real_login()) {
+            // TRANS: Client error message trying to log on with OpenID while already logged on.
             $this->clientError(_m('Already logged in.'));
         } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
             $token = $this->trimmed('token');
             if (!$token || $token != common_session_token()) {
+                // TRANS: Message given when there is a problem with the user's session token.
                 $this->showForm(_m('There was a problem with your session token. Try again, please.'));
                 return;
             }
             if ($this->arg('create')) {
                 if (!$this->boolean('license')) {
+                    // TRANS: Message given if user does not agree with the site's license.
                     $this->showForm(_m('You can\'t register if you don\'t agree to the license.'),
                                     $this->trimmed('newname'));
                     return;
@@ -48,7 +51,8 @@ class FinishopenidloginAction extends Action
             } else if ($this->arg('connect')) {
                 $this->connectUser();
             } else {
-                $this->showForm(_m('Something weird happened.'),
+                // TRANS: Messag given on an unknown error.
+                $this->showForm(_m('An unknown error has occured.'),
                                 $this->trimmed('newname'));
             }
         } else {
@@ -62,12 +66,15 @@ class FinishopenidloginAction extends Action
             $this->element('div', array('class' => 'error'), $this->error);
         } else {
             $this->element('div', 'instructions',
+                           // TRANS: Instructions given after a first successful logon using OpenID.
+                           // TRANS: %s is the site name.
                            sprintf(_m('This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
         }
     }
 
     function title()
     {
+        // TRANS: Title
         return _m('OpenID Account Setup');
     }
 
@@ -115,6 +122,8 @@ class FinishopenidloginAction extends Action
                                       'value' => 'true'));
         $this->elementStart('label', array('for' => 'license',
                                           'class' => 'checkbox'));
+        // TRANS: OpenID plugin link text.
+        // TRANS: %s is a link to a licese with the license name as link text.
         $message = _('My text and files are available under %s ' .
                      'except this private data: password, ' .
                      'email address, IM address, and phone number.');
@@ -127,23 +136,29 @@ class FinishopenidloginAction extends Action
         $this->elementEnd('label');
         $this->elementEnd('li');
         $this->elementEnd('ul');
-        $this->submit('create', _m('Create'));
+        // TRANS: Button label in form in which to create a new user on the site for an OpenID.
+        $this->submit('create', _m('BUTTON', 'Create'));
         $this->elementEnd('fieldset');
 
         $this->elementStart('fieldset', array('id' => 'form_openid_createaccount'));
         $this->element('legend', null,
+                       // TRANS: Used as form legend for form in which to connect an OpenID to an existing user on the site.
                        _m('Connect existing account'));
         $this->element('p', null,
+                       // TRANS: User instructions for form in which to connect an OpenID to an existing user on the site.
                        _m('If you already have an account, login with your username and password to connect it to your OpenID.'));
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
+        // TRANS: Field label in form in which to connect an OpenID to an existing user on the site.
         $this->input('nickname', _m('Existing nickname'));
         $this->elementEnd('li');
         $this->elementStart('li');
+        // TRANS: Field label in form in which to connect an OpenID to an existing user on the site.
         $this->password('password', _m('Password'));
         $this->elementEnd('li');
         $this->elementEnd('ul');
-        $this->submit('connect', _m('Connect'));
+        // TRANS: Button label in form in which to connect an OpenID to an existing user on the site.
+        $this->submit('connect', _m('BUTTON', 'Connect'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
@@ -155,10 +170,11 @@ class FinishopenidloginAction extends Action
         $response = $consumer->complete(common_local_url('finishopenidlogin'));
 
         if ($response->status == Auth_OpenID_CANCEL) {
+            // TRANS: Status message in case the response from the OpenID provider is that the logon attempt was cancelled.
             $this->message(_m('OpenID authentication cancelled.'));
             return;
         } else if ($response->status == Auth_OpenID_FAILURE) {
-            // Authentication failed; display the error message.
+            // TRANS: OpenID authentication failed; display the error message. %s is the error message.
             $this->message(sprintf(_m('OpenID authentication failed: %s'), $response->message));
         } else if ($response->status == Auth_OpenID_SUCCESS) {
             // This means the authentication succeeded; extract the
@@ -224,6 +240,7 @@ class FinishopenidloginAction extends Action
         # FIXME: save invite code before redirect, and check here
 
         if (common_config('site', 'closed')) {
+            // TRANS: OpenID plugin message. No new user registration is allowed on the site.
             $this->clientError(_m('Registration not allowed.'));
             return;
         }
@@ -233,6 +250,7 @@ class FinishopenidloginAction extends Action
         if (common_config('site', 'inviteonly')) {
             $code = $_SESSION['invitecode'];
             if (empty($code)) {
+                // TRANS: OpenID plugin message. No new user registration is allowed on the site without an invitation code, and none was provided.
                 $this->clientError(_m('Registration not allowed.'));
                 return;
             }
@@ -240,6 +258,7 @@ class FinishopenidloginAction extends Action
             $invite = Invitation::staticGet($code);
 
             if (empty($invite)) {
+                // TRANS: OpenID plugin message. No new user registration is allowed on the site without an invitation code, and the one provided was not valid.
                 $this->clientError(_m('Not a valid invitation code.'));
                 return;
             }
@@ -250,16 +269,19 @@ class FinishopenidloginAction extends Action
         if (!Validate::string($nickname, array('min_length' => 1,
                                                'max_length' => 64,
                                                'format' => NICKNAME_FMT))) {
+            // TRANS: OpenID plugin message. The entered new user name did not conform to the requirements.
             $this->showForm(_m('Nickname must have only lowercase letters and numbers and no spaces.'));
             return;
         }
 
         if (!User::allowed_nickname($nickname)) {
+            // TRANS: OpenID plugin message. The entered new user name is blacklisted.
             $this->showForm(_m('Nickname not allowed.'));
             return;
         }
 
         if (User::staticGet('nickname', $nickname)) {
+            // TRANS: OpenID plugin message. The entered new user name is already used.
             $this->showForm(_m('Nickname already in use. Try another one.'));
             return;
         }
@@ -267,6 +289,7 @@ class FinishopenidloginAction extends Action
         list($display, $canonical, $sreg) = $this->getSavedValues();
 
         if (!$display || !$canonical) {
+            // TRANS: OpenID plugin server error. A stored OpenID cannot be retrieved.
             $this->serverError(_m('Stored OpenID not found.'));
             return;
         }
@@ -276,6 +299,7 @@ class FinishopenidloginAction extends Action
         $other = oid_get_user($canonical);
 
         if ($other) {
+            // TRANS: OpenID plugin server error.
             $this->serverError(_m('Creating new account for OpenID that already has a user.'));
             return;
         }
@@ -336,6 +360,7 @@ class FinishopenidloginAction extends Action
         $password = $this->trimmed('password');
 
         if (!common_check_user($nickname, $password)) {
+            // TRANS: OpenID plugin message.
             $this->showForm(_m('Invalid username or password.'));
             return;
         }
@@ -347,6 +372,7 @@ class FinishopenidloginAction extends Action
         list($display, $canonical, $sreg) = $this->getSavedValues();
 
         if (!$display || !$canonical) {
+            // TRANS: OpenID plugin server error. A stored OpenID cannot be found.
             $this->serverError(_m('Stored OpenID not found.'));
             return;
         }
@@ -354,6 +380,7 @@ class FinishopenidloginAction extends Action
         $result = oid_link_user($user->id, $canonical, $display);
 
         if (!$result) {
+            // TRANS: OpenID plugin server error. The user or user profile could not be saved.
             $this->serverError(_m('Error connecting user to OpenID.'));
             return;
         }
index 7ed8798355dea8d103202e782c839b31bd9fc5e8..70908422e50a1900ee0e58ff983d66fc173d5b8b 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,311 +16,347 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: finishaddopenid.php:67
-msgid "Not logged in."
+#: openidsettings.php:59
+msgid "OpenID settings"
 msgstr ""
 
-#: finishaddopenid.php:88 finishopenidlogin.php:149
-msgid "OpenID authentication cancelled."
+#: openidsettings.php:70
+#, php-format
+msgid ""
+"[OpenID](%%doc.openid%%) lets you log into many sites with the same user "
+"account. Manage your associated OpenIDs from here."
 msgstr ""
 
-#: finishaddopenid.php:92 finishopenidlogin.php:153
-#, php-format
-msgid "OpenID authentication failed: %s"
+#: openidsettings.php:99
+msgid "Add OpenID"
 msgstr ""
 
-#: finishaddopenid.php:112
-msgid "You already have this OpenID!"
+#: openidsettings.php:102
+msgid ""
+"If you want to add an OpenID to your account, enter it in the box below and "
+"click \"Add\"."
 msgstr ""
 
-#: finishaddopenid.php:114
-msgid "Someone else already has this OpenID."
+#: openidsettings.php:107 openidlogin.php:119
+msgid "OpenID URL"
 msgstr ""
 
-#: finishaddopenid.php:126
-msgid "Error connecting user."
+#: openidsettings.php:117
+msgid "Add"
 msgstr ""
 
-#: finishaddopenid.php:131
-msgid "Error updating profile"
+#: openidsettings.php:129
+msgid "Remove OpenID"
 msgstr ""
 
-#: finishaddopenid.php:170 openidlogin.php:95
-msgid "OpenID Login"
+#: openidsettings.php:134
+msgid ""
+"Removing your only OpenID would make it impossible to log in! If you need to "
+"remove it, add another OpenID first."
 msgstr ""
 
-#: finishopenidlogin.php:34 openidlogin.php:30
-msgid "Already logged in."
+#: openidsettings.php:149
+msgid ""
+"You can remove an OpenID from your account by clicking the button marked "
+"\"Remove\"."
 msgstr ""
 
-#: finishopenidlogin.php:38 openidlogin.php:37 openidsettings.php:194
-msgid "There was a problem with your session token. Try again, please."
+#: openidsettings.php:172 openidsettings.php:213
+msgid "Remove"
 msgstr ""
 
-#: finishopenidlogin.php:43
-msgid "You can't register if you don't agree to the license."
+#: openidsettings.php:186
+msgid "OpenID Trusted Sites"
+msgstr ""
+
+#: openidsettings.php:189
+msgid ""
+"The following sites are allowed to access your identity and log you in. You "
+"can remove a site from this list to deny it access to your OpenID."
 msgstr ""
 
-#: finishopenidlogin.php:52 openidsettings.php:208
+#: openidsettings.php:231 finishopenidlogin.php:38 openidlogin.php:39
+msgid "There was a problem with your session token. Try again, please."
+msgstr ""
+
+#: openidsettings.php:247 finishopenidlogin.php:51
 msgid "Something weird happened."
 msgstr ""
 
-#: finishopenidlogin.php:66
-#, php-format
-msgid ""
-"This is the first time you've logged into %s so we must connect your OpenID "
-"to a local account. You can either create a new account, or connect with "
-"your existing account, if you have one."
+#: openidsettings.php:271
+msgid "No such OpenID trustroot."
 msgstr ""
 
-#: finishopenidlogin.php:72
-msgid "OpenID Account Setup"
+#: openidsettings.php:275
+msgid "Trustroots removed"
 msgstr ""
 
-#: finishopenidlogin.php:97
-msgid "Create new account"
+#: openidsettings.php:298
+msgid "No such OpenID."
 msgstr ""
 
-#: finishopenidlogin.php:99
-msgid "Create a new user with this nickname."
+#: openidsettings.php:303
+msgid "That OpenID does not belong to you."
 msgstr ""
 
-#: finishopenidlogin.php:102
-msgid "New nickname"
+#: openidsettings.php:307
+msgid "OpenID removed."
 msgstr ""
 
-#: finishopenidlogin.php:104
-msgid "1-64 lowercase letters or numbers, no punctuation or spaces"
+#: openid.php:137
+msgid "Cannot instantiate OpenID consumer object."
 msgstr ""
 
-#: finishopenidlogin.php:114
-msgid "My text and files are available under "
+#: openid.php:147
+msgid "Not a valid OpenID."
 msgstr ""
 
-#: finishopenidlogin.php:117
-msgid ""
-" except this private data: password, email address, IM address, phone number."
+#: openid.php:149
+#, php-format
+msgid "OpenID failure: %s"
 msgstr ""
 
-#: finishopenidlogin.php:121
-msgid "Create"
+#: openid.php:176
+#, php-format
+msgid "Could not redirect to server: %s"
 msgstr ""
 
-#: finishopenidlogin.php:126
-msgid "Connect existing account"
+#: openid.php:194
+#, php-format
+msgid "Could not create OpenID form: %s"
 msgstr ""
 
-#: finishopenidlogin.php:128
+#: openid.php:210
 msgid ""
-"If you already have an account, login with your username and password to "
-"connect it to your OpenID."
+"This form should automatically submit itself. If not, click the submit "
+"button to go to your OpenID provider."
 msgstr ""
 
-#: finishopenidlogin.php:131
-msgid "Existing nickname"
+#: openid.php:242
+msgid "Error saving the profile."
 msgstr ""
 
-#: finishopenidlogin.php:134
-msgid "Password"
+#: openid.php:253
+msgid "Error saving the user."
 msgstr ""
 
-#: finishopenidlogin.php:137
-msgid "Connect"
+#: openid.php:282
+msgid "Unauthorized URL used for OpenID login."
 msgstr ""
 
-#: finishopenidlogin.php:215 finishopenidlogin.php:224
-msgid "Registration not allowed."
+#: openid.php:302
+msgid "OpenID Login Submission"
 msgstr ""
 
-#: finishopenidlogin.php:231
-msgid "Not a valid invitation code."
+#: openid.php:312
+msgid "Requesting authorization from your login provider..."
 msgstr ""
 
-#: finishopenidlogin.php:241
-msgid "Nickname must have only lowercase letters and numbers and no spaces."
+#: openid.php:315
+msgid ""
+"If you are not redirected to your login provider in a few seconds, try "
+"pushing the button below."
 msgstr ""
 
-#: finishopenidlogin.php:246
-msgid "Nickname not allowed."
+#. TRANS: Tooltip for main menu option "Login"
+#: OpenIDPlugin.php:204
+msgctxt "TOOLTIP"
+msgid "Login to the site"
 msgstr ""
 
-#: finishopenidlogin.php:251
-msgid "Nickname already in use. Try another one."
+#: OpenIDPlugin.php:207
+msgctxt "MENU"
+msgid "Login"
 msgstr ""
 
-#: finishopenidlogin.php:258 finishopenidlogin.php:338
-msgid "Stored OpenID not found."
+#. TRANS: Tooltip for main menu option "Help"
+#: OpenIDPlugin.php:212
+msgctxt "TOOLTIP"
+msgid "Help me!"
 msgstr ""
 
-#: finishopenidlogin.php:267
-msgid "Creating new account for OpenID that already has a user."
+#: OpenIDPlugin.php:215
+msgctxt "MENU"
+msgid "Help"
 msgstr ""
 
-#: finishopenidlogin.php:327
-msgid "Invalid username or password."
+#. TRANS: Tooltip for main menu option "Search"
+#: OpenIDPlugin.php:221
+msgctxt "TOOLTIP"
+msgid "Search for people or text"
 msgstr ""
 
-#: finishopenidlogin.php:345
-msgid "Error connecting user to OpenID."
+#: OpenIDPlugin.php:224
+msgctxt "MENU"
+msgid "Search"
 msgstr ""
 
-#: openid.php:141
-msgid "Cannot instantiate OpenID consumer object."
+#: OpenIDPlugin.php:283 OpenIDPlugin.php:319
+msgid "OpenID"
 msgstr ""
 
-#: openid.php:151
-msgid "Not a valid OpenID."
+#: OpenIDPlugin.php:284
+msgid "Login or register with OpenID"
 msgstr ""
 
-#: openid.php:153
-#, php-format
-msgid "OpenID failure: %s"
+#: OpenIDPlugin.php:320
+msgid "Add or remove OpenIDs"
 msgstr ""
 
-#: openid.php:180
-#, php-format
-msgid "Could not redirect to server: %s"
+#: OpenIDPlugin.php:595
+msgid "Use <a href=\"http://openid.net/\">OpenID</a> to login to the site."
 msgstr ""
 
-#: openid.php:198
+#: openidserver.php:106
 #, php-format
-msgid "Could not create OpenID form: %s"
-msgstr ""
-
-#: openid.php:214
-msgid ""
-"This form should automatically submit itself. If not, click the submit "
-"button to go to your OpenID provider."
+msgid "You are not authorized to use the identity %s."
 msgstr ""
 
-#: openid.php:246
-msgid "Error saving the profile."
+#: openidserver.php:126
+msgid "Just an OpenID provider. Nothing to see here, move along..."
 msgstr ""
 
-#: openid.php:257
-msgid "Error saving the user."
+#: finishopenidlogin.php:34 openidlogin.php:30
+msgid "Already logged in."
 msgstr ""
 
-#: openid.php:277
-msgid "OpenID Auto-Submit"
+#: finishopenidlogin.php:43
+msgid "You can't register if you don't agree to the license."
 msgstr ""
 
-#: openidlogin.php:66
+#: finishopenidlogin.php:65
 #, php-format
 msgid ""
-"For security reasons, please re-login with your [OpenID](%%doc.openid%%) "
-"before changing your settings."
+"This is the first time you've logged into %s so we must connect your OpenID "
+"to a local account. You can either create a new account, or connect with "
+"your existing account, if you have one."
 msgstr ""
 
-#: openidlogin.php:70
-#, php-format
-msgid "Login with an [OpenID](%%doc.openid%%) account."
+#: finishopenidlogin.php:71
+msgid "OpenID Account Setup"
 msgstr ""
 
-#: openidlogin.php:112
-msgid "OpenID login"
+#: finishopenidlogin.php:101
+msgid "Create new account"
 msgstr ""
 
-#: openidlogin.php:117 openidsettings.php:107
-msgid "OpenID URL"
+#: finishopenidlogin.php:103
+msgid "Create a new user with this nickname."
 msgstr ""
 
-#: openidlogin.php:119
-msgid "Your OpenID URL"
+#: finishopenidlogin.php:106
+msgid "New nickname"
 msgstr ""
 
-#: openidlogin.php:122
-msgid "Remember me"
+#: finishopenidlogin.php:108
+msgid "1-64 lowercase letters or numbers, no punctuation or spaces"
 msgstr ""
 
-#: openidlogin.php:123
-msgid "Automatically login in the future; not for shared computers!"
+#: finishopenidlogin.php:130
+msgid "Create"
 msgstr ""
 
-#: openidlogin.php:127
-msgid "Login"
+#: finishopenidlogin.php:135
+msgid "Connect existing account"
 msgstr ""
 
-#: OpenIDPlugin.php:123 OpenIDPlugin.php:135
-msgid "OpenID"
+#: finishopenidlogin.php:137
+msgid ""
+"If you already have an account, login with your username and password to "
+"connect it to your OpenID."
 msgstr ""
 
-#: OpenIDPlugin.php:124
-msgid "Login or register with OpenID"
+#: finishopenidlogin.php:140
+msgid "Existing nickname"
 msgstr ""
 
-#: OpenIDPlugin.php:136
-msgid "Add or remove OpenIDs"
+#: finishopenidlogin.php:143
+msgid "Password"
 msgstr ""
 
-#: OpenIDPlugin.php:324
-msgid "Use <a href=\"http://openid.net/\">OpenID</a> to login to the site."
+#: finishopenidlogin.php:146
+msgid "Connect"
 msgstr ""
 
-#: openidserver.php:106
+#: finishopenidlogin.php:158 finishaddopenid.php:88
+msgid "OpenID authentication cancelled."
+msgstr ""
+
+#: finishopenidlogin.php:162 finishaddopenid.php:92
 #, php-format
-msgid "You are not authorized to use the identity %s."
+msgid "OpenID authentication failed: %s"
 msgstr ""
 
-#: openidserver.php:126
-msgid "Just an OpenID provider. Nothing to see here, move along..."
+#: finishopenidlogin.php:227 finishopenidlogin.php:236
+msgid "Registration not allowed."
 msgstr ""
 
-#: openidsettings.php:59
-msgid "OpenID settings"
+#: finishopenidlogin.php:243
+msgid "Not a valid invitation code."
 msgstr ""
 
-#: openidsettings.php:70
-#, php-format
-msgid ""
-"[OpenID](%%doc.openid%%) lets you log into many sites with the same user "
-"account. Manage your associated OpenIDs from here."
+#: finishopenidlogin.php:253
+msgid "Nickname must have only lowercase letters and numbers and no spaces."
 msgstr ""
 
-#: openidsettings.php:99
-msgid "Add OpenID"
+#: finishopenidlogin.php:258
+msgid "Nickname not allowed."
 msgstr ""
 
-#: openidsettings.php:102
-msgid ""
-"If you want to add an OpenID to your account, enter it in the box below and "
-"click \"Add\"."
+#: finishopenidlogin.php:263
+msgid "Nickname already in use. Try another one."
 msgstr ""
 
-#: openidsettings.php:117
-msgid "Add"
+#: finishopenidlogin.php:270 finishopenidlogin.php:350
+msgid "Stored OpenID not found."
 msgstr ""
 
-#: openidsettings.php:129
-msgid "Remove OpenID"
+#: finishopenidlogin.php:279
+msgid "Creating new account for OpenID that already has a user."
 msgstr ""
 
-#: openidsettings.php:134
-msgid ""
-"Removing your only OpenID would make it impossible to log in! If you need to "
-"remove it, add another OpenID first."
+#: finishopenidlogin.php:339
+msgid "Invalid username or password."
 msgstr ""
 
-#: openidsettings.php:149
+#: finishopenidlogin.php:357
+msgid "Error connecting user to OpenID."
+msgstr ""
+
+#: openidlogin.php:68
+#, php-format
 msgid ""
-"You can remove an OpenID from your account by clicking the button marked "
-"\"Remove\"."
+"For security reasons, please re-login with your [OpenID](%%doc.openid%%) "
+"before changing your settings."
 msgstr ""
 
-#: openidsettings.php:172
-msgid "Remove"
+#: openidlogin.php:72
+#, php-format
+msgid "Login with an [OpenID](%%doc.openid%%) account."
 msgstr ""
 
-#: openidsettings.php:228
-msgid "No such OpenID."
+#: openidlogin.php:97 finishaddopenid.php:170
+msgid "OpenID Login"
 msgstr ""
 
-#: openidsettings.php:233
-msgid "That OpenID does not belong to you."
+#: openidlogin.php:114
+msgid "OpenID login"
 msgstr ""
 
-#: openidsettings.php:237
-msgid "OpenID removed."
+#: openidlogin.php:121
+msgid "Your OpenID URL"
+msgstr ""
+
+#: openidlogin.php:124
+msgid "Remember me"
+msgstr ""
+
+#: openidlogin.php:125
+msgid "Automatically login in the future; not for shared computers!"
+msgstr ""
+
+#: openidlogin.php:129
+msgid "Login"
 msgstr ""
 
 #: openidtrust.php:51
@@ -332,17 +368,37 @@ msgid ""
 "This page should only be reached during OpenID processing, not directly."
 msgstr ""
 
-#: openidtrust.php:118
+#: openidtrust.php:117
 #, php-format
 msgid ""
 "%s  has asked to verify your identity. Click Continue to verify your "
 "identity and login without creating a new password."
 msgstr ""
 
-#: openidtrust.php:136
+#: openidtrust.php:135
 msgid "Continue"
 msgstr ""
 
-#: openidtrust.php:137
+#: openidtrust.php:136
 msgid "Cancel"
 msgstr ""
+
+#: finishaddopenid.php:67
+msgid "Not logged in."
+msgstr ""
+
+#: finishaddopenid.php:112
+msgid "You already have this OpenID!"
+msgstr ""
+
+#: finishaddopenid.php:114
+msgid "Someone else already has this OpenID."
+msgstr ""
+
+#: finishaddopenid.php:126
+msgid "Error connecting user."
+msgstr ""
+
+#: finishaddopenid.php:131
+msgid "Error updating profile"
+msgstr ""
index ae0329376cc4e7724d4072df3fea454d1b5f666a..5cda9b129a937d6ea0f328e6c323a5cf68ce43ed 100644 (file)
@@ -8,315 +8,351 @@ msgid ""
 msgstr ""
 "Project-Id-Version: StatusNet\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-04-11 21:42+0000\n"
-"PO-Revision-Date: 2010-04-12 00:53+0100\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: 2010-04-30 02:16+0100\n"
+"Last-Translator: Siebrand Mazeland <s.mazeland@xs4all.nl>\n"
 "Language-Team: Dutch\n"
+"MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"Last-Translator: Siebrand Mazeland <s.mazeland@xs4all.nl>\n"
-"MIME-Version: 1.0\n"
 
-#: finishaddopenid.php:67
-msgid "Not logged in."
-msgstr "Niet aangemeld."
+#: openidsettings.php:59
+msgid "OpenID settings"
+msgstr "OpenID-instellingen"
 
-#: finishaddopenid.php:88
-#: finishopenidlogin.php:149
-msgid "OpenID authentication cancelled."
-msgstr "De authenticatie via OpenID is afgebroken."
+#: openidsettings.php:70
+#, php-format
+msgid "[OpenID](%%doc.openid%%) lets you log into many sites with the same user account. Manage your associated OpenIDs from here."
+msgstr "Met [OpenID](%%doc.openid%%) kunt u aanmelden bij veel websites met dezelfde gebruiker. U kunt hier uw gekoppelde OpenID's beheren."
 
-#: finishaddopenid.php:92
-#: finishopenidlogin.php:153
+#: openidsettings.php:99
+msgid "Add OpenID"
+msgstr "OpenID toevoegen"
+
+#: openidsettings.php:102
+msgid "If you want to add an OpenID to your account, enter it in the box below and click \"Add\"."
+msgstr "Als u een OpenID aan uw gebruiker wilt toevoegen, voer deze dan hieronder in en klik op \"Toevoegen\"."
+
+#: openidsettings.php:107
+#: openidlogin.php:119
+msgid "OpenID URL"
+msgstr "OpenID-URL"
+
+#: openidsettings.php:117
+msgid "Add"
+msgstr "Toevoegen"
+
+#: openidsettings.php:129
+msgid "Remove OpenID"
+msgstr "OpenID verwijderen"
+
+#: openidsettings.php:134
+msgid "Removing your only OpenID would make it impossible to log in! If you need to remove it, add another OpenID first."
+msgstr "Door uw enige OpenID te verwijderen zou het niet meer mogelijk zijn om aan te melden. Als u het wilt verwijderen, voeg dan eerst een andere OpenID toe."
+
+#: openidsettings.php:149
+msgid "You can remove an OpenID from your account by clicking the button marked \"Remove\"."
+msgstr "U kunt een OpenID van uw gebruiker verwijderen door te klikken op de knop \"Verwijderen\"."
+
+#: openidsettings.php:172
+#: openidsettings.php:213
+msgid "Remove"
+msgstr "Verwijderen"
+
+#: openidsettings.php:186
+msgid "OpenID Trusted Sites"
+msgstr "Vertrouwde OpenID-sites"
+
+#: openidsettings.php:189
+msgid "The following sites are allowed to access your identity and log you in. You can remove a site from this list to deny it access to your OpenID."
+msgstr "De volgende sites hebben toegang tot uw indentiteit en kunnen u aanmelden. U kunt een site verwijderen uit deze lijst zodat deze niet langer toegang heeft tot uw OpenID."
+
+#: openidsettings.php:231
+#: finishopenidlogin.php:38
+#: openidlogin.php:39
+msgid "There was a problem with your session token. Try again, please."
+msgstr "Er was een probleem met uw sessietoken. Probeer het opnieuw."
+
+#: openidsettings.php:247
+#: finishopenidlogin.php:51
+msgid "Something weird happened."
+msgstr "Er is iets vreemds gebeurd."
+
+#: openidsettings.php:271
+msgid "No such OpenID trustroot."
+msgstr "Die OpenID trustroot bestaat niet."
+
+#: openidsettings.php:275
+msgid "Trustroots removed"
+msgstr "De trustroots zijn verwijderd"
+
+#: openidsettings.php:298
+msgid "No such OpenID."
+msgstr "De OpenID bestaat niet."
+
+#: openidsettings.php:303
+msgid "That OpenID does not belong to you."
+msgstr "Die OpenID is niet van u."
+
+#: openidsettings.php:307
+msgid "OpenID removed."
+msgstr "OpenID verwijderd."
+
+#: openid.php:137
+msgid "Cannot instantiate OpenID consumer object."
+msgstr "Het was niet mogelijk een OpenID-object aan te maken."
+
+#: openid.php:147
+msgid "Not a valid OpenID."
+msgstr "Geen geldige OpenID."
+
+#: openid.php:149
 #, php-format
-msgid "OpenID authentication failed: %s"
-msgstr "De authenticatie via OpenID is mislukt: %s"
+msgid "OpenID failure: %s"
+msgstr "OpenID-fout: %s"
 
-#: finishaddopenid.php:112
-msgid "You already have this OpenID!"
-msgstr "U hebt deze OpenID al!"
+#: openid.php:176
+#, php-format
+msgid "Could not redirect to server: %s"
+msgstr "Het was niet mogelijk door te verwijzen naar de server: %s"
 
-#: finishaddopenid.php:114
-msgid "Someone else already has this OpenID."
-msgstr "Iemand anders gebruikt deze OpenID al."
+#: openid.php:194
+#, php-format
+msgid "Could not create OpenID form: %s"
+msgstr "Het was niet mogelijk het OpenID-formulier aan te maken: %s"
 
-#: finishaddopenid.php:126
-msgid "Error connecting user."
-msgstr "Fout bij het verbinden met de gebruiker."
+#: openid.php:210
+msgid "This form should automatically submit itself. If not, click the submit button to go to your OpenID provider."
+msgstr "Dit formulier hoort zichzelf automatisch op te slaan. Als dat niet gebeurt, klik dan op de knop \"Aanmelden\" om naar uw OpenID-provider te gaan."
 
-#: finishaddopenid.php:131
-msgid "Error updating profile"
-msgstr "Fout bij het bijwerken van het profiel."
+#: openid.php:242
+msgid "Error saving the profile."
+msgstr "Fout bij het opslaan van het profiel."
 
-#: finishaddopenid.php:170
-#: openidlogin.php:95
-msgid "OpenID Login"
+#: openid.php:253
+msgid "Error saving the user."
+msgstr "Fout bij het opslaan van de gebruiker."
+
+#: openid.php:282
+msgid "Unauthorized URL used for OpenID login."
+msgstr "Ongeautoriseerde URL gebruikt voor aanmelden via OpenID"
+
+#: openid.php:302
+#, fuzzy
+msgid "OpenID Login Submission"
 msgstr "Aanmelden via OpenID"
 
+#: openid.php:312
+msgid "Requesting authorization from your login provider..."
+msgstr "Bezig met het vragen van autorisatie van uw aanmeldprovider..."
+
+#: openid.php:315
+msgid "If you are not redirected to your login provider in a few seconds, try pushing the button below."
+msgstr "Als u binnen een aantal seconden niet wordt doorverwezen naar uw aanmeldprovider, klik dan op de onderstaande knop."
+
+#. TRANS: Tooltip for main menu option "Login"
+#: OpenIDPlugin.php:204
+msgctxt "TOOLTIP"
+msgid "Login to the site"
+msgstr "Aanmelden bij de site"
+
+#: OpenIDPlugin.php:207
+#, fuzzy
+msgctxt "MENU"
+msgid "Login"
+msgstr "Aanmelden"
+
+#. TRANS: Tooltip for main menu option "Help"
+#: OpenIDPlugin.php:212
+msgctxt "TOOLTIP"
+msgid "Help me!"
+msgstr "Help me"
+
+#: OpenIDPlugin.php:215
+msgctxt "MENU"
+msgid "Help"
+msgstr "Hulp"
+
+#. TRANS: Tooltip for main menu option "Search"
+#: OpenIDPlugin.php:221
+msgctxt "TOOLTIP"
+msgid "Search for people or text"
+msgstr "Zoeken naar mensen of tekst"
+
+#: OpenIDPlugin.php:224
+msgctxt "MENU"
+msgid "Search"
+msgstr "Zoeken"
+
+#: OpenIDPlugin.php:283
+#: OpenIDPlugin.php:319
+msgid "OpenID"
+msgstr "OpenID"
+
+#: OpenIDPlugin.php:284
+msgid "Login or register with OpenID"
+msgstr "Aanmelden of registreren met OpenID"
+
+#: OpenIDPlugin.php:320
+msgid "Add or remove OpenIDs"
+msgstr "OpenID's toevoegen of verwijderen"
+
+#: OpenIDPlugin.php:595
+msgid "Use <a href=\"http://openid.net/\">OpenID</a> to login to the site."
+msgstr "Gebruik <a href=\"http://openid.net/\">OpenID</a> om aan te melden bij de site."
+
+#: openidserver.php:106
+#, php-format
+msgid "You are not authorized to use the identity %s."
+msgstr "U mag de identiteit %s niet gebruiken."
+
+#: openidserver.php:126
+msgid "Just an OpenID provider. Nothing to see here, move along..."
+msgstr "Gewoon een OpenID-provider. Niets te zien hier..."
+
 #: finishopenidlogin.php:34
 #: openidlogin.php:30
 msgid "Already logged in."
 msgstr "U bent al aangemeld."
 
-#: finishopenidlogin.php:38
-#: openidlogin.php:37
-#: openidsettings.php:194
-msgid "There was a problem with your session token. Try again, please."
-msgstr "Er was een probleem met uw sessietoken. Probeer het opnieuw."
-
 #: finishopenidlogin.php:43
 msgid "You can't register if you don't agree to the license."
 msgstr "U kunt niet registreren als u niet akkoord gaat met de licentie."
 
-#: finishopenidlogin.php:52
-#: openidsettings.php:208
-msgid "Something weird happened."
-msgstr "Er is iets vreemds gebeurd."
-
-#: finishopenidlogin.php:66
+#: finishopenidlogin.php:65
 #, php-format
 msgid "This is the first time you've logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one."
 msgstr "Dit is de eerste keer dat u aameldt bij %s en uw OpenID moet gekoppeld worden aan uw lokale gebruiker. U kunt een nieuwe gebruiker aanmaken of koppelen met uw bestaande gebruiker als u die al hebt."
 
-#: finishopenidlogin.php:72
+#: finishopenidlogin.php:71
 msgid "OpenID Account Setup"
 msgstr "Instellingen OpenID"
 
-#: finishopenidlogin.php:97
+#: finishopenidlogin.php:101
 msgid "Create new account"
 msgstr "Nieuwe gebruiker aanmaken"
 
-#: finishopenidlogin.php:99
+#: finishopenidlogin.php:103
 msgid "Create a new user with this nickname."
 msgstr "Nieuwe gebruiker met deze naam aanmaken."
 
-#: finishopenidlogin.php:102
+#: finishopenidlogin.php:106
 msgid "New nickname"
 msgstr "Nieuwe gebruiker"
 
-#: finishopenidlogin.php:104
+#: finishopenidlogin.php:108
 msgid "1-64 lowercase letters or numbers, no punctuation or spaces"
 msgstr "1-64 kleine letters of getallen; geen leestekens of spaties"
 
-#: finishopenidlogin.php:114
-msgid "My text and files are available under "
-msgstr "Mijn teksten en bestanden zijn beschikbaar onder"
-
-#: finishopenidlogin.php:117
-msgid " except this private data: password, email address, IM address, phone number."
-msgstr "behalve de volgende privégegevens: wachtwoord, e-mailadres, IM-adres, telefoonnummer."
-
-#: finishopenidlogin.php:121
+#: finishopenidlogin.php:130
 msgid "Create"
 msgstr "Aanmaken"
 
-#: finishopenidlogin.php:126
+#: finishopenidlogin.php:135
 msgid "Connect existing account"
 msgstr "Koppelen met bestaande gebruiker"
 
-#: finishopenidlogin.php:128
+#: finishopenidlogin.php:137
 msgid "If you already have an account, login with your username and password to connect it to your OpenID."
 msgstr "Als u al een gebruiker hebt, meld u dan aan met uw gebruikersnaam en wachtwoord om de gebruiker te koppelen met uw OpenID."
 
-#: finishopenidlogin.php:131
+#: finishopenidlogin.php:140
 msgid "Existing nickname"
 msgstr "Bestaande gebruiker"
 
-#: finishopenidlogin.php:134
+#: finishopenidlogin.php:143
 msgid "Password"
 msgstr "Wachtwoord"
 
-#: finishopenidlogin.php:137
+#: finishopenidlogin.php:146
 msgid "Connect"
 msgstr "Koppelen"
 
-#: finishopenidlogin.php:215
-#: finishopenidlogin.php:224
+#: finishopenidlogin.php:158
+#: finishaddopenid.php:88
+msgid "OpenID authentication cancelled."
+msgstr "De authenticatie via OpenID is afgebroken."
+
+#: finishopenidlogin.php:162
+#: finishaddopenid.php:92
+#, php-format
+msgid "OpenID authentication failed: %s"
+msgstr "De authenticatie via OpenID is mislukt: %s"
+
+#: finishopenidlogin.php:227
+#: finishopenidlogin.php:236
 msgid "Registration not allowed."
 msgstr "Registreren is niet mogelijk."
 
-#: finishopenidlogin.php:231
+#: finishopenidlogin.php:243
 msgid "Not a valid invitation code."
 msgstr "De uitnodigingscode is niet geldig."
 
-#: finishopenidlogin.php:241
+#: finishopenidlogin.php:253
 msgid "Nickname must have only lowercase letters and numbers and no spaces."
 msgstr "De gebruikersnaam mag alleen uit kleine letters en cijfers bestaan, en geen spaties bevatten."
 
-#: finishopenidlogin.php:246
+#: finishopenidlogin.php:258
 msgid "Nickname not allowed."
 msgstr "Deze gebruikersnaam is niet toegestaan."
 
-#: finishopenidlogin.php:251
+#: finishopenidlogin.php:263
 msgid "Nickname already in use. Try another one."
 msgstr "Deze gebruikersnaam wordt al gebruikt. Kies een andere."
 
-#: finishopenidlogin.php:258
-#: finishopenidlogin.php:338
+#: finishopenidlogin.php:270
+#: finishopenidlogin.php:350
 msgid "Stored OpenID not found."
 msgstr "Het opgeslagen OpenID is niet aangetroffen."
 
-#: finishopenidlogin.php:267
+#: finishopenidlogin.php:279
 msgid "Creating new account for OpenID that already has a user."
 msgstr "Bezig met het aanmaken van een gebruiker voor OpenID die al een gebruiker heeft."
 
-#: finishopenidlogin.php:327
+#: finishopenidlogin.php:339
 msgid "Invalid username or password."
 msgstr "Ongeldige gebruikersnaam of wachtwoord."
 
-#: finishopenidlogin.php:345
+#: finishopenidlogin.php:357
 msgid "Error connecting user to OpenID."
 msgstr "Fout bij het koppelen met OpenID."
 
-#: openid.php:141
-msgid "Cannot instantiate OpenID consumer object."
-msgstr "Het was niet mogelijk een OpenID-object aan te maken."
-
-#: openid.php:151
-msgid "Not a valid OpenID."
-msgstr "Geen geldige OpenID."
-
-#: openid.php:153
-#, php-format
-msgid "OpenID failure: %s"
-msgstr "OpenID-fout: %s"
-
-#: openid.php:180
-#, php-format
-msgid "Could not redirect to server: %s"
-msgstr "Het was niet mogelijk door te verwijzen naar de server: %s"
-
-#: openid.php:198
-#, php-format
-msgid "Could not create OpenID form: %s"
-msgstr "Het was niet mogelijk het OpenID-formulier aan te maken: %s"
-
-#: openid.php:214
-msgid "This form should automatically submit itself. If not, click the submit button to go to your OpenID provider."
-msgstr "Dit formulier hoort zichzelf automatisch op te slaan. Als dat niet gebeurt, klik dan op de knop \"Aanmelden\" om naar uw OpenID-provider te gaan."
-
-#: openid.php:246
-msgid "Error saving the profile."
-msgstr "Fout bij het opslaan van het profiel."
-
-#: openid.php:257
-msgid "Error saving the user."
-msgstr "Fout bij het opslaan van de gebruiker."
-
-#: openid.php:277
-msgid "OpenID Auto-Submit"
-msgstr "OpenID automatisch opslaan"
-
-#: openidlogin.php:66
+#: openidlogin.php:68
 #, php-format
 msgid "For security reasons, please re-login with your [OpenID](%%doc.openid%%) before changing your settings."
 msgstr "Om veiligheidsreden moet u opnieuw aanmelden met uw [OpenID](%%doc.openid%%) voordat u uw instellingen kunt wijzigen."
 
-#: openidlogin.php:70
+#: openidlogin.php:72
 #, php-format
 msgid "Login with an [OpenID](%%doc.openid%%) account."
 msgstr "Aanmelden met een [OpenID](%%doc.openid%%)-gebruiker."
 
-#: openidlogin.php:112
-msgid "OpenID login"
+#: openidlogin.php:97
+#: finishaddopenid.php:170
+msgid "OpenID Login"
 msgstr "Aanmelden via OpenID"
 
-#: openidlogin.php:117
-#: openidsettings.php:107
-msgid "OpenID URL"
-msgstr "OpenID-URL"
+#: openidlogin.php:114
+msgid "OpenID login"
+msgstr "Aanmelden via OpenID"
 
-#: openidlogin.php:119
+#: openidlogin.php:121
 msgid "Your OpenID URL"
 msgstr "Uw OpenID-URL"
 
-#: openidlogin.php:122
+#: openidlogin.php:124
 msgid "Remember me"
 msgstr "Aanmeldgegevens onthouden"
 
-#: openidlogin.php:123
+#: openidlogin.php:125
 msgid "Automatically login in the future; not for shared computers!"
 msgstr "In het vervolg automatisch aanmelden. Niet gebruiken op gedeelde computers!"
 
-#: openidlogin.php:127
+#: openidlogin.php:129
 msgid "Login"
 msgstr "Aanmelden"
 
-#: OpenIDPlugin.php:123
-#: OpenIDPlugin.php:135
-msgid "OpenID"
-msgstr "OpenID"
-
-#: OpenIDPlugin.php:124
-msgid "Login or register with OpenID"
-msgstr "Aanmelden of registreren met OpenID"
-
-#: OpenIDPlugin.php:136
-msgid "Add or remove OpenIDs"
-msgstr "OpenID's toevoegen of verwijderen"
-
-#: OpenIDPlugin.php:324
-msgid "Use <a href=\"http://openid.net/\">OpenID</a> to login to the site."
-msgstr "Gebruik <a href=\"http://openid.net/\">OpenID</a> om aan te melden bij de site."
-
-#: openidserver.php:106
-#, php-format
-msgid "You are not authorized to use the identity %s."
-msgstr "U mag de identiteit %s niet gebruiken."
-
-#: openidserver.php:126
-msgid "Just an OpenID provider. Nothing to see here, move along..."
-msgstr "Gewoon een OpenID-provider. Niets te zien hier..."
-
-#: openidsettings.php:59
-msgid "OpenID settings"
-msgstr "OpenID-instellingen"
-
-#: openidsettings.php:70
-#, php-format
-msgid "[OpenID](%%doc.openid%%) lets you log into many sites with the same user account. Manage your associated OpenIDs from here."
-msgstr "Met [OpenID](%%doc.openid%%) kunt u aanmelden bij veel websites met dezelfde gebruiker. U kunt hier uw gekoppelde OpenID's beheren."
-
-#: openidsettings.php:99
-msgid "Add OpenID"
-msgstr "OpenID toevoegen"
-
-#: openidsettings.php:102
-msgid "If you want to add an OpenID to your account, enter it in the box below and click \"Add\"."
-msgstr "Als u een OpenID aan uw gebruiker wilt toevoegen, voer deze dan hieronder in en klik op \"Toevoegen\"."
-
-#: openidsettings.php:117
-msgid "Add"
-msgstr "Toevoegen"
-
-#: openidsettings.php:129
-msgid "Remove OpenID"
-msgstr "OpenID verwijderen"
-
-#: openidsettings.php:134
-msgid "Removing your only OpenID would make it impossible to log in! If you need to remove it, add another OpenID first."
-msgstr "Door uw enige OpenID te verwijderen zou het niet meer mogelijk zijn om aan te melden. Als u het wilt verwijderen, voeg dan eerst een andere OpenID toe."
-
-#: openidsettings.php:149
-msgid "You can remove an OpenID from your account by clicking the button marked \"Remove\"."
-msgstr "U kunt een OpenID van uw gebruiker verwijderen door te klikken op de knop \"Verwijderen\"."
-
-#: openidsettings.php:172
-msgid "Remove"
-msgstr "Verwijderen"
-
-#: openidsettings.php:228
-msgid "No such OpenID."
-msgstr "De OpenID bestaat niet."
-
-#: openidsettings.php:233
-msgid "That OpenID does not belong to you."
-msgstr "Die OpenID is niet van u."
-
-#: openidsettings.php:237
-msgid "OpenID removed."
-msgstr "OpenID verwijderd."
-
 #: openidtrust.php:51
 msgid "OpenID Identity Verification"
 msgstr "OpenID-identiteitscontrole"
@@ -325,16 +361,35 @@ msgstr "OpenID-identiteitscontrole"
 msgid "This page should only be reached during OpenID processing, not directly."
 msgstr "Deze pagina hoort alleen bezocht te worden tijdens het verwerken van een OpenID, en niet direct."
 
-#: openidtrust.php:118
+#: openidtrust.php:117
 #, php-format
 msgid "%s  has asked to verify your identity. Click Continue to verify your identity and login without creating a new password."
 msgstr "%s heeft gevraagd uw identiteit te bevestigen. Klik op \"Doorgaan\" om uw indentiteit te controleren en aan te melden zonder een wachtwoord te hoeven invoeren."
 
-#: openidtrust.php:136
+#: openidtrust.php:135
 msgid "Continue"
 msgstr "Doorgaan"
 
-#: openidtrust.php:137
+#: openidtrust.php:136
 msgid "Cancel"
 msgstr "Annuleren"
 
+#: finishaddopenid.php:67
+msgid "Not logged in."
+msgstr "Niet aangemeld."
+
+#: finishaddopenid.php:112
+msgid "You already have this OpenID!"
+msgstr "U hebt deze OpenID al!"
+
+#: finishaddopenid.php:114
+msgid "Someone else already has this OpenID."
+msgstr "Iemand anders gebruikt deze OpenID al."
+
+#: finishaddopenid.php:126
+msgid "Error connecting user."
+msgstr "Fout bij het verbinden met de gebruiker."
+
+#: finishaddopenid.php:131
+msgid "Error updating profile"
+msgstr "Fout bij het bijwerken van het profiel."
index 4ec336e1c3d95fb3b421db1e25dbbee7c770aae4..68b5c29e2461386b42f14e4940f47ca714abfadb 100644 (file)
@@ -134,6 +134,7 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
     $consumer = oid_consumer();
 
     if (!$consumer) {
+        // TRANS: OpenID plugin server error.
         common_server_error(_m('Cannot instantiate OpenID consumer object.'));
         return false;
     }
@@ -144,8 +145,11 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
 
     // Handle failure status return values.
     if (!$auth_request) {
+        // TRANS: OpenID plugin message. Given when an OpenID is not valid.
         return _m('Not a valid OpenID.');
     } else if (Auth_OpenID::isFailure($auth_request)) {
+        // TRANS: OpenID plugin server error. Given when the OpenID authentication request fails.
+        // TRANS: %s is the failure message.
         return sprintf(_m('OpenID failure: %s'), $auth_request->message);
     }
 
@@ -173,6 +177,8 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
                                                    $immediate);
         if (!$redirect_url) {
         } else if (Auth_OpenID::isFailure($redirect_url)) {
+            // TRANS: OpenID plugin server error. Given when the OpenID authentication request cannot be redirected.
+            // TRANS: %s is the failure message.
             return sprintf(_m('Could not redirect to server: %s'), $redirect_url->message);
         } else {
             common_redirect($redirect_url, 303);
@@ -191,6 +197,8 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
         // Display an error if the form markup couldn't be generated;
         // otherwise, render the HTML.
         if (Auth_OpenID::isFailure($form_html)) {
+            // TRANS: OpenID plugin server error if the form markup could not be generated.
+            // TRANS: %s is the failure message.
             common_server_error(sprintf(_m('Could not create OpenID form: %s'), $form_html->message));
         } else {
             $action = new AutosubmitAction(); // see below
@@ -207,6 +215,7 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
 function _oid_print_instructions()
 {
     common_element('div', 'instructions',
+                   // TRANS: OpenID plugin user instructions.
                    _m('This form should automatically submit itself. '.
                       'If not, click the submit button to go to your '.
                       'OpenID provider.'));
@@ -239,6 +248,7 @@ function oid_update_user(&$user, &$sreg)
     # XXX save timezone if it's passed
 
     if (!$profile->update($orig_profile)) {
+        // TRANS: OpenID plugin server error.
         common_server_error(_m('Error saving the profile.'));
         return false;
     }
@@ -250,6 +260,7 @@ function oid_update_user(&$user, &$sreg)
     }
 
     if (!$user->update($orig_user)) {
+        // TRANS: OpenID plugin server error.
         common_server_error(_m('Error saving the user.'));
         return false;
     }
@@ -279,6 +290,7 @@ function oid_assert_allowed($url)
                     return;
                 }
             }
+            // TRANS: OpenID plugin client exception (403).
             throw new ClientException(_m("Unauthorized URL used for OpenID login."), 403);
         }
     }
@@ -299,6 +311,7 @@ class AutosubmitAction extends Action
 
     function title()
     {
+        // TRANS: Title
         return _m('OpenID Login Submission');
     }
 
@@ -309,9 +322,11 @@ class AutosubmitAction extends Action
         $this->element('img', array('src' => Theme::path('images/icons/icon_processing.gif', 'base'),
                                     // for some reason the base CSS sets <img>s as block display?!
                                     'style' => 'display: inline'));
+        // TRANS: OpenID plugin message used while requesting authorization user's OpenID login provider.
         $this->text(_m('Requesting authorization from your login provider...'));
         $this->raw('</p>');
         $this->raw('<p style="margin-top: 60px; font-style: italic">');
+        // TRANS: OpenID plugin message. User instruction while requesting authorization user's OpenID login provider.
         $this->text(_m('If you are not redirected to your login provider in a few seconds, try pushing the button below.'));
         $this->raw('</p>');
         $this->raw($this->form_html);
index 2a743672cf68d2bfb59e4bcfa61c0239cccd489c..ec05daeb180efd15bc147badf0444856aaa72df5 100644 (file)
@@ -27,6 +27,7 @@ class OpenidloginAction extends Action
     {
         parent::handle($args);
         if (common_is_real_login()) {
+            // TRANS: Client error message trying to log on with OpenID while already logged on.
             $this->clientError(_m('Already logged in.'));
         } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
             $openid_url = $this->trimmed('openid_url');
@@ -36,6 +37,7 @@ class OpenidloginAction extends Action
             # CSRF protection
             $token = $this->trimmed('token');
             if (!$token || $token != common_session_token()) {
+                // TRANS: Message given when there is a problem with the user's session token.
                 $this->showForm(_m('There was a problem with your session token. Try again, please.'), $openid_url);
                 return;
             }
@@ -65,10 +67,14 @@ class OpenidloginAction extends Action
             common_get_returnto()) {
             // rememberme logins have to reauthenticate before
             // changing any profile settings (cookie-stealing protection)
+            // TRANS: OpenID plugin message. Rememberme logins have to reauthenticate before changing any profile settings.
+            // TRANS: "OpenID" is the display text for a link with URL "(%%doc.openid%%)".
             return _m('For security reasons, please re-login with your ' .
                      '[OpenID](%%doc.openid%%) ' .
                      'before changing your settings.');
         } else {
+            // TRANS: OpenID plugin message.
+            // TRANS: "OpenID" is the display text for a link with URL "(%%doc.openid%%)".
             return _m('Login with an [OpenID](%%doc.openid%%) account.');
         }
     }
@@ -94,6 +100,7 @@ class OpenidloginAction extends Action
 
     function title()
     {
+        // TRANS: OpenID plugin message. Title.
         return _m('OpenID Login');
     }
 
@@ -111,22 +118,28 @@ class OpenidloginAction extends Action
                                            'class' => 'form_settings',
                                            'action' => $formaction));
         $this->elementStart('fieldset');
+        // TRANS: OpenID plugin logon form legend.
         $this->element('legend', null, _m('OpenID login'));
         $this->hidden('token', common_session_token());
 
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
+        // TRANS: OpenID plugin logon form field label.
         $this->input('openid_url', _m('OpenID URL'),
                      $this->openid_url,
+                     // TRANS: OpenID plugin logon form field instructions.
                      _m('Your OpenID URL'));
         $this->elementEnd('li');
         $this->elementStart('li', array('id' => 'settings_rememberme'));
+        // TRANS: OpenID plugin logon form checkbox label for setting to put the OpenID information in a cookie.
         $this->checkbox('rememberme', _m('Remember me'), false,
+                        // TRANS: OpenID plugin logon form field instructions.
                         _m('Automatically login in the future; ' .
                            'not for shared computers!'));
         $this->elementEnd('li');
         $this->elementEnd('ul');
-        $this->submit('submit', _m('Login'));
+        // TRANS: OpenID plugin logon form button label to start logon with the data provided in the logon form.
+        $this->submit('submit', _m('BUTTON', 'Login'));
         $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
index afbca553f5e42799558ba5635bbf5ef3d6334adb..f7e3a45f2072dabb082d32052fb604e6ab362bcb 100644 (file)
@@ -71,7 +71,7 @@ class OpenidserverAction extends Action
                 }else{
                     /* Go log in, and then come back. */
                     common_set_returnto($_SERVER['REQUEST_URI']);
-                    common_redirect(common_local_url('login'));
+                    common_redirect(common_local_url('login'), 303);
                     return;
                 }
             }else if(common_profile_url($user->nickname) == $request->identity || $request->idSelect()){
@@ -91,7 +91,7 @@ class OpenidserverAction extends Action
                         $_SESSION['openid_allow_url'] = $allowResponse->encodeToUrl();
                         $_SESSION['openid_deny_url'] = $denyResponse->encodeToUrl();
                         //ask the user to trust this trust root
-                        common_redirect(common_local_url('openidtrust'));
+                        common_redirect(common_local_url('openidtrust'), 303);
                         return;
                     }
                 }else{
@@ -103,6 +103,7 @@ class OpenidserverAction extends Action
                 $response = $this->generateDenyResponse($request);
             } else {
                 //invalid
+                // TRANS: OpenID plugin client error given trying to add an unauthorised OpenID to a user (403).
                 $this->clientError(sprintf(_m('You are not authorized to use the identity %s.'),$request->identity),$code=403);
             }
         } else {
@@ -123,6 +124,7 @@ class OpenidserverAction extends Action
             }
             $this->raw($response->body);
         }else{
+            // TRANS: OpenID plugin client error given when not getting a response for a given OpenID provider (500).
             $this->clientError(_m('Just an OpenID provider. Nothing to see here, move along...'),$code=500);
         }
     }
diff --git a/plugins/PostDebug/locale/PostDebug.pot b/plugins/PostDebug/locale/PostDebug.pot
new file mode 100644 (file)
index 0000000..b7107d4
--- /dev/null
@@ -0,0 +1,21 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: PostDebugPlugin.php:58
+msgid "Debugging tool to record request details on POST."
+msgstr ""
index 8f8434a85d188baa3d8d6350b9edf7e89ea9f5ac..bc0e814f2cee1c109ed43e56ef80adf65e76884a 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
diff --git a/plugins/PtitUrl/locale/PtitUrl.pot b/plugins/PtitUrl/locale/PtitUrl.pot
new file mode 100644 (file)
index 0000000..a888f80
--- /dev/null
@@ -0,0 +1,22 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: PtitUrlPlugin.php:67
+#, php-format
+msgid "Uses <a href=\"http://%1$s/\">%1$s</a> URL-shortener service."
+msgstr ""
diff --git a/plugins/RSSCloud/locale/RSSCloud.pot b/plugins/RSSCloud/locale/RSSCloud.pot
new file mode 100644 (file)
index 0000000..4078cc7
--- /dev/null
@@ -0,0 +1,24 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: RSSCloudPlugin.php:260
+msgid ""
+"The RSSCloud plugin enables your StatusNet instance to publish real-time "
+"updates for profile RSS feeds using the <a href=\"http://rsscloud.org/"
+"\">RSSCloud protocol</a>\"."
+msgstr ""
diff --git a/plugins/Recaptcha/locale/Recaptcha.pot b/plugins/Recaptcha/locale/Recaptcha.pot
new file mode 100644 (file)
index 0000000..6611ff6
--- /dev/null
@@ -0,0 +1,23 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: RecaptchaPlugin.php:97
+msgid ""
+"Uses <a href=\"http://recaptcha.org/\">Recaptcha</a> service to add a  "
+"captcha to the registration page."
+msgstr ""
diff --git a/plugins/RegisterThrottle/locale/RegisterThrottle.pot b/plugins/RegisterThrottle/locale/RegisterThrottle.pot
new file mode 100644 (file)
index 0000000..834f5fd
--- /dev/null
@@ -0,0 +1,29 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: RegisterThrottlePlugin.php:122 RegisterThrottlePlugin.php:161
+msgid "Cannot find IP address."
+msgstr ""
+
+#: RegisterThrottlePlugin.php:167
+msgid "Cannot find user after successful registration."
+msgstr ""
+
+#: RegisterThrottlePlugin.php:200
+msgid "Throttles excessive registration from a single IP."
+msgstr ""
index 49ac4f6f4d9df6ca7a2e36f13008da69b50b0ee7..c8953a1fa36f29bcbd487f1d39e4b48eb3908cea 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-10 10:05-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
diff --git a/plugins/ReverseUsernameAuthentication/locale/ReverseUsernameAuthentication.pot b/plugins/ReverseUsernameAuthentication/locale/ReverseUsernameAuthentication.pot
new file mode 100644 (file)
index 0000000..6fa18c4
--- /dev/null
@@ -0,0 +1,24 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ReverseUsernameAuthenticationPlugin.php:67
+msgid ""
+"The Reverse Username Authentication plugin allows for StatusNet to handle "
+"authentication by checking if the provided password is the same as the "
+"reverse of the username."
+msgstr ""
index a52c4ec01c03ba6eaf1fda8204b3aac6e3c32e38..bd21dd3c4ce0158fff8910bc638221ee2a28892a 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,26 +17,20 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
 
-#: hello.php:115 SamplePlugin.php:266
-msgid "Hello"
+#: User_greeting_count.php:163
+#, php-format
+msgid "Could not save new greeting count for %d"
 msgstr ""
 
-#: hello.php:117 hello.php:141
+#: User_greeting_count.php:176
 #, php-format
-msgid "Hello, %s"
+msgid "Could not increment greeting count for %d"
 msgstr ""
 
-#: hello.php:138
-msgid "Hello, stranger!"
+#: SamplePlugin.php:266 hello.php:115
+msgid "Hello"
 msgstr ""
 
-#: hello.php:143
-#, php-format
-msgid "I have greeted you %d time."
-msgid_plural "I have greeted you %d times."
-msgstr[0] ""
-msgstr[1] ""
-
 #: SamplePlugin.php:266
 msgid "A warm greeting"
 msgstr ""
@@ -45,12 +39,18 @@ msgstr ""
 msgid "A sample plugin to show basics of development for new hackers."
 msgstr ""
 
-#: User_greeting_count.php:163
+#: hello.php:117 hello.php:141
 #, php-format
-msgid "Could not save new greeting count for %d"
+msgid "Hello, %s"
 msgstr ""
 
-#: User_greeting_count.php:176
-#, php-format
-msgid "Could not increment greeting count for %d"
+#: hello.php:138
+msgid "Hello, stranger!"
 msgstr ""
+
+#: hello.php:143
+#, php-format
+msgid "I have greeted you %d time."
+msgid_plural "I have greeted you %d times."
+msgstr[0] ""
+msgstr[1] ""
diff --git a/plugins/SimpleUrl/locale/SimpleUrl.pot b/plugins/SimpleUrl/locale/SimpleUrl.pot
new file mode 100644 (file)
index 0000000..e3c241d
--- /dev/null
@@ -0,0 +1,22 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: SimpleUrlPlugin.php:58
+#, php-format
+msgid "Uses <a href=\"http://%1$s/\">%1$s</a> URL-shortener service."
+msgstr ""
diff --git a/plugins/SpotifyPlugin.php b/plugins/SpotifyPlugin.php
new file mode 100644 (file)
index 0000000..e7a5a53
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+  *
+ * Plugin to create pretty Spotify URLs
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Nick Holliday <n.g.holliday@gmail.com>
+ * @copyright Nick Holliday
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ *
+ * @see      Event
+ */
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+define('SPOTIFYPLUGIN_VERSION', '0.1');
+
+/**
+ * Plugin to create pretty Spotify URLs
+ *
+ * The Spotify API is called before the notice is saved to gather artist and track information.
+ *
+ * @category  Plugin
+ * @package   StatusNet
+ * @author    Nick Holliday <n.g.holliday@gmail.com>
+ * @copyright Nick Holliday
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ *
+ * @see       Event
+ */
+
+class SpotifyPlugin extends Plugin
+{
+
+    function __construct()
+    {
+        parent::__construct();
+    }
+
+    function onStartNoticeSave($notice)
+    {
+        $notice->rendered = preg_replace_callback('/spotify:[a-z]{5,6}:[a-z0-9]{22}/i',
+                                                  "renderSpotifyURILink",
+                                                  $notice->rendered);
+
+        $notice->rendered = preg_replace_callback('/<a href="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" title="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" rel="external">http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}<\/a>/i',
+                                                  "renderSpotifyHTTPLink",
+                                                  $notice->rendered);
+
+        return true;
+    }
+
+    function userAgent()
+    {
+        return 'SpotifyPlugin/'.SPOTIFYPLUGIN_VERSION .
+               ' StatusNet/' . STATUSNET_VERSION;
+    }
+}
+
+function doSpotifyLookup($uri, $isArtist)
+{
+    $request = HTTPClient::start();
+    $response = $request->get('http://ws.spotify.com/lookup/1/?uri=' . $uri);
+    if ($response->isOk()) {
+        $xml = simplexml_load_string($response->getBody());
+
+        if($isArtist)
+            return $xml->name;
+        else
+            return $xml->artist->name . ' - ' . $xml->name;
+    }
+}
+
+function renderSpotifyURILink($match)
+{
+    $isArtist = false;
+    if(preg_match('/artist/', $match[0]) > 0) $isArtist = true;
+
+    $name = doSpotifyLookup($match[0], $isArtist);
+    return "<a href=\"{$match[0]}\">" . $name . "</a>";
+}
+
+function renderSpotifyHTTPLink($match)
+{
+    $match[0] = preg_replace('/<a href="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" title="http:\/\/open.spotify.com\/[a-z]{5,6}\/[a-z0-9]{22}" rel="external">http:\/\/open.spotify.com\//i', 'spotify:', $match[0]);
+    $match[0] = preg_replace('/<\/a>/', '', $match[0]);
+    $match[0] = preg_replace('/\//', ':', $match[0]);
+
+    $isArtist = false;
+    if(preg_match('/artist/', $match[0]) > 0) $isArtist = true;
+
+    $name = doSpotifyLookup($match[0], $isArtist);
+    return "<a href=\"{$match[0]}\">" . $name . "</a>";
+}
diff --git a/plugins/TabFocus/locale/TabFocus.pot b/plugins/TabFocus/locale/TabFocus.pot
new file mode 100644 (file)
index 0000000..3b0e3c2
--- /dev/null
@@ -0,0 +1,24 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: TabFocusPlugin.php:54
+msgid ""
+"TabFocus changes the notice form behavior so that, while in the text area, "
+"pressing the tab key focuses the \"Send\" button, matching the behavor of "
+"Twitter."
+msgstr ""
diff --git a/plugins/TightUrl/locale/TightUrl.pot b/plugins/TightUrl/locale/TightUrl.pot
new file mode 100644 (file)
index 0000000..10f59a1
--- /dev/null
@@ -0,0 +1,22 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: TightUrlPlugin.php:68
+#, php-format
+msgid "Uses <a href=\"http://%1$s/\">%1$s</a> URL-shortener service."
+msgstr ""
index eff1255799675bc8210fb6463d3586123c6ae8ec..c7ac8053ca3b9a393e16c6011fbb3d2f77d35e16 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-01 14:58-0800\n"
+"POT-Creation-Date: 2010-04-29 23:39+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,11 +16,11 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: twitter.php:320
+#: twitter.php:342
 msgid "Your Twitter bridge has been disabled."
 msgstr ""
 
-#: twitter.php:324
+#: twitter.php:346
 #, php-format
 msgid ""
 "Hi, %1$s. We're sorry to inform you that your link to Twitter has been "
@@ -36,28 +36,97 @@ msgid ""
 "%3$s\n"
 msgstr ""
 
-#: twitterauthorization.php:181 twitterauthorization.php:229
-msgid "Couldn't link your Twitter account."
+#: TwitterBridgePlugin.php:155 TwitterBridgePlugin.php:178
+#: TwitterBridgePlugin.php:291 twitteradminpanel.php:54
+msgid "Twitter"
 msgstr ""
 
-#: twitterauthorization.php:201
-msgid "Couldn't link your Twitter account: oauth_token mismatch."
+#: TwitterBridgePlugin.php:156
+msgid "Login or register using Twitter"
 msgstr ""
 
-#: TwitterBridgePlugin.php:114
-msgid "Twitter"
+#: TwitterBridgePlugin.php:179
+msgid "Twitter integration options"
 msgstr ""
 
-#: TwitterBridgePlugin.php:115
-msgid "Twitter integration options"
+#: TwitterBridgePlugin.php:292
+msgid "Twitter bridge configuration"
 msgstr ""
 
-#: TwitterBridgePlugin.php:207
+#: TwitterBridgePlugin.php:317
 msgid ""
 "The Twitter \"bridge\" plugin allows you to integrate your StatusNet "
 "instance with <a href=\"http://twitter.com/\">Twitter</a>."
 msgstr ""
 
+#: twitteradminpanel.php:65
+msgid "Twitter bridge settings"
+msgstr ""
+
+#: twitteradminpanel.php:148
+msgid "Invalid consumer key. Max length is 255 characters."
+msgstr ""
+
+#: twitteradminpanel.php:154
+msgid "Invalid consumer secret. Max length is 255 characters."
+msgstr ""
+
+#: twitteradminpanel.php:207
+msgid "Twitter application settings"
+msgstr ""
+
+#: twitteradminpanel.php:213
+msgid "Consumer key"
+msgstr ""
+
+#: twitteradminpanel.php:214
+msgid "Consumer key assigned by Twitter"
+msgstr ""
+
+#: twitteradminpanel.php:222
+msgid "Consumer secret"
+msgstr ""
+
+#: twitteradminpanel.php:223
+msgid "Consumer secret assigned by Twitter"
+msgstr ""
+
+#: twitteradminpanel.php:240
+msgid "Integration source"
+msgstr ""
+
+#: twitteradminpanel.php:241
+msgid "Name of your Twitter application"
+msgstr ""
+
+#: twitteradminpanel.php:253
+msgid "Options"
+msgstr ""
+
+#: twitteradminpanel.php:260
+msgid "Enable \"Sign-in with Twitter\""
+msgstr ""
+
+#: twitteradminpanel.php:262
+msgid "Allow users to login with their Twitter credentials"
+msgstr ""
+
+#: twitteradminpanel.php:268
+msgid "Enable Twitter import"
+msgstr ""
+
+#: twitteradminpanel.php:270
+msgid "Allow users to import their Twitter friends' timelines"
+msgstr ""
+
+#: twitterauthorization.php:181 twitterauthorization.php:229
+msgid "Couldn't link your Twitter account."
+msgstr ""
+
+#: twitterauthorization.php:201
+msgid "Couldn't link your Twitter account: oauth_token mismatch."
+msgstr ""
+
 #: twittersettings.php:59
 msgid "Twitter settings"
 msgstr ""
diff --git a/scripts/apidocs.config b/scripts/apidocs.config
new file mode 100644 (file)
index 0000000..fdbe35b
--- /dev/null
@@ -0,0 +1,1551 @@
+# Doxyfile 1.6.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = "StatusNet REST API"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../apidocs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = NO
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = NO
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = NO
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = NO
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = NO
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = ../actions ../lib
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = api*.php
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = *Action Api* if*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+#  plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be implemented using a PHP enabled web server instead of at the web client using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server based approach is that it scales better to large projects and allows full text search. The disadvances is that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/scripts/docgen.php b/scripts/docgen.php
new file mode 100755 (executable)
index 0000000..ac0a5c8
--- /dev/null
@@ -0,0 +1,114 @@
+#!/usr/bin/env php
+<?php
+
+$shortoptions = '';
+$longoptions = array('plugin=');
+
+
+$helptext = <<<ENDOFHELP
+Build HTML documentation from doc comments in source.
+
+Usage: docgen.php [options] output-directory
+Options:
+
+  --plugin=...     build docs for given plugin instead of core
+
+
+ENDOFHELP;
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+set_include_path(INSTALLDIR . DIRECTORY_SEPARATOR . 'extlib' . PATH_SEPARATOR . get_include_path());
+
+$pattern = "*.php *.inc";
+$exclude = 'config.php */extlib/* */local/* */plugins/* */scripts/*';
+$plugin = false;
+
+require_once 'Console/Getopt.php';
+$parser = new Console_Getopt();
+$result = $parser->getopt($_SERVER['argv'], $shortoptions, $longoptions);
+if (PEAR::isError($result)) {
+    print $result->getMessage() . "\n";
+    exit(1);
+}
+list($options, $args) = $result;
+
+foreach ($options as $option) {
+    $arg = $option[0];
+    if ($arg == '--plugin') {
+        $plugin = $options[1];
+    } else if ($arg == 'h' || $arg == '--help') {
+        print $helptext;
+        exit(0);
+    }
+}
+
+if (isset($args[0])) {
+    $outdir = $args[0];
+    if (!is_dir($outdir)) {
+        echo "Output directory $outdir is not a directory.\n";
+        exit(1);
+    }
+} else {
+    print $helptext;
+    exit(1);
+}
+
+if ($plugin) {
+    $exclude = "*/extlib/*";
+    $indir = INSTALLDIR . "/plugins/" . $plugin;
+    if (!is_dir($indir)) {
+        $indir = INSTALLDIR . "/plugins";
+        $filename = "{$plugin}Plugin.php";
+        if (!file_exists("$indir/$filename")) {
+            echo "Can't find plugin $plugin.\n";
+            exit(1);
+        } else {
+            $pattern = $filename;
+        }
+    }
+} else {
+    $indir = INSTALLDIR;
+}
+
+function getVersion()
+{
+    // define('STATUSNET_VERSION', '0.9.1');
+    $source = file_get_contents(INSTALLDIR . '/lib/common.php');
+    if (preg_match('/^\s*define\s*\(\s*[\'"]STATUSNET_VERSION[\'"]\s*,\s*[\'"](.*)[\'"]\s*\)\s*;/m', $source, $matches)) {
+        return $matches[1];
+    }
+    return 'unknown';
+}
+
+
+$replacements = array(
+    '%%version%%' => getVersion(),
+    '%%indir%%' => $indir,
+    '%%pattern%%' => $pattern,
+    '%%outdir%%' => $outdir,
+    '%%htmlout%%' => $outdir,
+    '%%exclude%%' => $exclude,
+);
+
+var_dump($replacements);
+
+$template = file_get_contents(dirname(__FILE__) . '/doxygen.tmpl');
+$template = strtr($template, $replacements);
+
+$templateFile = tempnam(sys_get_temp_dir(), 'statusnet-doxygen');
+file_put_contents($templateFile, $template);
+
+$cmd = "doxygen " . escapeshellarg($templateFile);
+
+$retval = 0;
+passthru($cmd, $retval);
+
+if ($retval == 0) {
+    echo "Done!\n";
+    unlink($templateFile);
+    exit(0);
+} else {
+    echo "Failed! Doxygen config left in $templateFile\n";
+    exit($retval);
+}
+
diff --git a/scripts/doxygen.tmpl b/scripts/doxygen.tmpl
new file mode 100644 (file)
index 0000000..15d03e3
--- /dev/null
@@ -0,0 +1,1516 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = StatusNet
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = %%version%%
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = %%outdir%%
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = %%indir%%
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = %%indir%%
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = %%pattern%%
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+# fixme for some reason this doesn't work?
+
+EXCLUDE                = config.php extlib local plugins scripts
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = %%exclude%%
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = %%htmlout%%
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = NO
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
index 45fe460a04f614bcab968ec856272542ea801b6c..89d937e9dd28d293418acd08377d68b74cd22dcf 100755 (executable)
@@ -31,7 +31,7 @@ define('LACONICA', true); // compatibility
 require_once(INSTALLDIR . '/lib/common.php');
 
 // Master StatusNet .pot file location (created by update_pot.sh)
-$statusnet_pot = INSTALLDIR . '/locale/statusnet.po';
+$statusnet_pot = INSTALLDIR . '/locale/statusnet.pot';
 
 set_time_limit(60);
 
@@ -98,7 +98,7 @@ foreach ($languages as $language) {
     $new_file = curl_get_file($file_url);
 
     if ($new_file === FALSE) {
-        echo "Couldn't retrieve .po file for $code: $file_url\n";
+        echo "Could not retrieve .po file for $code: $file_url\n";
         continue;
     }