]> git.mxchange.org Git - friendica.git/blobdiff - mod/admin.php
Events: Now with guid.
[friendica.git] / mod / admin.php
index 886d7a4d9df77e5af7b40663bbf4c43c9cd86bbc..454d59bb07b006c4d915c6e1ad420de2b8f43297 100644 (file)
@@ -1,15 +1,27 @@
 <?php
 
  /**
-  * Friendica admin
-  */
-require_once("include/remoteupdate.php");
+ * @file mod/admin.php
+ * 
+ * @brief Friendica admin
+ */
+
+
 require_once("include/enotify.php");
 require_once("include/text.php");
 
-
 /**
+ * @brief Process send data from the admin panels subpages
+ *
+ * This function acts as relais for processing the data send from the subpages
+ * of the admin panel. Depending on the 1st parameter of the url (argv[1])
+ * specialized functions are called to process the data from the subpages.
+ *
+ * The function itself does not return anything, but the subsequencely function
+ * return the HTML for the pages of the admin panel.
+ *
  * @param App $a
+ *
  */
 function admin_post(&$a){
 
@@ -26,7 +38,7 @@ function admin_post(&$a){
 
 
        // urls
-       if ($a->argc > 1){
+       if($a->argc > 1) {
                switch ($a->argv[1]){
                        case 'site':
                                admin_page_site_post($a);
@@ -35,26 +47,26 @@ function admin_post(&$a){
                                admin_page_users_post($a);
                                break;
                        case 'plugins':
-                               if ($a->argc > 2 &&
-                                       is_file("addon/".$a->argv[2]."/".$a->argv[2].".php")){
+                               if($a->argc > 2 &&
+                                       is_file("addon/".$a->argv[2]."/".$a->argv[2].".php")) {
                                                @include_once("addon/".$a->argv[2]."/".$a->argv[2].".php");
                                                if(function_exists($a->argv[2].'_plugin_admin_post')) {
                                                        $func = $a->argv[2].'_plugin_admin_post';
                                                        $func($a);
                                                }
                                }
-                               goaway($a->get_baseurl(true) . '/admin/plugins/' . $a->argv[2] );
+                               goaway('admin/plugins/'.$a->argv[2]);
                                return; // NOTREACHED
                                break;
                        case 'themes':
-                               if ($a->argc < 2) {
+                               if($a->argc < 2) {
                                        if(is_ajax()) return;
-                                       goaway($a->get_baseurl(true) . '/admin/' );
+                                       goaway('admin/');
                                        return;
                                }
 
                                $theme = $a->argv[2];
-                               if (is_file("view/theme/$theme/config.php")){
+                               if(is_file("view/theme/$theme/config.php")){
                                        function __call_theme_admin_post(&$a, $theme) {
                                                $orig_theme = $a->theme;
                                                $orig_page = $a->page;
@@ -66,7 +78,7 @@ function admin_post(&$a){
 
                                                $init = $theme."_init";
                                                if(function_exists($init)) $init($a);
-                                               if(function_exists("theme_admin_post")){
+                                               if(function_exists("theme_admin_post")) {
                                                        $admin_form = theme_admin_post($a);
                                                }
 
@@ -80,26 +92,39 @@ function admin_post(&$a){
                                info(t('Theme settings updated.'));
                                if(is_ajax()) return;
 
-                               goaway($a->get_baseurl(true) . '/admin/themes/' . $theme );
+                               goaway('admin/themes/'.$theme);
                                return;
                                break;
+                       case 'features':
+                               admin_page_features_post($a);
+                               break;
                        case 'logs':
                                admin_page_logs_post($a);
                                break;
                        case 'dbsync':
                                admin_page_dbsync_post($a);
                                break;
-                       case 'update':
-                               admin_page_remoteupdate_post($a);
-                               break;
                }
        }
 
-       goaway($a->get_baseurl(true) . '/admin' );
+       goaway('admin');
        return; // NOTREACHED
 }
 
 /**
+ * @brief Generates content of the admin panel pages
+ *
+ * This function generates the content for the admin panel. It consists of the
+ * aside menu (same for the entire admin panel) and the code for the soecified
+ * subpage of the panel.
+ *
+ * The structure of the adress is: /admin/subpage/details though "details" is
+ * only necessary for some subpages, like themes or addons where it is the name
+ * of one theme resp. addon from which the details should be shown. Content for
+ * the subpages is generated in separate functions for each of the subpages.
+ *
+ * The returned string hold the generated HTML code of the page.
+ *
  * @param App $a
  * @return string
  */
@@ -118,58 +143,62 @@ function admin_content(&$a) {
        //      apc_delete($toDelete);
        //}
 
-       /**
+       // Header stuff
+       $a->page['htmlhead'] .= replace_macros(get_markup_template('admin_settings_head.tpl'), array());
+
+       /*
         * Side bar links
         */
-       $aside = Array();
-       // array( url, name, extra css classes )
+       $aside_tools = array();
+       // array(url, name, extra css classes)
        // not part of $aside to make the template more adjustable
-       $asidesubpages = Array(
-               'site'   =>     Array($a->get_baseurl(true)."/admin/site/", t("Site") , "site"),
-               'users'  =>     Array($a->get_baseurl(true)."/admin/users/", t("Users") , "users"),
-               'plugins'=>     Array($a->get_baseurl(true)."/admin/plugins/", t("Plugins") , "plugins"),
-               'themes' =>     Array($a->get_baseurl(true)."/admin/themes/", t("Themes") , "themes"),
-               'dbsync' =>     Array($a->get_baseurl(true)."/admin/dbsync/", t('DB updates'), "dbsync"),
-               'queue'  =>     Array($a->get_baseurl(true)."/admin/queue/", t('Inspect Queue'), "queue"),
-               'federation' => Array($a->get_baseurl(true)."/admin/federation/", t('Federation Statistics'), "federation"),
-               //'update' =>   Array($a->get_baseurl(true)."/admin/update/", t("Software Update") , "update")
+       $aside_sub = array(
+               'site'   =>     array("admin/site/", t("Site") , "site"),
+               'users'  =>     array("admin/users/", t("Users") , "users"),
+               'plugins'=>     array("admin/plugins/", t("Plugins") , "plugins"),
+               'themes' =>     array("admin/themes/", t("Themes") , "themes"),
+               'features' =>   array("admin/features/", t("Additional features") , "features"),
+               'dbsync' =>     array("admin/dbsync/", t('DB updates'), "dbsync"),
+               'queue'  =>     array("admin/queue/", t('Inspect Queue'), "queue"),
+               'federation' => array("admin/federation/", t('Federation Statistics'), "federation"),
        );
 
        /* get plugins admin page */
 
        $r = q("SELECT `name` FROM `addon` WHERE `plugin_admin`=1 ORDER BY `name`");
-       $aside['plugins_admin']=Array();
+       $aside_tools['plugins_admin']=array();
        foreach ($r as $h){
                $plugin =$h['name'];
-               $aside['plugins_admin'][] = Array($a->get_baseurl(true)."/admin/plugins/".$plugin, $plugin, "plugin");
+               $aside_tools['plugins_admin'][] = array("admin/plugins/".$plugin, $plugin, "plugin");
                // temp plugins with admin
                $a->plugins_admin[] = $plugin;
        }
 
-       $aside['logs'] = Array($a->get_baseurl(true)."/admin/logs/", t("Logs"), "logs");
-       $aside['diagnostics_probe'] = Array($a->get_baseurl(true).'/probe/', t('probe address'), 'probe');
-       $aside['diagnostics_webfinger'] = Array($a->get_baseurl(true).'/webfinger/', t('check webfinger'), 'webfinger');
+       $aside_tools['logs'] = array("admin/logs/", t("Logs"), "logs");
+       $aside_tools['viewlogs'] = array("admin/viewlogs/", t("View Logs"), 'viewlogs');
+       $aside_tools['diagnostics_probe'] = array('probe/', t('probe address'), 'probe');
+       $aside_tools['diagnostics_webfinger'] = array('webfinger/', t('check webfinger'), 'webfinger');
 
        $t = get_markup_template("admin_aside.tpl");
-       $a->page['aside'] .= replace_macros( $t, array(
-           '$admin' => $aside,
-           '$subpages' => $asidesubpages,
-                       '$admtxt' => t('Admin'),
-                       '$plugadmtxt' => t('Plugin Features'),
-                       '$logtxt' => t('Logs'),
-                       '$diagnosticstxt' => t('diagnostics'),
-                       '$h_pending' => t('User registrations waiting for confirmation'),
-                       '$admurl'=> $a->get_baseurl(true)."/admin/"
+       $a->page['aside'] .= replace_macros($t, array(
+               '$admin' => $aside_tools,
+               '$subpages' => $aside_sub,
+               '$admtxt' => t('Admin'),
+               '$plugadmtxt' => t('Plugin Features'),
+               '$logtxt' => t('Logs'),
+               '$diagnosticstxt' => t('diagnostics'),
+               '$h_pending' => t('User registrations waiting for confirmation'),
+               '$admurl'=> "admin/"
        ));
 
 
 
-       /**
+       /*
         * Page content
         */
        $o = '';
        // urls
-       if ($a->argc > 1){
+       if($a->argc > 1) {
                switch ($a->argv[1]){
                        case 'site':
                                $o = admin_page_site($a);
@@ -183,23 +212,26 @@ function admin_content(&$a) {
                        case 'themes':
                                $o = admin_page_themes($a);
                                break;
+                       case 'features':
+                               $o = admin_page_features($a);
+                               break;
                        case 'logs':
                                $o = admin_page_logs($a);
                                break;
+                       case 'viewlogs':
+                               $o = admin_page_viewlogs($a);
+                               break;
                        case 'dbsync':
                                $o = admin_page_dbsync($a);
                                break;
-                       case 'update':
-                               $o = admin_page_remoteupdate($a);
-                               break;
                        case 'queue':
-                               $o = admin_page_queue($a);
+                               $o = admin_page_queue($a);
                                break;
                        case 'federation':
-                               $o = admin_page_federation($a);
+                               $o = admin_page_federation($a);
                                break;
                        default:
-                               notice( t("Item not found.") );
+                               notice(t("Item not found."));
                }
        } else {
                $o = admin_page_summary($a);
@@ -215,54 +247,146 @@ function admin_content(&$a) {
 }
 
 /**
- * Admin Federation Stats Page; display some numbers from gserver
+ * @brief Subpage with some stats about "the federation" network
+ *
+ * This function generates the "Federation Statistics" subpage for the admin
+ * panel. The page lists some numbers to the part of "The Federation" known to
+ * the node. This data includes the different connected networks (e.g.
+ * Diaspora, Hubzilla, GNU Social) and the used versions in the different
+ * networks.
+ *
+ * The returned string contains the HTML code of the subpage for display.
+ *
  * @param App $a
- * returning string
+ * @return string
  */
 function admin_page_federation(&$a) {
-    // get counts on active friendica, diaspora, redmatrix, hubzilla, gnu
-    // social and statusnet nodes this node is knowing
-    //
-    // We are looking for the following platforms in the DB, "Red" should find
-    // all variants of that platform ID string as the q() function is stripping
-    // off one % two of them are needed in the query
-    $platforms = array('Diaspora', 'Friendica', '%%red%%', 'Hubzilla', 'GNU Social', 'StatusNet');
-    $counts = array();
-    foreach ($platforms as $p) {
-       // get a totaƶ count for the platform, the name and version of the
-       // highest version and the protocol tpe
-       $c = q('select count(*), platform, network, version from gserver where platform like "'.$p.'" and last_contact > last_failure order by version asc;');
-       // what versions for that platform do we know at all?
-       // again only the active nodes
-       $v = q('select count(*), version from gserver where last_contact > last_failure and platform like "'.$p.'" group by version order by version;');
-       // the 3rd array item is needed for the JavaScript graphs as JS does
-       // not like some characters in the names of variables...
-       $counts[$p]=array($c[0], $v, str_replace(array(' ','%'),'',$p));
-    }
-    // some helpful text
-    $intro = t('This page offers you some numbers to the known part of the federated social network your Friendica node is part of. These numbers are not complete but only reflect the part of the network your node is aware of.');
-    $hint = t('The <em>Auto Discovered Contact Directory</em> feature is not enabled, it will improve the data displayed here.');
-    // load the template, replace the macros and return the page content
-    $t = get_markup_template("admin_federation.tpl");
-    return replace_macros($t, array(
-       '$title' => t('Administration'),
-       '$page' => t('Federation Statistics'),
-       '$intro' => $intro,
-       '$hint' => $hint,
-       '$autoactive' => get_config('system', 'poco_completion'),
-       '$counts' => $counts,
-       '$version' => FRIENDICA_VERSION,
-       '$legendtext' => t('Currently this node is aware of nodes from the following platforms:'),
-    ));
+       // get counts on active friendica, diaspora, redmatrix, hubzilla, gnu
+       // social and statusnet nodes this node is knowing
+       //
+       // We are looking for the following platforms in the DB, "Red" should find
+       // all variants of that platform ID string as the q() function is stripping
+       // off one % two of them are needed in the query
+       // Add more platforms if you like, when one returns 0 known nodes it is not
+       // displayed on the stats page.
+       $platforms = array('Friendica', 'Diaspora', '%%red%%', 'Hubzilla', 'GNU Social', 'StatusNet');
+       $colors    = array('Friendica' => '#ffc018',     // orange from the logo
+                          'Diaspora'  => '#a1a1a1',     // logo is black and white, makes a gray
+                          '%%red%%'   => '#c50001',     // fire red from the logo
+                          'Hubzilla'  => '#43488a',     // blue from the logo
+                          'GNU Social'=> '#a22430',     // dark red from the logo
+                          'StatusNet' => '#789240');    // the green from the logo (red and blue have already others
+       $counts = array();
+       $total = 0;
+
+       foreach ($platforms as $p) {
+               // get a total count for the platform, the name and version of the
+               // highest version and the protocol tpe
+               $c = q('SELECT count(*) AS total, platform, network, version FROM gserver
+                       WHERE platform LIKE "%s" AND last_contact > last_failure AND `version` != ""
+                       ORDER BY version ASC;', $p);
+               $total = $total + $c[0]['total'];
+
+               // what versions for that platform do we know at all?
+               // again only the active nodes
+               $v = q('SELECT count(*) AS total, version FROM gserver
+                       WHERE last_contact > last_failure AND platform LIKE "%s"  AND `version` != ""
+                       GROUP BY version
+                       ORDER BY version;', $p);
+
+               //
+               // clean up version numbers
+               //
+               // in the DB the Diaspora versions have the format x.x.x.x-xx the last
+               // part (-xx) should be removed to clean up the versions from the "head
+               // commit" information and combined into a single entry for x.x.x.x
+               if($p=='Diaspora') {
+                       $newV = array();
+                       $newVv = array();
+                       foreach($v as $vv) {
+                               $newVC = $vv['total'];
+                               $newVV = $vv['version'];
+                               $posDash = strpos($newVV, '-');
+                               if($posDash) 
+                                       $newVV = substr($newVV, 0, $posDash);
+                               if(isset($newV[$newVV]))
+                                       $newV[$newVV] += $newVC; 
+                               else
+                                       $newV[$newVV] = $newVC; 
+                       }
+                       foreach ($newV as $key => $value) {
+                               array_push($newVv, array('total'=>$value, 'version'=>$key));
+                       }
+                       $v = $newVv;
+               }
+
+               // early friendica versions have the format x.x.xxxx where xxxx is the
+               // DB version stamp; those should be operated out and versions be
+               // conbined
+               if($p=='Friendica') {
+                       $newV = array();
+                       $newVv = array();
+                       foreach ($v as $vv) {
+                               $newVC = $vv['total'];
+                               $newVV = $vv['version'];
+                               $lastDot = strrpos($newVV,'.');
+                               $len = strlen($newVV)-1;
+                               if(($lastDot == $len-4) && (!strrpos($newVV,'-rc')==$len-3))
+                                       $newVV = substr($newVV, 0, $lastDot);
+                               if(isset($newV[$newVV]))
+                                       $newV[$newVV] += $newVC;
+                               else
+                                       $newV[$newVV] = $newVC;
+                       }
+                       foreach ($newV as $key => $value) {
+                               array_push($newVv, array('total'=>$value, 'version'=>$key));
+                       }
+                       $v = $newVv;
+               }
+
+               foreach ($v as $key => $vv)
+                       $v[$key]["version"] = trim(strip_tags($vv["version"]));
+
+               // the 3rd array item is needed for the JavaScript graphs as JS does
+               // not like some characters in the names of variables...
+               $counts[$p]=array($c[0], $v, str_replace(array(' ','%'),'',$p), $colors[$p]);
+       }
+
+       // some helpful text
+       $intro = t('This page offers you some numbers to the known part of the federated social network your Friendica node is part of. These numbers are not complete but only reflect the part of the network your node is aware of.');
+       $hint = t('The <em>Auto Discovered Contact Directory</em> feature is not enabled, it will improve the data displayed here.');
+
+       // load the template, replace the macros and return the page content
+       $t = get_markup_template("admin_federation.tpl");
+       return replace_macros($t, array(
+               '$title' => t('Administration'),
+               '$page' => t('Federation Statistics'),
+               '$intro' => $intro,
+               '$hint' => $hint,
+               '$autoactive' => get_config('system', 'poco_completion'),
+               '$counts' => $counts,
+               '$version' => FRIENDICA_VERSION,
+               '$legendtext' => sprintf(t('Currently this node is aware of %d nodes from the following platforms:'), $total),
+               '$baseurl' => $a->get_baseurl(),
+       ));
 }
+
 /**
- * Admin Inspect Queue Page
+ * @brief Admin Inspect Queue Page
+ *
+ * Generates a page for the admin to have a look into the current queue of
+ * postings that are not deliverabke. Shown are the name and url of the
+ * recipient, the delivery network and the dates when the posting was generated
+ * and the last time tried to deliver the posting.
+ *
+ * The returned string holds the content of the page.
+ *
  * @param App $a
- * return string
+ * @return string
  */
 function admin_page_queue(&$a) {
-       // get content from the queue table
-       $r = q("SELECT c.name,c.nurl,q.id,q.network,q.created,q.last from queue as q, contact as c where c.id=q.cid order by q.cid, q.created;");
+       // get content from the queue table
+       $r = q("SELECT c.name,c.nurl,q.id,q.network,q.created,q.last from queue as q, contact as c where c.id=q.cid order by q.cid, q.created;");
 
        $t = get_markup_template("admin_queue.tpl");
        return replace_macros($t, array(
@@ -279,26 +403,33 @@ function admin_page_queue(&$a) {
                '$entries' => $r,
        ));
 }
+
 /**
- * Admin Summary Page
+ * @brief Admin Summary Page
+ *
+ * The summary page is the "start page" of the admin panel. It gives the admin
+ * a first overview of the open adminastrative tasks.
+ *
+ * The returned string contains the HTML content of the generated page.
+ *
  * @param App $a
  * @return string
  */
 function admin_page_summary(&$a) {
        $r = q("SELECT `page-flags`, COUNT(uid) as `count` FROM `user` GROUP BY `page-flags`");
-       $accounts = Array(
-               Array( t('Normal Account'), 0),
-               Array( t('Soapbox Account'), 0),
-               Array( t('Community/Celebrity Account'), 0),
-               Array( t('Automatic Friend Account'), 0),
-               Array( t('Blog Account'), 0),
-               Array( t('Private Forum'), 0)
+       $accounts = array(
+               array(t('Normal Account'), 0),
+               array(t('Soapbox Account'), 0),
+               array(t('Community/Celebrity Account'), 0),
+               array(t('Automatic Friend Account'), 0),
+               array(t('Blog Account'), 0),
+               array(t('Private Forum'), 0)
        );
 
        $users=0;
        foreach ($r as $u){ $accounts[$u['page-flags']][1] = $u['count']; $users+= $u['count']; }
 
-       logger('accounts: ' . print_r($accounts,true),LOGGER_DATA);
+       logger('accounts: '.print_r($accounts,true),LOGGER_DATA);
 
        $r = q("SELECT COUNT(id) as `count` FROM `register`");
        $pending = $r[0]['count'];
@@ -311,7 +442,7 @@ function admin_page_summary(&$a) {
 
        // We can do better, but this is a quick queue status
 
-       $queues = array( 'label' => t('Message queues'), 'deliverq' => $deliverq, 'queue' => $queue );
+       $queues = array('label' => t('Message queues'), 'deliverq' => $deliverq, 'queue' => $queue);
 
 
        $t = get_markup_template("admin_summary.tpl");
@@ -319,39 +450,39 @@ function admin_page_summary(&$a) {
                '$title' => t('Administration'),
                '$page' => t('Summary'),
                '$queues' => $queues,
-               '$users' => Array( t('Registered users'), $users),
+               '$users' => array(t('Registered users'), $users),
                '$accounts' => $accounts,
-               '$pending' => Array( t('Pending registrations'), $pending),
-               '$version' => Array( t('Version'), FRIENDICA_VERSION),
+               '$pending' => array(t('Pending registrations'), $pending),
+               '$version' => array(t('Version'), FRIENDICA_VERSION),
                '$baseurl' => $a->get_baseurl(),
                '$platform' => FRIENDICA_PLATFORM,
                '$codename' => FRIENDICA_CODENAME,
                '$build' =>  get_config('system','build'),
-               '$plugins' => Array( t('Active plugins'), $a->plugins )
+               '$plugins' => array(t('Active plugins'), $a->plugins)
        ));
 }
 
-
 /**
- * Admin Site Page
- *  @param App $a
+ * @brief Process send data from Admin Site Page
+ * 
+ * @param App $a
  */
-function admin_page_site_post(&$a){
-       if (!x($_POST,"page_site")){
+function admin_page_site_post(&$a) {
+       if(!x($_POST,"page_site")) {
                return;
        }
 
        check_form_security_token_redirectOnErr('/admin/site', 'admin_site');
 
        // relocate
-       if (x($_POST,'relocate') && x($_POST,'relocate_url') && $_POST['relocate_url']!=""){
+       if(x($_POST,'relocate') && x($_POST,'relocate_url') && $_POST['relocate_url']!="") {
                $new_url = $_POST['relocate_url'];
                $new_url = rtrim($new_url,"/");
 
                $parsed = @parse_url($new_url);
-               if (!$parsed || (!x($parsed,'host') || !x($parsed,'scheme'))) {
+               if(!$parsed || (!x($parsed,'host') || !x($parsed,'scheme'))) {
                        notice(t("Can not parse base url. Must have at least <scheme>://<domain>"));
-                       goaway($a->get_baseurl(true) . '/admin/site' );
+                       goaway('admin/site');
                }
 
                /* steps:
@@ -361,6 +492,10 @@ function admin_page_site_post(&$a){
 
                $old_url = $a->get_baseurl(true);
 
+               // Generate host names for relocation the addresses in the format user@address.tld
+               $new_host = str_replace("http://", "@", normalise_link($new_url));
+               $old_host = str_replace("http://", "@", normalise_link($old_url));
+
                function update_table($table_name, $fields, $old_url, $new_url) {
                        global $db, $a;
 
@@ -378,18 +513,23 @@ function admin_page_site_post(&$a){
 
                        $q = sprintf("UPDATE %s SET %s;", $table_name, $upds);
                        $r = q($q);
-                       if (!$r) {
-                               notice( "Failed updating '$table_name': " . $db->error );
-                               goaway($a->get_baseurl(true) . '/admin/site' );
+                       if(!$r) {
+                               notice("Failed updating '$table_name': ".$db->error);
+                               goaway('admin/site');
                        }
                }
 
                // update tables
+               // update profile links in the format "http://server.tld"
                update_table("profile", array('photo', 'thumb'), $old_url, $new_url);
                update_table("term", array('url'), $old_url, $new_url);
-               update_table("contact", array('photo','thumb','micro','url','nurl','request','notify','poll','confirm','poco'), $old_url, $new_url);
-               update_table("gcontact", array('photo','url','nurl','server_url'), $old_url, $new_url);
-               update_table("item", array('owner-link','owner-avatar','author-name','author-link','author-avatar','body','plink','tag'), $old_url, $new_url);
+               update_table("contact", array('photo','thumb','micro','url','nurl','alias','request','notify','poll','confirm','poco', 'avatar'), $old_url, $new_url);
+               update_table("gcontact", array('url','nurl','photo','server_url','notify','alias'), $old_url, $new_url);
+               update_table("item", array('owner-link','owner-avatar','author-link','author-avatar','body','plink','tag'), $old_url, $new_url);
+
+               // update profile addresses in the format "user@server.tld"
+               update_table("contact", array('addr'), $old_host, $new_host);
+               update_table("gcontact", array('connect','addr'), $old_host, $new_host);
 
                // update config
                $a->set_baseurl($new_url);
@@ -404,7 +544,7 @@ function admin_page_site_post(&$a){
 
                info("Relocation started. Could take a while to complete.");
 
-               goaway($a->get_baseurl(true) . '/admin/site' );
+               goaway('admin/site');
        }
        // end relocate
 
@@ -414,7 +554,7 @@ function admin_page_site_post(&$a){
        $banner                 =       ((x($_POST,'banner'))                   ? trim($_POST['banner'])                        : false);
        $shortcut_icon          =       ((x($_POST,'shortcut_icon'))            ? notags(trim($_POST['shortcut_icon']))         : '');
        $touch_icon             =       ((x($_POST,'touch_icon'))               ? notags(trim($_POST['touch_icon']))            : '');
-       $info                   =       ((x($_POST,'info'))                     ? trim($_POST['info'])                  : false);
+       $info                   =       ((x($_POST,'info'))                     ? trim($_POST['info'])                          : false);
        $language               =       ((x($_POST,'language'))                 ? notags(trim($_POST['language']))              : '');
        $theme                  =       ((x($_POST,'theme'))                    ? notags(trim($_POST['theme']))                 : '');
        $theme_mobile           =       ((x($_POST,'theme_mobile'))             ? notags(trim($_POST['theme_mobile']))          : '');
@@ -433,13 +573,13 @@ function admin_page_site_post(&$a){
        $allowed_email          =       ((x($_POST,'allowed_email'))            ? notags(trim($_POST['allowed_email']))         : '');
        $block_public           =       ((x($_POST,'block_public'))             ? True                                          : False);
        $force_publish          =       ((x($_POST,'publish_all'))              ? True                                          : False);
-       $global_directory       =       ((x($_POST,'directory'))                ? notags(trim($_POST['directory']))     : '');
+       $global_directory       =       ((x($_POST,'directory'))                ? notags(trim($_POST['directory']))             : '');
        $thread_allow           =       ((x($_POST,'thread_allow'))             ? True                                          : False);
-       $newuser_private                =       ((x($_POST,'newuser_private'))          ? True                                          : False);
-       $enotify_no_content             =       ((x($_POST,'enotify_no_content'))       ? True                                          : False);
-       $private_addons                 =       ((x($_POST,'private_addons'))           ? True                                          : False);
-       $disable_embedded               =       ((x($_POST,'disable_embedded'))         ? True                                          : False);
-       $allow_users_remote_self        =       ((x($_POST,'allow_users_remote_self'))          ? True                                          : False);
+       $newuser_private                =       ((x($_POST,'newuser_private'))          ? True                                  : False);
+       $enotify_no_content             =       ((x($_POST,'enotify_no_content'))       ? True                                  : False);
+       $private_addons                 =       ((x($_POST,'private_addons'))           ? True                                  : False);
+       $disable_embedded               =       ((x($_POST,'disable_embedded'))         ? True                                  : False);
+       $allow_users_remote_self        =       ((x($_POST,'allow_users_remote_self'))  ? True                                  : False);
 
        $no_multi_reg           =       ((x($_POST,'no_multi_reg'))             ? True                                          : False);
        $no_openid              =       !((x($_POST,'no_openid'))               ? True                                          : False);
@@ -467,6 +607,7 @@ function admin_page_site_post(&$a){
        $dfrn_only              =       ((x($_POST,'dfrn_only'))                ? True                                          : False);
        $ostatus_disabled       =       !((x($_POST,'ostatus_disabled'))        ? True                                          : False);
        $ostatus_poll_interval  =       ((x($_POST,'ostatus_poll_interval'))    ? intval(trim($_POST['ostatus_poll_interval'])) :  0);
+       $ostatus_full_threads   =       ((x($_POST,'ostatus_full_threads'))     ? True                                          : False);
        $diaspora_enabled       =       ((x($_POST,'diaspora_enabled'))         ? True                                          : False);
        $ssl_policy             =       ((x($_POST,'ssl_policy'))               ? intval($_POST['ssl_policy'])                  : 0);
        $force_ssl              =       ((x($_POST,'force_ssl'))                ? True                                          : False);
@@ -485,13 +626,16 @@ function admin_page_site_post(&$a){
        $proxy_disabled         =       ((x($_POST,'proxy_disabled'))           ? True                                          : False);
        $old_pager              =       ((x($_POST,'old_pager'))                ? True                                          : False);
        $only_tag_search        =       ((x($_POST,'only_tag_search'))          ? True                                          : False);
-       $rino                   =       ((x($_POST,'rino'))                             ? intval($_POST['rino'])                                : 0);
+       $rino                   =       ((x($_POST,'rino'))                     ? intval($_POST['rino'])                        : 0);
        $embedly                =       ((x($_POST,'embedly'))                  ? notags(trim($_POST['embedly']))               : '');
+       $worker                 =       ((x($_POST,'worker'))                   ? True                                          : False);
+       $worker_queues          =       ((x($_POST,'worker_queues'))            ? intval($_POST['worker_queues'])               : 4);
+       $worker_dont_fork       =       ((x($_POST,'worker_dont_fork'))         ? True                                          : False);
 
-       if ($a->get_path() != "")
+       if($a->get_path() != "")
                $diaspora_enabled = false;
 
-       if (!$thread_allow)
+       if(!$thread_allow)
                $ostatus_disabled = true;
 
        if($ssl_policy != intval(get_config('system','ssl_policy'))) {
@@ -555,7 +699,7 @@ function admin_page_site_post(&$a){
        set_config('system','shortcut_icon',$shortcut_icon);
        set_config('system','touch_icon',$touch_icon);
 
-       if ($banner==""){
+       if($banner=="") {
                // don't know why, but del_config doesn't work...
                q("DELETE FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1",
                        dbesc("system"),
@@ -564,19 +708,21 @@ function admin_page_site_post(&$a){
        } else {
                set_config('system','banner', $banner);
        }
-       if ($info=="") {
+
+       if($info=="") {
                del_config('config','info');
        } else {
                set_config('config','info',$info);
        }
        set_config('system','language', $language);
        set_config('system','theme', $theme);
-       if ( $theme_mobile === '---' ) {
+
+       if($theme_mobile === '---') {
                del_config('system','mobile-theme');
        } else {
                set_config('system','mobile-theme', $theme_mobile);
                }
-               if ( $singleuser === '---' ) {
+               if($singleuser === '---') {
                        del_config('system','singleuser');
                } else {
                        set_config('system','singleuser', $singleuser);
@@ -613,6 +759,7 @@ function admin_page_site_post(&$a){
        set_config('system','dfrn_only', $dfrn_only);
        set_config('system','ostatus_disabled', $ostatus_disabled);
        set_config('system','ostatus_poll_interval', $ostatus_poll_interval);
+       set_config('system','ostatus_full_threads', $ostatus_full_threads);
        set_config('system','diaspora_enabled', $diaspora_enabled);
 
        set_config('config','private_addons', $private_addons);
@@ -630,9 +777,11 @@ function admin_page_site_post(&$a){
        set_config('system','proxy_disabled', $proxy_disabled);
        set_config('system','old_pager', $old_pager);
        set_config('system','only_tag_search', $only_tag_search);
+       set_config('system','worker', $worker);
+       set_config('system','worker_queues', $worker_queues);
+       set_config('system','worker_dont_fork', $worker_dont_fork);
 
-
-       if ($rino==2 and !function_exists('mcrypt_create_iv')){
+       if($rino==2 and !function_exists('mcrypt_create_iv')) {
                notice(t("RINO2 needs mcrypt php extension to work."));
        } else {
                set_config('system','rino_encrypt', $rino);
@@ -641,13 +790,17 @@ function admin_page_site_post(&$a){
        set_config('system','embedly', $embedly);
 
 
-       info( t('Site settings updated.') . EOL);
-       goaway($a->get_baseurl(true) . '/admin/site' );
+       info(t('Site settings updated.').EOL);
+       goaway('admin/site');
        return; // NOTREACHED
 
 }
 
 /**
+ * @brief Generate Admin Site subpage
+ *
+ * This function generates the main configuration page of the admin panel.
+ *
  * @param  App $a
  * @return string
  */
@@ -656,25 +809,25 @@ function admin_page_site(&$a) {
        /* Installed langs */
        $lang_choices = get_avaiable_languages();
 
-       if (strlen(get_config('system','directory_submit_url')) AND
+       if(strlen(get_config('system','directory_submit_url')) AND
                !strlen(get_config('system','directory'))) {
-               set_config('system','directory', dirname(get_config('system','directory_submit_url')));
-               del_config('system','directory_submit_url');
+                       set_config('system','directory', dirname(get_config('system','directory_submit_url')));
+                       del_config('system','directory_submit_url');
        }
 
        /* Installed themes */
        $theme_choices = array();
        $theme_choices_mobile = array();
        $theme_choices_mobile["---"] = t("No special theme for mobile devices");
-       $files = glob('view/theme/*'); /**/
+       $files = glob('view/theme/*');
        if($files) {
                foreach($files as $file) {
-                       if (intval(file_exists($file . '/unsupported')))
+                       if(intval(file_exists($file.'/unsupported')))
                                continue;
 
                        $f = basename($file);
-                       $theme_name = ((file_exists($file . '/experimental')) ?  sprintf("%s - \x28Experimental\x29", $f) : $f);
-                       if (file_exists($file . '/mobile')) {
+                       $theme_name = ((file_exists($file.'/experimental')) ?  sprintf("%s - \x28Experimental\x29", $f) : $f);
+                       if(file_exists($file.'/mobile')) {
                                $theme_choices_mobile[$f] = $theme_name;
                        } else {
                                $theme_choices[$f] = $theme_name;
@@ -737,7 +890,7 @@ function admin_page_site(&$a) {
        //echo "<pre>"; var_dump($lang_choices); die("</pre>");
 
        /* Register policy */
-       $register_choices = Array(
+       $register_choices = array(
                REGISTER_CLOSED => t("Closed"),
                REGISTER_APPROVE => t("Requires approval"),
                REGISTER_OPEN => t("Open")
@@ -749,7 +902,7 @@ function admin_page_site(&$a) {
                SSL_POLICY_SELFSIGN => t("Self-signed certificate, use SSL for local links only (discouraged)")
        );
 
-       if ($a->config['hostname'] == "")
+       if($a->config['hostname'] == "")
                $a->config['hostname'] = $a->get_hostname();
 
        $diaspora_able = ($a->get_path() == "");
@@ -765,6 +918,7 @@ function admin_page_site(&$a) {
                '$advanced' => t('Advanced'),
                '$portable_contacts' => t('Auto Discovered Contact Directory'),
                '$performance' => t('Performance'),
+               '$worker_title' => t('Worker'),
                '$relocate'=> t('Relocate - WARNING: advanced function. Could make this server unreachable.'),
                '$baseurl' => $a->get_baseurl(true),
                // name, label, value, help string, extra data...
@@ -774,7 +928,7 @@ function admin_page_site(&$a) {
                '$banner'               => array('banner', t("Banner/Logo"), $banner, ""),
                '$shortcut_icon'        => array('shortcut_icon', t("Shortcut icon"), get_config('system','shortcut_icon'),  t("Link to an icon that will be used for browsers.")),
                '$touch_icon'           => array('touch_icon', t("Touch icon"), get_config('system','touch_icon'),  t("Link to an icon that will be used for tablets and mobiles.")),
-               '$info' => array('info',t('Additional Info'), $info, sprintf(t('For public servers: you can add additional information here that will be listed at %s/siteinfo.'), get_server())),
+               '$info'                 => array('info',t('Additional Info'), $info, sprintf(t('For public servers: you can add additional information here that will be listed at %s/siteinfo.'), get_server())),
                '$language'             => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
                '$theme'                => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices),
                '$theme_mobile'         => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile-theme'), t("Theme for mobile devices"), $theme_choices_mobile),
@@ -784,8 +938,8 @@ function admin_page_site(&$a) {
                '$hide_help'            => array('hide_help', t("Hide help entry from navigation menu"), get_config('system','hide_help'), t("Hides the menu entry for the Help pages from the navigation menu. You can still access it calling /help directly.")),
                '$singleuser'           => array('singleuser', t("Single user instance"), get_config('system','singleuser'), t("Make this instance multi-user or single-user for the named user"), $user_names),
                '$maximagesize'         => array('maximagesize', t("Maximum image size"), get_config('system','maximagesize'), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")),
-               '$maximagelength'               => array('maximagelength', t("Maximum image length"), get_config('system','max_image_length'), t("Maximum length in pixels of the longest side of uploaded images. Default is -1, which means no limits.")),
-               '$jpegimagequality'             => array('jpegimagequality', t("JPEG image quality"), get_config('system','jpeg_quality'), t("Uploaded JPEGS will be saved at this quality setting [0-100]. Default is 100, which is full quality.")),
+               '$maximagelength'       => array('maximagelength', t("Maximum image length"), get_config('system','max_image_length'), t("Maximum length in pixels of the longest side of uploaded images. Default is -1, which means no limits.")),
+               '$jpegimagequality'     => array('jpegimagequality', t("JPEG image quality"), get_config('system','jpeg_quality'), t("Uploaded JPEGS will be saved at this quality setting [0-100]. Default is 100, which is full quality.")),
 
                '$register_policy'      => array('register_policy', t("Register policy"), $a->config['register_policy'], "", $register_choices),
                '$daily_registrations'  => array('max_daily_registrations', t("Maximum Daily Registrations"), get_config('system', 'max_daily_registrations'), t("If registration is permitted above, this sets the maximum number of new user registrations to accept per day.  If register is set to closed, this setting has no effect.")),
@@ -801,7 +955,7 @@ function admin_page_site(&$a) {
                '$enotify_no_content'   => array('enotify_no_content', t("Don't include post content in email notifications"), get_config('system','enotify_no_content'), t("Don't include the content of a post/comment/private message/etc. in the email notifications that are sent out from this site, as a privacy measure.")),
                '$private_addons'       => array('private_addons', t("Disallow public access to addons listed in the apps menu."), get_config('config','private_addons'), t("Checking this box will restrict addons listed in the apps menu to members only.")),
                '$disable_embedded'     => array('disable_embedded', t("Don't embed private images in posts"), get_config('system','disable_embedded'), t("Don't replace locally-hosted private photos in posts with an embedded copy of the image. This means that contacts who receive posts containing private photos will have to authenticate and load each image, which may take a while.")),
-               '$allow_users_remote_self'      => array('allow_users_remote_self', t('Allow Users to set remote_self'), get_config('system','allow_users_remote_self'), t('With checking this, every user is allowed to mark every contact as a remote_self in the repair contact dialog. Setting this flag on a contact causes mirroring every posting of that contact in the users stream.')),
+               '$allow_users_remote_self' => array('allow_users_remote_self', t('Allow Users to set remote_self'), get_config('system','allow_users_remote_self'), t('With checking this, every user is allowed to mark every contact as a remote_self in the repair contact dialog. Setting this flag on a contact causes mirroring every posting of that contact in the users stream.')),
                '$no_multi_reg'         => array('no_multi_reg', t("Block multiple registrations"),  get_config('system','block_extended_register'), t("Disallow users to register additional accounts for use as pages.")),
                '$no_openid'            => array('no_openid', t("OpenID support"), !get_config('system','no_openid'), t("OpenID support for registration and logins.")),
                '$no_regfullname'       => array('no_regfullname', t("Fullname check"), !get_config('system','no_regfullname'), t("Force users to register with a space between firstname and lastname in Full name, as an antispam measure")),
@@ -809,12 +963,13 @@ function admin_page_site(&$a) {
                '$community_page_style' => array('community_page_style', t("Community Page Style"), get_config('system','community_page_style'), t("Type of community page to show. 'Global community' shows every public posting from an open distributed network that arrived on this server."), $community_page_style_choices),
                '$max_author_posts_community_page' => array('max_author_posts_community_page', t("Posts per user on community page"), get_config('system','max_author_posts_community_page'), t("The maximum number of posts per user on the community page. (Not valid for 'Global Community')")),
                '$ostatus_disabled'     => array('ostatus_disabled', t("Enable OStatus support"), !get_config('system','ostatus_disabled'), t("Provide built-in OStatus \x28StatusNet, GNU Social etc.\x29 compatibility. All communications in OStatus are public, so privacy warnings will be occasionally displayed.")),
-               '$ostatus_poll_interval'        => array('ostatus_poll_interval', t("OStatus conversation completion interval"), (string) intval(get_config('system','ostatus_poll_interval')), t("How often shall the poller check for new entries in OStatus conversations? This can be a very ressource task."), $ostatus_poll_choices),
+               '$ostatus_poll_interval' => array('ostatus_poll_interval', t("OStatus conversation completion interval"), (string) intval(get_config('system','ostatus_poll_interval')), t("How often shall the poller check for new entries in OStatus conversations? This can be a very ressource task."), $ostatus_poll_choices),
+               '$ostatus_full_threads' => array('ostatus_full_threads', t("Only import OStatus threads from our contacts"), get_config('system','ostatus_full_threads'), t("Normally we import every content from our OStatus contacts. With this option we only store threads that are started by a contact that is known on our system.")),
                '$ostatus_not_able'     => t("OStatus support can only be enabled if threading is enabled."),
                '$diaspora_able'        => $diaspora_able,
                '$diaspora_not_able'    => t("Diaspora support can't be enabled because Friendica was installed into a sub directory."),
-               '$diaspora_enabled'     => array('diaspora_enabled', t("Enable Diaspora support"), get_config('system','diaspora_enabled'), t("Provide built-in Diaspora network compatibility.")),
-               '$dfrn_only'            => array('dfrn_only', t('Only allow Friendica contacts'), get_config('system','dfrn_only'), t("All contacts must use Friendica protocols. All other built-in communication protocols disabled.")),
+               '$diaspora_enabled'     => array('diaspora_enabled', t("Enable Diaspora support"), get_config('system','diaspora_enabled'), t("Provide built-in Diaspora network compatibility.")),
+               '$dfrn_only'            => array('dfrn_only', t('Only allow Friendica contacts'), get_config('system','dfrn_only'), t("All contacts must use Friendica protocols. All other built-in communication protocols disabled.")),
                '$verifyssl'            => array('verifyssl', t("Verify SSL"), get_config('system','verifyssl'), t("If you wish, you can turn on strict certificate checking. This will mean you cannot connect (at all) to self-signed SSL sites.")),
                '$proxyuser'            => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""),
                '$proxy'                => array('proxy', t("Proxy URL"), get_config('system','proxy'), ""),
@@ -852,42 +1007,57 @@ function admin_page_site(&$a) {
                '$rino'                 => array('rino', t("RINO Encryption"), intval(get_config('system','rino_encrypt')), t("Encryption layer between nodes."), array("Disabled", "RINO1 (deprecated)", "RINO2")),
                '$embedly'              => array('embedly', t("Embedly API key"), get_config('system','embedly'), t("<a href='http://embed.ly'>Embedly</a> is used to fetch additional data for web pages. This is an optional parameter.")),
 
-               '$form_security_token' => get_form_security_token("admin_site")
+               '$worker'               => array('worker', t("Enable 'worker' background processing"), get_config('system','worker'), t("The worker background processing limits the number of parallel background jobs to a maximum number and respects the system load.")),
+               '$worker_queues'        => array('worker_queues', t("Maximum number of parallel workers"), get_config('system','worker_queues'), t("On shared hosters set this to 2. On larger systems, values of 10 are great. Default value is 4.")),
+               '$worker_dont_fork'     => array('worker_dont_fork', t("Don't use 'proc_open' with the worker"), get_config('system','worker_dont_fork'), t("Enable this if your system doesn't allow the use of 'proc_open'. This can happen on shared hosters. If this is enabled you should increase the frequency of poller calls in your crontab.")),
+
+               '$form_security_token'  => get_form_security_token("admin_site")
 
        ));
 
 }
 
-
+/**
+ * @brief Generates admin panel subpage for DB syncronization
+ *
+ * This page checks if the database of friendica is in sync with the specs.
+ * Should this not be the case, it attemps to sync the structure and notifies
+ * the admin if the automatic process was failing.
+ *
+ * The returned string holds the HTML code of the page.
+ *
+ * @param App $a
+ * @return string
+ **/
 function admin_page_dbsync(&$a) {
 
        $o = '';
 
        if($a->argc > 3 && intval($a->argv[3]) && $a->argv[2] === 'mark') {
-               set_config('database', 'update_' . intval($a->argv[3]), 'success');
+               set_config('database', 'update_'.intval($a->argv[3]), 'success');
                $curr = get_config('system','build');
                if(intval($curr) == intval($a->argv[3]))
                        set_config('system','build',intval($curr) + 1);
-               info( t('Update has been marked successful') . EOL);
-               goaway($a->get_baseurl(true) . '/admin/dbsync');
+               info(t('Update has been marked successful').EOL);
+               goaway('admin/dbsync');
        }
 
        if(($a->argc > 2) AND (intval($a->argv[2]) OR ($a->argv[2] === 'check'))) {
                require_once("include/dbstructure.php");
                $retval = update_structure(false, true);
-               if (!$retval) {
+               if(!$retval) {
                        $o .= sprintf(t("Database structure update %s was successfully applied."), DB_UPDATE_VERSION)."<br />";
                        set_config('database', 'dbupdate_'.DB_UPDATE_VERSION, 'success');
                } else
                        $o .= sprintf(t("Executing of database structure update %s failed with error: %s"),
                                        DB_UPDATE_VERSION, $retval)."<br />";
-               if ($a->argv[2] === 'check')
+               if($a->argv[2] === 'check')
                        return $o;
        }
 
-       if ($a->argc > 2 && intval($a->argv[2])) {
+       if($a->argc > 2 && intval($a->argv[2])) {
                require_once('update.php');
-               $func = 'update_' . intval($a->argv[2]);
+               $func = 'update_'.intval($a->argv[2]);
                if(function_exists($func)) {
                        $retval = $func();
                        if($retval === UPDATE_FAILED) {
@@ -938,23 +1108,23 @@ function admin_page_dbsync(&$a) {
 }
 
 /**
- * Users admin page
- *
+ * @brief Process data send by Users admin page
+ * 
  * @param App $a
  */
 function admin_page_users_post(&$a){
-       $pending = ( x($_POST, 'pending') ? $_POST['pending'] : Array() );
-       $users = ( x($_POST, 'user') ? $_POST['user'] : Array() );
-       $nu_name = ( x($_POST, 'new_user_name') ? $_POST['new_user_name'] : '');
-       $nu_nickname = ( x($_POST, 'new_user_nickname') ? $_POST['new_user_nickname'] : '');
-       $nu_email = ( x($_POST, 'new_user_email') ? $_POST['new_user_email'] : '');
+       $pending        =       (x($_POST, 'pending')                   ? $_POST['pending']             : array());
+       $users          =       (x($_POST, 'user')                      ? $_POST['user']                : array());
+       $nu_name        =       (x($_POST, 'new_user_name')             ? $_POST['new_user_name']       : '');
+       $nu_nickname    =       (x($_POST, 'new_user_nickname') ? $_POST['new_user_nickname']   : '');
+       $nu_email       =       (x($_POST, 'new_user_email')            ? $_POST['new_user_email']      : '');
 
        check_form_security_token_redirectOnErr('/admin/users', 'admin_users');
 
-       if (!($nu_name==="") && !($nu_email==="") && !($nu_nickname==="")) {
+       if(!($nu_name==="") && !($nu_email==="") && !($nu_nickname==="")) {
                require_once('include/user.php');
 
-               $result = create_user( array('username'=>$nu_name, 'email'=>$nu_email, 'nickname'=>$nu_nickname, 'verified'=>1)  );
+               $result = create_user(array('username'=>$nu_name, 'email'=>$nu_email, 'nickname'=>$nu_nickname, 'verified'=>1));
                if(! $result['success']) {
                        notice($result['message']);
                        return;
@@ -995,55 +1165,63 @@ function admin_page_users_post(&$a){
                notification(array(
                        'type' => "SYSTEM_EMAIL",
                        'to_email' => $nu['email'],
-                       'subject'=> sprintf( t('Registration details for %s'), $a->config['sitename']),
+                       'subject'=> sprintf(t('Registration details for %s'), $a->config['sitename']),
                        'preamble'=> $preamble,
                        'body' => $body));
 
        }
 
-       if (x($_POST,'page_users_block')){
+       if(x($_POST,'page_users_block')) {
                foreach($users as $uid){
                        q("UPDATE `user` SET `blocked`=1-`blocked` WHERE `uid`=%s",
-                               intval( $uid )
+                               intval($uid)
                        );
                }
-               notice( sprintf( tt("%s user blocked/unblocked", "%s users blocked/unblocked", count($users)), count($users)) );
+               notice(sprintf(tt("%s user blocked/unblocked", "%s users blocked/unblocked", count($users)), count($users)));
        }
-       if (x($_POST,'page_users_delete')){
+       if(x($_POST,'page_users_delete')) {
                require_once("include/Contact.php");
                foreach($users as $uid){
                        user_remove($uid);
                }
-               notice( sprintf( tt("%s user deleted", "%s users deleted", count($users)), count($users)) );
+               notice(sprintf(tt("%s user deleted", "%s users deleted", count($users)), count($users)));
        }
 
-       if (x($_POST,'page_users_approve')){
+       if(x($_POST,'page_users_approve')) {
                require_once("mod/regmod.php");
                foreach($pending as $hash){
                        user_allow($hash);
                }
        }
-       if (x($_POST,'page_users_deny')){
+       if(x($_POST,'page_users_deny')) {
                require_once("mod/regmod.php");
                foreach($pending as $hash){
                        user_deny($hash);
                }
        }
-       goaway($a->get_baseurl(true) . '/admin/users' );
+       goaway('admin/users');
        return; // NOTREACHED
 }
 
 /**
+ * @brief Admin panel subpage for User management
+ *
+ * This function generates the admin panel page for user management of the
+ * node. It offers functionality to add/block/delete users and offers some
+ * statistics about the userbase.
+ *
+ * The returned string holds the HTML code of the page.
+ *
  * @param App $a
  * @return string
  */
 function admin_page_users(&$a){
-       if ($a->argc>2) {
+       if($a->argc>2) {
                $uid = $a->argv[3];
                $user = q("SELECT username, blocked FROM `user` WHERE `uid`=%d", intval($uid));
-               if (count($user)==0){
-                       notice( 'User not found' . EOL);
-                       goaway($a->get_baseurl(true) . '/admin/users' );
+               if(count($user)==0) {
+                       notice('User not found'.EOL);
+                       goaway('admin/users');
                        return ''; // NOTREACHED
                }
                switch($a->argv[2]){
@@ -1053,18 +1231,18 @@ function admin_page_users(&$a){
                                require_once("include/Contact.php");
                                user_remove($uid);
 
-                               notice( sprintf(t("User '%s' deleted"), $user[0]['username']) . EOL);
+                               notice(sprintf(t("User '%s' deleted"), $user[0]['username']).EOL);
                        }; break;
                        case "block":{
                                check_form_security_token_redirectOnErr('/admin/users', 'admin_users', 't');
                                q("UPDATE `user` SET `blocked`=%d WHERE `uid`=%s",
-                                       intval( 1-$user[0]['blocked'] ),
-                                       intval( $uid )
+                                       intval(1-$user[0]['blocked']),
+                                       intval($uid)
                                );
-                               notice( sprintf( ($user[0]['blocked']?t("User '%s' unblocked"):t("User '%s' blocked")) , $user[0]['username']) . EOL);
+                               notice(sprintf(($user[0]['blocked']?t("User '%s' unblocked"):t("User '%s' blocked")) , $user[0]['username']).EOL);
                        }; break;
                }
-               goaway($a->get_baseurl(true) . '/admin/users' );
+               goaway('admin/users');
                return ''; // NOTREACHED
 
        }
@@ -1077,15 +1255,43 @@ function admin_page_users(&$a){
 
 
        /* get users */
-
        $total = q("SELECT count(*) as total FROM `user` where 1");
        if(count($total)) {
                $a->set_pager_total($total[0]['total']);
                $a->set_pager_itemspage(100);
        }
 
-
-       $users = q("SELECT `user` . * , `contact`.`name` , `contact`.`url` , `contact`.`micro`, `lastitem`.`lastitem_date`, `user`.`account_expired`
+       /* ordering */
+       $valid_orders = array(
+               'contact.name', 
+               'user.email',
+               'user.register_date',
+               'user.login_date',
+               'lastitem.lastitem_date',
+               'user.page-flags'
+       );
+       
+       $order = "contact.name";
+       $order_direction = "+";
+       if (x($_GET,'o')){
+               $new_order = $_GET['o'];
+               if ($new_order[0]==="-") {
+                       $order_direction = "-";
+                       $new_order = substr($new_order,1);
+               }
+               
+               if (in_array($new_order, $valid_orders)){
+                       $order = $new_order;
+               }
+               if (x($_GET,'d')){
+                       $new_direction = $_GET['d'];
+                       
+               }
+       }
+       $sql_order = "`".str_replace('.','`.`',$order)."`";
+       $sql_order_direction = ($order_direction==="+")?"ASC":"DESC";
+       
+       $users = q("SELECT `user`.* , `contact`.`name` , `contact`.`url` , `contact`.`micro`, `lastitem`.`lastitem_date`, `user`.`account_expired`
                                FROM
                                        (SELECT MAX(`item`.`changed`) as `lastitem_date`, `item`.`uid`
                                        FROM `item`
@@ -1097,15 +1303,17 @@ function admin_page_users(&$a){
                                           `user`.`uid` = `contact`.`uid`
                                                AND `user`.`verified` =1
                                        AND `contact`.`self` =1
-                               ORDER BY `contact`.`name` LIMIT %d, %d
+                               ORDER BY $sql_order $sql_order_direction LIMIT %d, %d
                                ",
                                intval($a->pager['start']),
                                intval($a->pager['itemspage'])
                                );
-
+    
+       //echo "<pre>$users"; killme();
+                               
        $adminlist = explode(",", str_replace(" ", "", $a->config['admin_email']));
        $_setup_users = function ($e) use ($adminlist){
-               $accounts = Array(
+               $accounts = array(
                        t('Normal Account'),
                        t('Soapbox Account'),
                        t('Community/Celebrity Account'),
@@ -1127,12 +1335,12 @@ function admin_page_users(&$a){
        // Get rid of dashes in key names, Smarty3 can't handle them
        // and extracting deleted users
 
-       $tmp_users = Array();
-       $deleted = Array();
+       $tmp_users = array();
+       $deleted = array();
 
        while(count($users)) {
-               $new_user = Array();
-               foreach( array_pop($users) as $k => $v) {
+               $new_user = array();
+               foreach(array_pop($users) as $k => $v) {
                        $k = str_replace('-','_',$k);
                        $new_user[$k] = $v;
                }
@@ -1149,6 +1357,11 @@ function admin_page_users(&$a){
                array_push($users, array_pop($tmp_users));
        }
 
+       $th_users = array_map(null,
+               array(t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'),  t('Account')),
+               $valid_orders
+       );
+       
        $t = get_markup_template("admin_users.tpl");
        $o = replace_macros($t, array(
                // strings //
@@ -1158,7 +1371,7 @@ function admin_page_users(&$a){
                '$select_all' => t('select all'),
                '$h_pending' => t('User registrations waiting for confirm'),
                '$h_deleted' => t('User waiting for permanent deletion'),
-               '$th_pending' => array( t('Request date'), t('Name'), t('Email') ),
+               '$th_pending' => array(t('Request date'), t('Name'), t('Email')),
                '$no_pending' =>  t('No registrations.'),
                '$approve' => t('Approve'),
                '$deny' => t('Deny'),
@@ -1170,8 +1383,10 @@ function admin_page_users(&$a){
 
                '$h_users' => t('Users'),
                '$h_newuser' => t('New User'),
-               '$th_deleted' => array( t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'), t('Deleted since') ),
-               '$th_users' => array( t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'),  t('Account') ),
+               '$th_deleted' => array(t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'), t('Deleted since')),
+               '$th_users' => $th_users,
+               '$order_users' => $order,
+               '$order_direction_users' => $order_direction,
 
                '$confirm_delete_multi' => t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'),
                '$confirm_delete' => t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'),
@@ -1184,9 +1399,9 @@ function admin_page_users(&$a){
                '$pending' => $pending,
                'deleted' => $deleted,
                '$users' => $users,
-               '$newusername'  => array('new_user_name', t("Name"), '', t("Name of the new user.")),
-               '$newusernickname'  => array('new_user_nickname', t("Nickname"), '', t("Nickname of the new user.")),
-               '$newuseremail'  => array('new_user_email', t("Email"), '', t("Email address of the new user."), '', '', 'email'),
+               '$newusername' => array('new_user_name', t("Name"), '', t("Name of the new user.")),
+               '$newusernickname' => array('new_user_nickname', t("Nickname"), '', t("Nickname of the new user.")),
+               '$newuseremail' => array('new_user_email', t("Email"), '', t("Email address of the new user."), '', '', 'email'),
        ));
        $o .= paginate($a);
        return $o;
@@ -1194,60 +1409,71 @@ function admin_page_users(&$a){
 
 
 /**
- * Plugins admin page
+ * @brief Plugins admin page
+ *
+ * This function generates the admin panel page for managing plugins on the
+ * friendica node. If a plugin name is given a single page showing the details
+ * for this addon is generated. If no name is given, a list of available
+ * plugins is shown.
+ *
+ * The template used for displaying the list of plugins and the details of the
+ * plugin are the same as used for the templates.
+ *
+ * The returned string returned hulds the HTML code of the page.
  *
  * @param App $a
  * @return string
  */
 function admin_page_plugins(&$a){
 
-       /**
+       /*
         * Single plugin
         */
-       if ($a->argc == 3){
+       if($a->argc == 3) {
                $plugin = $a->argv[2];
-               if (!is_file("addon/$plugin/$plugin.php")){
-                       notice( t("Item not found.") );
+               if(!is_file("addon/$plugin/$plugin.php")) {
+                       notice(t("Item not found."));
                        return '';
                }
 
-               if (x($_GET,"a") && $_GET['a']=="t"){
+               if(x($_GET,"a") && $_GET['a']=="t") {
                        check_form_security_token_redirectOnErr('/admin/plugins', 'admin_themes', 't');
 
                        // Toggle plugin status
                        $idx = array_search($plugin, $a->plugins);
-                       if ($idx !== false){
+                       if($idx !== false) {
                                unset($a->plugins[$idx]);
                                uninstall_plugin($plugin);
-                               info( sprintf( t("Plugin %s disabled."), $plugin ) );
+                               info(sprintf(t("Plugin %s disabled."), $plugin));
                        } else {
                                $a->plugins[] = $plugin;
                                install_plugin($plugin);
-                               info( sprintf( t("Plugin %s enabled."), $plugin ) );
+                               info(sprintf(t("Plugin %s enabled."), $plugin));
                        }
                        set_config("system","addon", implode(", ",$a->plugins));
-                       goaway($a->get_baseurl(true) . '/admin/plugins' );
+                       goaway('admin/plugins');
                        return ''; // NOTREACHED
                }
+
                // display plugin details
                require_once('library/markdown.php');
 
-               if (in_array($plugin, $a->plugins)){
+               if(in_array($plugin, $a->plugins)) {
                        $status="on"; $action= t("Disable");
                } else {
                        $status="off"; $action= t("Enable");
                }
 
                $readme=Null;
-               if (is_file("addon/$plugin/README.md")){
+               if(is_file("addon/$plugin/README.md")) {
                        $readme = file_get_contents("addon/$plugin/README.md");
                        $readme = Markdown($readme);
-               } else if (is_file("addon/$plugin/README")){
+               } elseif(is_file("addon/$plugin/README")) {
                        $readme = "<pre>". file_get_contents("addon/$plugin/README") ."</pre>";
                }
 
                $admin_form="";
-               if (is_array($a->plugins_admin) && in_array($plugin, $a->plugins_admin)){
+               if(is_array($a->plugins_admin) && in_array($plugin, $a->plugins_admin)) {
                        @require_once("addon/$plugin/$plugin.php");
                        $func = $plugin.'_plugin_admin';
                        $func($a, $admin_form);
@@ -1280,11 +1506,11 @@ function admin_page_plugins(&$a){
 
 
 
-       /**
+       /*
         * List plugins
         */
 
-       if (x($_GET,"a") && $_GET['a']=="r"){
+       if(x($_GET,"a") && $_GET['a']=="r") {
                check_form_security_token_redirectOnErr($a->get_baseurl().'/admin/plugins', 'admin_themes', 't');
                reload_plugins();
                info("Plugins reloaded");
@@ -1292,23 +1518,23 @@ function admin_page_plugins(&$a){
        }
 
        $plugins = array();
-       $files = glob("addon/*/"); /* */
+       $files = glob("addon/*/");
        if($files) {
                foreach($files as $file) {
-                       if (is_dir($file)){
+                       if(is_dir($file)) {
                                list($tmp, $id)=array_map("trim", explode("/",$file));
                                $info = get_plugin_info($id);
                                $show_plugin = true;
 
                                // If the addon is unsupported, then only show it, when it is enabled
-                               if ((strtolower($info["status"]) == "unsupported") AND !in_array($id,  $a->plugins))
+                               if((strtolower($info["status"]) == "unsupported") AND !in_array($id,  $a->plugins))
                                        $show_plugin = false;
 
                                // Override the above szenario, when the admin really wants to see outdated stuff
-                               if (get_config("system", "show_unsupported_addons"))
+                               if(get_config("system", "show_unsupported_addons"))
                                        $show_plugin = true;
 
-                               if ($show_plugin)
+                               if($show_plugin)
                                        $plugins[] = array($id, (in_array($id,  $a->plugins)?"on":"off") , $info);
                        }
                }
@@ -1323,6 +1549,8 @@ function admin_page_plugins(&$a){
                '$baseurl' => $a->get_baseurl(true),
                '$function' => 'plugins',
                '$plugins' => $plugins,
+               '$pcount' => count($plugins), 
+               '$noplugshint' => sprintf(t('There are currently no plugins available on your node. You can find the official plugin repository at %1$s and might find other interesting plugins in the open plugin registry at %2$s'), 'https://github.com/friendica/friendica-addons', 'http://addons.friendi.ca'),
                '$form_security_token' => get_form_security_token("admin_themes"),
        ));
 }
@@ -1387,7 +1615,17 @@ function rebuild_theme_table($themes) {
 
 
 /**
- * Themes admin page
+ * @brief Themes admin page
+ *
+ * This function generates the admin panel page to control the themes available
+ * on the friendica node. If the name of a theme is given as parameter a page
+ * with the details for the theme is shown. Otherwise a list of available
+ * themes is generated.
+ *
+ * The template used for displaying the list of themes and the details of the
+ * themes are the same as used for the plugins.
+ *
+ * The returned string contains the HTML code of the admin panel page.
  *
  * @param App $a
  * @return string
@@ -1403,36 +1641,36 @@ function admin_page_themes(&$a){
                                $allowed_themes[] = trim($x);
 
        $themes = array();
-       $files = glob('view/theme/*'); /* */
+       $files = glob('view/theme/*');
        if($files) {
                foreach($files as $file) {
                        $f = basename($file);
-                       $is_experimental = intval(file_exists($file . '/experimental'));
-                       $is_supported = 1-(intval(file_exists($file . '/unsupported')));
+                       $is_experimental = intval(file_exists($file.'/experimental'));
+                       $is_supported = 1-(intval(file_exists($file.'/unsupported')));
                        $is_allowed = intval(in_array($f,$allowed_themes));
 
-                       if ($is_allowed OR $is_supported OR get_config("system", "show_unsupported_themes"))
+                       if($is_allowed OR $is_supported OR get_config("system", "show_unsupported_themes"))
                                $themes[] = array('name' => $f, 'experimental' => $is_experimental, 'supported' => $is_supported, 'allowed' => $is_allowed);
                }
        }
 
        if(! count($themes)) {
-               notice( t('No themes found.'));
+               notice(t('No themes found.'));
                return '';
        }
 
-       /**
+       /*
         * Single theme
         */
 
-       if ($a->argc == 3){
+       if($a->argc == 3) {
                $theme = $a->argv[2];
-               if(! is_dir("view/theme/$theme")){
-                       notice( t("Item not found.") );
+               if(! is_dir("view/theme/$theme")) {
+                       notice(t("Item not found."));
                        return '';
                }
 
-               if (x($_GET,"a") && $_GET['a']=="t"){
+               if(x($_GET,"a") && $_GET['a']=="t") {
                        check_form_security_token_redirectOnErr('/admin/themes', 'admin_themes', 't');
 
                        // Toggle theme status
@@ -1441,37 +1679,37 @@ function admin_page_themes(&$a){
                        $s = rebuild_theme_table($themes);
                        if($result) {
                                install_theme($theme);
-                               info( sprintf('Theme %s enabled.',$theme));
+                               info(sprintf('Theme %s enabled.',$theme));
                        }
                        else {
                                uninstall_theme($theme);
-                               info( sprintf('Theme %s disabled.',$theme));
+                               info(sprintf('Theme %s disabled.',$theme));
                        }
 
                        set_config('system','allowed_themes',$s);
-                       goaway($a->get_baseurl(true) . '/admin/themes' );
+                       goaway('admin/themes');
                        return ''; // NOTREACHED
                }
 
                // display theme details
                require_once('library/markdown.php');
 
-               if (theme_status($themes,$theme)) {
+               if(theme_status($themes,$theme)) {
                        $status="on"; $action= t("Disable");
                } else {
                        $status="off"; $action= t("Enable");
                }
 
                $readme=Null;
-               if (is_file("view/theme/$theme/README.md")){
+               if(is_file("view/theme/$theme/README.md")) {
                        $readme = file_get_contents("view/theme/$theme/README.md");
                        $readme = Markdown($readme);
-               } else if (is_file("view/theme/$theme/README")){
+               } elseif(is_file("view/theme/$theme/README")) {
                        $readme = "<pre>". file_get_contents("view/theme/$theme/README") ."</pre>";
                }
 
                $admin_form="";
-               if (is_file("view/theme/$theme/config.php")){
+               if(is_file("view/theme/$theme/config.php")) {
                        function __get_theme_admin_form(&$a, $theme) {
                                $orig_theme = $a->theme;
                                $orig_page = $a->page;
@@ -1483,7 +1721,7 @@ function admin_page_themes(&$a){
 
                                $init = $theme."_init";
                                if(function_exists($init)) $init($a);
-                               if(function_exists("theme_admin")){
+                               if(function_exists("theme_admin")) {
                                        $admin_form = theme_admin($a);
                                }
 
@@ -1495,10 +1733,11 @@ function admin_page_themes(&$a){
                        $admin_form = __get_theme_admin_form($a, $theme);
                }
 
-               $screenshot = array( get_theme_screenshot($theme), t('Screenshot'));
+               $screenshot = array(get_theme_screenshot($theme), t('Screenshot'));
                if(! stristr($screenshot[0],$theme))
                        $screenshot = null;
 
+
                $t = get_markup_template("admin_plugins_details.tpl");
                return replace_macros($t, array(
                        '$title' => t('Administration'),
@@ -1506,7 +1745,6 @@ function admin_page_themes(&$a){
                        '$toggle' => t('Toggle'),
                        '$settings' => t('Settings'),
                        '$baseurl' => $a->get_baseurl(true),
-
                        '$plugin' => $theme,
                        '$status' => $status,
                        '$action' => $action,
@@ -1524,11 +1762,11 @@ function admin_page_themes(&$a){
 
 
        // reload active themes
-       if (x($_GET,"a") && $_GET['a']=="r"){
+       if(x($_GET,"a") && $_GET['a']=="r") {
                check_form_security_token_redirectOnErr($a->get_baseurl().'/admin/themes', 'admin_themes', 't');
-               if ($themes) {
+               if($themes) {
                        foreach($themes as $th) {
-                               if ($th['allowed']) {
+                               if($th['allowed']) {
                                        uninstall_theme($th['name']);
                                        install_theme($th['name']);
                                }
@@ -1538,7 +1776,7 @@ function admin_page_themes(&$a){
                goaway($a->get_baseurl().'/admin/themes');
        }
 
-       /**
+       /*
         * List themes
         */
 
@@ -1559,6 +1797,8 @@ function admin_page_themes(&$a){
                '$baseurl' => $a->get_baseurl(true),
                '$function' => 'themes',
                '$plugins' => $xthemes,
+               '$pcount' => count($themes),
+               '$noplugshint' => sprintf(t('No themes found on the system. They should be paced in %1$s'),'<code>/view/themes</code>'),
                '$experimental' => t('[Experimental]'),
                '$unsupported' => t('[Unsupported]'),
                '$form_security_token' => get_form_security_token("admin_themes"),
@@ -1567,38 +1807,47 @@ function admin_page_themes(&$a){
 
 
 /**
- * Logs admin page
- *
+ * @brief Prosesses data send by Logs admin page
+ * 
  * @param App $a
  */
-
 function admin_page_logs_post(&$a) {
-       if (x($_POST,"page_logs")) {
+       if(x($_POST,"page_logs")) {
                check_form_security_token_redirectOnErr('/admin/logs', 'admin_logs');
 
-               $logfile                =       ((x($_POST,'logfile'))          ? notags(trim($_POST['logfile']))       : '');
-               $debugging              =       ((x($_POST,'debugging'))        ? true                                                          : false);
-               $loglevel               =       ((x($_POST,'loglevel'))         ? intval(trim($_POST['loglevel']))      : 0);
+               $logfile        =       ((x($_POST,'logfile'))          ? notags(trim($_POST['logfile']))       : '');
+               $debugging      =       ((x($_POST,'debugging'))        ? true                                  : false);
+               $loglevel       =       ((x($_POST,'loglevel'))         ? intval(trim($_POST['loglevel']))      : 0);
 
                set_config('system','logfile', $logfile);
                set_config('system','debugging',  $debugging);
                set_config('system','loglevel', $loglevel);
-
-
        }
 
-       info( t("Log settings updated.") );
-       goaway($a->get_baseurl(true) . '/admin/logs' );
+       info(t("Log settings updated."));
+       goaway('admin/logs');
        return; // NOTREACHED
 }
 
 /**
+ * @brief Generates admin panel subpage for configuration of the logs
+ *
+ * This function take the view/templates/admin_logs.tpl file and generates a
+ * page where admin can configure the logging of friendica.
+ *
+ * Displaying the log is separated from the log config as the logfile can get
+ * big depending on the settings and changing settings regarding the logs can
+ * thus waste bandwidth.
+ *
+ * The string returned contains the content of the template file with replaced
+ * macros.
+ *
  * @param App $a
  * @return string
  */
 function admin_page_logs(&$a){
 
-       $log_choices = Array(
+       $log_choices = array(
                LOGGER_NORMAL => 'Normal',
                LOGGER_TRACE => 'Trace',
                LOGGER_DEBUG => 'Debug',
@@ -1608,13 +1857,51 @@ function admin_page_logs(&$a){
 
        $t = get_markup_template("admin_logs.tpl");
 
-       $f = get_config('system','logfile');
+       return replace_macros($t, array(
+               '$title' => t('Administration'),
+               '$page' => t('Logs'),
+               '$submit' => t('Save Settings'),
+               '$clear' => t('Clear'),
+               '$baseurl' => $a->get_baseurl(true),
+               '$logname' =>  get_config('system','logfile'),
 
+               // name, label, value, help string, extra data...
+               '$debugging' => array('debugging', t("Enable Debugging"),get_config('system','debugging'), ""),
+               '$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your Friendica top-level directory.")),
+               '$loglevel' => array('loglevel', t("Log level"), get_config('system','loglevel'), "", $log_choices),
+
+               '$form_security_token' => get_form_security_token("admin_logs"),
+               '$phpheader' => t("PHP logging"),
+               '$phphint' => t("To enable logging of PHP errors and warnings you can add the following to the .htconfig.php file of your installation. The filename set in the 'error_log' line is relative to the friendica top-level directory and must be writeable by the web server. The option '1' for 'log_errors' and 'display_errors' is to enable these options, set to '0' to disable them."),
+               '$phplogcode' => "error_reporting(E_ERROR | E_WARNING | E_PARSE);\nini_set('error_log','php.out');\nini_set('log_errors','1');\nini_set('display_errors', '1');",
+       ));
+}
+
+/**
+ * @brief Generates admin panel subpage to view the Friendica log
+ *
+ * This function loads the template view/templates/admin_viewlogs.tpl to
+ * display the systemlog content. The filename for the systemlog of friendica
+ * is relative to the base directory and taken from the config entry 'logfile'
+ * in the 'system' category.
+ *
+ * Displaying the log is separated from the log config as the logfile can get
+ * big depending on the settings and changing settings regarding the logs can
+ * thus waste bandwidth.
+ *
+ * The string returned contains the content of the template file with replaced
+ * macros.
+ *
+ * @param App $a
+ * @return string
+ */
+function admin_page_viewlogs(&$a){
+       $t = get_markup_template("admin_viewlogs.tpl");
+       $f = get_config('system','logfile');
        $data = '';
 
        if(!file_exists($f)) {
-               $data = t("Error trying to open <strong>$f</strong> log file.\r\n<br/>Check to see if file $f exist and is
-readable.");
+               $data = t("Error trying to open <strong>$f</strong> log file.\r\n<br/>Check to see if file $f exist and is readable.");
        }
        else {
                $fp = fopen($f, 'r');
@@ -1624,8 +1911,7 @@ readable.");
                else {
                        $fstat = fstat($fp);
                        $size = $fstat['size'];
-                       if($size != 0)
-                       {
+                       if($size != 0) {
                                if($size > 5000000 || $size < 0)
                                        $size = 5000000;
                                $seek = fseek($fp,0-$size,SEEK_END);
@@ -1638,80 +1924,94 @@ readable.");
                        fclose($fp);
                }
        }
-
        return replace_macros($t, array(
                '$title' => t('Administration'),
-               '$page' => t('Logs'),
-               '$submit' => t('Save Settings'),
-               '$clear' => t('Clear'),
+               '$page' => t('View Logs'),
                '$data' => $data,
-               '$baseurl' => $a->get_baseurl(true),
-               '$logname' =>  get_config('system','logfile'),
-
-                                                                       // name, label, value, help string, extra data...
-               '$debugging'            => array('debugging', t("Enable Debugging"),get_config('system','debugging'), ""),
-               '$logfile'                      => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your Friendica top-level directory.")),
-               '$loglevel'             => array('loglevel', t("Log level"), get_config('system','loglevel'), "", $log_choices),
-
-               '$form_security_token' => get_form_security_token("admin_logs"),
+               '$logname' =>  get_config('system','logfile')
        ));
 }
 
 /**
+ * @brief Prosesses data send by the features admin page
+ * 
  * @param App $a
  */
-function admin_page_remoteupdate_post(&$a) {
-       // this function should be called via ajax post
-       if(!is_site_admin()) {
-               return;
-       }
+function admin_page_features_post(&$a) {
 
+       check_form_security_token_redirectOnErr('/admin/features', 'admin_manage_features');
 
-       if (x($_POST,'remotefile') && $_POST['remotefile']!=""){
-               $remotefile = $_POST['remotefile'];
-               $ftpdata = (x($_POST['ftphost'])?$_POST:false);
-               doUpdate($remotefile, $ftpdata);
-       } else {
-               echo "No remote file to download. Abort!";
+       logger('postvars: '.print_r($_POST,true),LOGGER_DATA);
+
+       $arr = array();
+       $features = get_features(false);
+
+       foreach($features as $fname => $fdata) {
+               foreach(array_slice($fdata,1) as $f) {
+                       $feature = $f[0];
+                       $feature_state = 'feature_'.$feature;
+                       $featurelock = 'featurelock_'.$feature;
+
+                       if(x($_POST[$feature_state]))
+                               $val = intval($_POST['feature_'.$feature]);
+                       else
+                               $val = 0;
+                       set_config('feature',$feature,$val);
+
+                       if(x($_POST[$featurelock]))
+                               set_config('feature_lock',$feature,$val);
+                       else
+                               del_config('feature_lock',$feature);
+               }
        }
 
-       killme();
+       goaway('admin/features');
+       return; // NOTREACHED
 }
 
 /**
+ * @brief Subpage for global additional feature management
+ * 
+ * This functin generates the subpage 'Manage Additional Features'
+ * for the admin panel. At this page the admin can set preferences
+ * for the user settings of the 'additional features'. If needed this 
+ * preferences can be locked through the admin.
+ * 
+ * The returned string contains the HTML code of the subpage 'Manage
+ * Additional Features'
+ * 
  * @param App $a
  * @return string
  */
-function admin_page_remoteupdate(&$a) {
-       if(!is_site_admin()) {
-               return login(false);
-       }
-
-       $canwrite = canWeWrite();
-       $canftp = function_exists('ftp_connect');
+function admin_page_features(&$a) {
+       
+       if((argc() > 1) && (argv(1) === 'features')) {
+               $arr = array();
+               $features = get_features(false);
+
+               foreach($features as $fname => $fdata) {
+                       $arr[$fname] = array();
+                       $arr[$fname][0] = $fdata[0];
+                       foreach(array_slice($fdata,1) as $f) {
+
+                               $set = get_config('feature',$f[0]);
+                               if($set === false)
+                                       $set = $f[3];
+                               $arr[$fname][1][] = array(
+                                       array('feature_' .$f[0],$f[1],$set,$f[2],array(t('Off'),t('On'))),
+                                       array('featurelock_' .$f[0],sprintf(t('Lock feature %s'),$f[1]),(($f[4] !== false) ? "1" : ''),'',array(t('Off'),t('On')))
+                               );
+                       }
+               }
+               
+               $tpl = get_markup_template("admin_settings_features.tpl");
+               $o .= replace_macros($tpl, array(
+                       '$form_security_token' => get_form_security_token("admin_manage_features"),
+                       '$title' => t('Manage Additional Features'),
+                       '$features' => $arr,
+                       '$submit' => t('Save Settings'),
+               ));
 
-       $needupdate = true;
-       $u = checkUpdate();
-       if (!is_array($u)){
-               $needupdate = false;
-               $u = array('','','');
+               return $o;
        }
-
-       $tpl = get_markup_template("admin_remoteupdate.tpl");
-       return replace_macros($tpl, array(
-               '$baseurl' => $a->get_baseurl(true),
-               '$submit' => t("Update now"),
-               '$close' => t("Close"),
-               '$localversion' => FRIENDICA_VERSION,
-               '$remoteversion' => $u[1],
-               '$needupdate' => $needupdate,
-               '$canwrite' => $canwrite,
-               '$canftp'       => $canftp,
-               '$ftphost'      => array('ftphost', t("FTP Host"), '',''),
-               '$ftppath'      => array('ftppath', t("FTP Path"), '/',''),
-               '$ftpuser'      => array('ftpuser', t("FTP User"), '',''),
-               '$ftppwd'       => array('ftppwd', t("FTP Password"), '',''),
-               '$remotefile'=>array('remotefile','', $u['2'],''),
-       ));
-
 }