Merge branch 'develop' of https://github.com/friendica/friendica into develop

This commit is contained in:
Silke Meyer 2016-11-12 10:05:46 +01:00
commit 7886de5c39
406 changed files with 103030 additions and 53821 deletions

6
.gitignore vendored
View file

@ -42,3 +42,9 @@ nbproject
#ignore local folder
/local/
#ignore config files from Visual Studio
/.vs/
/php_friendica.phpproj
/php_friendica.sln
/php_friendica.phpproj.user

View file

@ -4,7 +4,14 @@ AddType audio/ogg .oga
#AddHandler php53-cgi .php
<FilesMatch "\.(out|log)$">
Deny from all
<IfModule authz_host_module>
#Apache 2.4
Require all denied
</IfModule>
<IfModule !authz_host_module>
#Apache 2.2
Deny from all
</IfModule>
</FilesMatch>
<IfModule mod_rewrite.c>

View file

@ -1,3 +1,63 @@
Version 3.5
Friendica Core:
NEW Optional local directory with possible federated contacts [heluecht]
NEW Autocompletion for @-mentions and BBCode tags [rabuzarus]
NEW Added a composer derived autoloader which allows composer autoloaders in addons/libraries [fabrixxm]
NEW theme: frio [rabuzarus, heluecht, fabrixxm]
Enhance .htaccess file (nerdoc, dissolve)
Updates to the translations (DE, ES, IS, IT, RU) [translation teams]
Updates to the documentation [tobiasd, heluecht, mexcon, silke, rabuzarus, fabrixxm, Olivier Mehani, gerhard6380, ben utzer]
Extended the BBCode by [abstract] tag used for bridged postings to networks with limited character length [heluecht]
Code cleanup [heluecht, QuixOr]
Improvements to the API and Friendica specific extensions [heluecht, fabrixxm, gerhard6380]
Improvements to the RSS/Atom feed import [mexcon]
Improvements to the communication with federated networks (Diaspora, Hubzilla, OStatus) [heluecht]
Improvements on the themes (quattro, vier, frost) [rabuzarus, fabrixxm, stieben, heluecht, Quix0r, tobiasd]
Improvements to the ACL dialog [fabrixxm, rabuzarus]
Improvements to the database structure and optimization of queries [heluecht]
Improvements to the UI (contacts, hotkeys, remember me, ARIA, code hightlighting) [rabuzarus, heluecht, tobiasd]
Improvements to the background process (poller, worker) [heluecht]
Improvements to the admin panel [tobiasd, heluecht, fabrixxm]
Improvements to the performance [heluecht]
Improvements to the installation wizzard (language selection, RINO version, check required PHP modules, default theme is now vier) [tobiasd]
Improvements to the relocation of nodes and accounts [heluecht]
Improvements to the DDoS detection [heluecht]
Improvements to the calendar/events module [heluecht, rabuzarus]
Improvements to OpenID login [strk]
Improvements to the ShaShape font [andi]
Reworked the implementation of the DFRN, Diaspora protocols [heluecht]
Reworked the notifications code [fabrixxm, rabuzarus, heluecht]
Reworked the p/config code [fabrixxm, rabuzarus]
Reworked XML generation [heluecht]
Removed now unused simplepie from library [heluecht]
Friendica Addons
Updated to the translations (DE, ES, IS, NL, PT BR), [translation teams]
Piwik [tobiasd]
Twitter Connector [heluecht]
Pumpio Connector [heluecht]
Rendertime [heluecht]
wppost [heluecht]
showmore [rabuzarus]
fromgplus [heluecht]
app.net Connector [heluecht]
GNU Social Connector [heluecht]
LDAP [Olivier Mehani]
smileybutton [rabuzarus]
retriver [mexon]
mailstream [mexon]
forumdirectory [tobiasd]
NEW notifyall (port from Hubzilla) [rabuzarus, tobiasd]
DEPRECATED cal (now in core), FB Connector, FB Post Connector, FB Sync
Closed Issues
683, 786, 796, 922, 1261, 1576, 1701, 1769, 1970, 1145, 1494,
1728, 1877, 2063, 2059, 2078, 2079, 2133, 2165, 2194, 2229, 2230,
2241, 2254, 2242, 2270, 2277, 2339, 2320, 2345, 2352, 2358, 2367,
2373, 2376, 2378, 2385, 2395, 2402, 2406, 2433, 2472, 2485, 2492,
2506, 2512, 2516, 2539, 2540, 2893, 2597, 2611, 2617, 2629, 2645,
2687, 2716, 2757, 2764
Version 3.4.3
What's new for the users:
Updates to the documentation (silke, tobiasd, annando, rebeka-catalina)

View file

@ -32,8 +32,7 @@ link if your cert is self-signed).
- Apache with mod-rewrite enabled and "Options All" so you can use a
local .htaccess file
- PHP 5.2+. The later the better. PHP 5.3 is required for communications
with the Diaspora network and improved security.
- PHP 5.4+.
- PHP *command line* access with register_argc_argv set to true in the
php.ini file [or see 'poormancron' in section 8]
@ -42,7 +41,7 @@ php.ini file [or see 'poormancron' in section 8]
- some form of email server or email gateway such that PHP mail() works
- Mysql 5.x
- Mysql 5.5.3+ or an equivalant alternative for MySQL (MariaDB, Percona Server etc.)
- ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks
(Windows) [Note: other options are presented in Section 8 of this document]

View file

@ -1,5 +1,5 @@
Friendica Communications Server
Copyright (c) 2010-2013 the Friendica Project
Copyright (c) 2010-2016 the Friendica Project
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by

View file

@ -24,12 +24,12 @@ If you want to get your work into the source tree yourself, feel free to do so a
The process is simple and friendica ships with all the tools necessary.
The location of the translated files in the source tree is
/view/LNG-CODE/
/view/lang/LNG-CODE/
where LNG-CODE is the language code used, e.g. de for German or fr for French.
The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses.
To do so, place the file in the directory mentioned above and use the "po2php" utility from the util directory of your friendica installation.
Assuming you want to convert the German localization which is placed in view/de/message.po you would do the following.
Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following.
1. Navigate at the command prompt to the base directory of your
friendica installation
@ -37,9 +37,9 @@ Assuming you want to convert the German localization which is placed in view/de/
2. Execute the po2php script, which will place the translation
in the strings.php file that is used by friendica.
$> php util/po2php.php view/de/messages.po
$> php util/po2php.php view/lang/de/messages.po
The output of the script will be placed at view/de/strings.php where
The output of the script will be placed at view/lang/de/strings.php where
friendica is expecting it, so you can test your translation immediately.
3. Visit your friendica page to check if it still works in the language you
@ -50,7 +50,7 @@ Assuming you want to convert the German localization which is placed in view/de/
not give any output if the file is ok but might give a hint for
searching the bug in the file.
$> php view/de/strings.php
$> php view/lang/de/strings.php
4. commit the two files with a meaningful commit message to your git
repository, push it to your fork of the friendica repository at github and

500
boot.php
View file

@ -36,9 +36,9 @@ require_once('include/dbstructure.php');
define ( 'FRIENDICA_PLATFORM', 'Friendica');
define ( 'FRIENDICA_CODENAME', 'Asparagus');
define ( 'FRIENDICA_VERSION', '3.5-dev' );
define ( 'FRIENDICA_VERSION', '3.5.1-dev' );
define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
define ( 'DB_UPDATE_VERSION', 1196 );
define ( 'DB_UPDATE_VERSION', 1208 );
/**
* @brief Constant with a HTML line break.
@ -53,7 +53,7 @@ define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
/**
* @brief Image storage quality.
*
*
* Lower numbers save space at cost of image detail.
* For ease of upgrade, please do not change here. Change jpeg quality with
* $a->config['system']['jpeg_quality'] = n;
@ -95,7 +95,7 @@ define ( 'DEFAULT_DB_ENGINE', 'MyISAM' );
/**
* @name SSL Policy
*
*
* SSL redirection policies
* @{
*/
@ -106,7 +106,7 @@ define ( 'SSL_POLICY_SELFSIGN', 2 );
/**
* @name Logger
*
*
* log levels
* @{
*/
@ -119,7 +119,7 @@ define ( 'LOGGER_ALL', 4 );
/**
* @name Cache
*
*
* Cache levels
* @{
*/
@ -127,11 +127,15 @@ define ( 'CACHE_MONTH', 0 );
define ( 'CACHE_WEEK', 1 );
define ( 'CACHE_DAY', 2 );
define ( 'CACHE_HOUR', 3 );
define ( 'CACHE_HALF_HOUR', 4 );
define ( 'CACHE_QUARTER_HOUR', 5 );
define ( 'CACHE_FIVE_MINUTES', 6 );
define ( 'CACHE_MINUTE', 7 );
/* @}*/
/**
* @name Register
*
*
* Registration policies
* @{
*/
@ -142,7 +146,7 @@ define ( 'REGISTER_OPEN', 2 );
/**
* @name Contact_is
*
*
* Relationship types
* @{
*/
@ -153,7 +157,7 @@ define ( 'CONTACT_IS_FRIEND', 3);
/**
* @name Update
*
*
* DB update return values
* @{
*/
@ -181,9 +185,31 @@ define ( 'PAGE_BLOG', 4 );
define ( 'PAGE_PRVGROUP', 5 );
/** @}*/
/**
* @name account types
*
* ACCOUNT_TYPE_PERSON - the account belongs to a person
* Associated page types: PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE
*
* ACCOUNT_TYPE_ORGANISATION - the account belongs to an organisation
* Associated page type: PAGE_SOAPBOX
*
* ACCOUNT_TYPE_NEWS - the account is a news reflector
* Associated page type: PAGE_SOAPBOX
*
* ACCOUNT_TYPE_COMMUNITY - the account is community forum
* Associated page types: PAGE_COMMUNITY, PAGE_PRVGROUP
* @{
*/
define ( 'ACCOUNT_TYPE_PERSON', 0 );
define ( 'ACCOUNT_TYPE_ORGANISATION',1 );
define ( 'ACCOUNT_TYPE_NEWS', 2 );
define ( 'ACCOUNT_TYPE_COMMUNITY', 3 );
/** @}*/
/**
* @name CP
*
*
* Type of the community page
* @{
*/
@ -194,7 +220,7 @@ define ( 'CP_GLOBAL_COMMUNITY', 1 );
/**
* @name Network
*
*
* Network and protocol family types
* @{
*/
@ -266,7 +292,7 @@ define ( 'ZCURL_TIMEOUT' , (-1));
/**
* @name Notify
*
*
* Email notification options
* @{
*/
@ -288,7 +314,7 @@ define ( 'NOTIFY_SYSTEM', 0x8000 );
/**
* @name Term
*
*
* Tag/term types
* @{
*/
@ -308,7 +334,7 @@ define ( 'TERM_OBJ_PHOTO', 2 );
/**
* @name Namespaces
*
*
* Various namespaces we may need to parse
* @{
*/
@ -331,7 +357,7 @@ define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' );
/**
* @name Activity
*
*
* Activity stream defines
* @{
*/
@ -377,7 +403,7 @@ define ( 'ACTIVITY_OBJ_QUESTION', 'http://activityschema.org/object/question' );
/**
* @name Gravity
*
*
* Item weight for query ordering
* @{
*/
@ -386,6 +412,20 @@ define ( 'GRAVITY_LIKE', 3);
define ( 'GRAVITY_COMMENT', 6);
/* @}*/
/**
* @name Priority
*
* Process priority for the worker
* @{
*/
define('PRIORITY_UNDEFINED', 0);
define('PRIORITY_CRITICAL', 10);
define('PRIORITY_HIGH', 20);
define('PRIORITY_MEDIUM', 30);
define('PRIORITY_LOW', 40);
define('PRIORITY_NEGLIGIBLE',50);
/* @}*/
// Normally this constant is defined - but not if "pcntl" isn't installed
if (!defined("SIGTERM"))
@ -430,9 +470,9 @@ function startup() {
/**
*
* class: App
*
*
* @brief Our main application structure for the life of this page.
*
*
* Primarily deals with the URL that got us here
* and tries to make some sense of it, and
* stores our page contents and config storage
@ -475,6 +515,7 @@ class App {
public $performance = array();
public $callstack = array();
public $theme_info = array();
public $backend = true;
public $nav_sel;
@ -516,6 +557,8 @@ class App {
*/
public $template_engine_instance = array();
public $process_id;
private $ldelim = array(
'internal' => '',
'smarty3' => '{{'
@ -557,6 +600,7 @@ class App {
$this->performance["start"] = microtime(true);
$this->performance["database"] = 0;
$this->performance["database_write"] = 0;
$this->performance["network"] = 0;
$this->performance["file"] = 0;
$this->performance["rendering"] = 0;
@ -576,6 +620,8 @@ class App {
$this->query_string = '';
$this->process_id = uniqid("log", true);
startup();
set_include_path(
@ -739,60 +785,100 @@ class App {
return($this->scheme);
}
/**
* @brief Retrieves the Friendica instance base URL
*
* This function assembles the base URL from multiple parts:
* - Protocol is determined either by the request or a combination of
* system.ssl_policy and the $ssl parameter.
* - Host name is determined either by system.hostname or inferred from request
* - Path is inferred from SCRIPT_NAME
*
* Caches the result (depending on $ssl value) for performance.
*
* Note: $ssl parameter value doesn't directly correlate with the resulting protocol
*
* @param bool $ssl Whether to append http or https under SSL_POLICY_SELFSIGN
* @return string Friendica server base URL
*/
function get_baseurl($ssl = false) {
// Is the function called statically?
if (!is_object($this))
return(self::$a->get_baseurl($ssl));
if (!is_object($this)) {
return self::$a->get_baseurl($ssl);
}
// Arbitrary values, the resulting url protocol can be different
$cache_index = $ssl ? 'https' : 'http';
// Cached value found, nothing to process
if (isset($this->baseurl[$cache_index])) {
return $this->baseurl[$cache_index];
}
$scheme = $this->scheme;
if((x($this->config,'system')) && (x($this->config['system'],'ssl_policy'))) {
if(intval($this->config['system']['ssl_policy']) === intval(SSL_POLICY_FULL))
if ((x($this->config, 'system')) && (x($this->config['system'], 'ssl_policy'))) {
if (intval($this->config['system']['ssl_policy']) === SSL_POLICY_FULL) {
$scheme = 'https';
}
// Basically, we have $ssl = true on any links which can only be seen by a logged in user
// (and also the login link). Anything seen by an outsider will have it turned off.
if($this->config['system']['ssl_policy'] == SSL_POLICY_SELFSIGN) {
if($ssl)
if ($this->config['system']['ssl_policy'] == SSL_POLICY_SELFSIGN) {
if ($ssl) {
$scheme = 'https';
else
} else {
$scheme = 'http';
}
}
}
if (get_config('config','hostname') != "")
$this->hostname = get_config('config','hostname');
if (get_config('config', 'hostname') != '') {
$this->hostname = get_config('config', 'hostname');
}
$this->baseurl = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
return $this->baseurl;
$this->baseurl[$cache_index] = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
return $this->baseurl[$cache_index];
}
/**
* @brief Initializes the baseurl components
*
* Clears the baseurl cache to prevent inconstistencies
*
* @param string $url
*/
function set_baseurl($url) {
$parsed = @parse_url($url);
$this->baseurl = $url;
$this->baseurl = [];
if($parsed) {
$this->scheme = $parsed['scheme'];
$hostname = $parsed['host'];
if(x($parsed,'port'))
if (x($parsed, 'port')) {
$hostname .= ':' . $parsed['port'];
if(x($parsed,'path'))
$this->path = trim($parsed['path'],'\\/');
}
if (x($parsed, 'path')) {
$this->path = trim($parsed['path'], '\\/');
}
if (file_exists(".htpreconfig.php"))
if (file_exists(".htpreconfig.php")) {
@include(".htpreconfig.php");
}
if (get_config('config','hostname') != "")
$this->hostname = get_config('config','hostname');
if (get_config('config', 'hostname') != '') {
$this->hostname = get_config('config', 'hostname');
}
if (!isset($this->hostname) OR ($this->hostname == ""))
if (!isset($this->hostname) OR ($this->hostname == '')) {
$this->hostname = $hostname;
}
}
}
function get_hostname() {
@ -940,7 +1026,7 @@ class App {
} else {
$r = q("SELECT `contact`.`avatar-date` AS picdate FROM `contact` WHERE `contact`.`thumb` like '%%/%s'",
$common_filename);
if(! count($r)){
if(! dbm::is_result($r)){
$this->cached_profile_image[$avatar_image] = $avatar_image;
} else {
$this->cached_profile_picdate[$common_filename] = "?rev=".urlencode($r[0]['picdate']);
@ -973,9 +1059,9 @@ class App {
/**
* @brief Register template engine class
*
*
* If $name is "", is used class static property $class::$name
*
*
* @param string $class
* @param string $name
*/
@ -993,7 +1079,7 @@ class App {
/**
* @brief Return template engine instance.
*
*
* If $name is not defined, return engine defined by theme,
* or default
*
@ -1058,6 +1144,9 @@ class App {
}
function save_timestamp($stamp, $value) {
if (!isset($this->config['system']['profiler']) || !$this->config['system']['profiler'])
return;
$duration = (float)(microtime(true)-$stamp);
if (!isset($this->performance[$value])) {
@ -1079,6 +1168,52 @@ class App {
}
/**
* @brief Log active processes into the "process" table
*/
function start_process() {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
$command = basename($trace[0]["file"]);
$this->remove_inactive_processes();
q("START TRANSACTION");
$r = q("SELECT `pid` FROM `process` WHERE `pid` = %d", intval(getmypid()));
if(!dbm::is_result($r)) {
q("INSERT INTO `process` (`pid`,`command`,`created`) VALUES (%d, '%s', '%s')",
intval(getmypid()),
dbesc($command),
dbesc(datetime_convert()));
}
q("COMMIT");
}
/**
* @brief Remove inactive processes
*/
function remove_inactive_processes() {
q("START TRANSACTION");
$r = q("SELECT `pid` FROM `process`");
if(dbm::is_result($r)) {
foreach ($r AS $process) {
if (!posix_kill($process["pid"], 0)) {
q("DELETE FROM `process` WHERE `pid` = %d", intval($process["pid"]));
}
}
}
q("COMMIT");
}
/**
* @brief Remove the active process from the "process" table
*/
function end_process() {
q("DELETE FROM `process` WHERE `pid` = %d", intval(getmypid()));
}
/**
* @brief Returns a string with a callstack. Can be used for logging.
*
@ -1098,11 +1233,6 @@ class App {
return implode(", ", $callstack);
}
function mark_timestamp($mark) {
//$this->performance["markstart"] -= microtime(true) - $this->performance["marktime"];
$this->performance["markstart"] = microtime(true) - $this->performance["markstart"] - $this->performance["marktime"];
}
function get_useragent() {
return(FRIENDICA_PLATFORM." '".FRIENDICA_CODENAME."' ".FRIENDICA_VERSION."-".DB_UPDATE_VERSION."; ".$this->get_baseurl());
}
@ -1111,6 +1241,77 @@ class App {
return($this->is_friendica_app);
}
/**
* @brief Checks if the site is called via a backend process
*
* This isn't a perfect solution. But we need this check very early.
* So we cannot wait until the modules are loaded.
*
* @return bool Is it a known backend?
*/
function is_backend() {
$backend = array();
$backend[] = "_well_known";
$backend[] = "api";
$backend[] = "dfrn_notify";
$backend[] = "fetch";
$backend[] = "hcard";
$backend[] = "hostxrd";
$backend[] = "nodeinfo";
$backend[] = "noscrape";
$backend[] = "p";
$backend[] = "poco";
$backend[] = "post";
$backend[] = "proxy";
$backend[] = "pubsub";
$backend[] = "pubsubhubbub";
$backend[] = "receive";
$backend[] = "rsd_xml";
$backend[] = "salmon";
$backend[] = "statistics_json";
$backend[] = "xrd";
if (in_array($this->module, $backend))
return(true);
else
return($this->backend);
}
/**
* @brief Checks if the maximum number of database processes is reached
*
* @return bool Is the limit reached?
*/
function max_processes_reached() {
// Is the function called statically?
if (!is_object($this))
return(self::$a->max_processes_reached());
if ($this->is_backend()) {
$process = "backend";
$max_processes = get_config('system', 'max_processes_backend');
if (intval($max_processes) == 0)
$max_processes = 5;
} else {
$process = "frontend";
$max_processes = get_config('system', 'max_processes_frontend');
if (intval($max_processes) == 0)
$max_processes = 20;
}
$processlist = dbm::processlist();
if ($processlist["list"] != "") {
logger("Processcheck: Processes: ".$processlist["amount"]." - Processlist: ".$processlist["list"], LOGGER_DEBUG);
if ($processlist["amount"] > $max_processes) {
logger("Processcheck: Maximum number of processes for ".$process." tasks (".$max_processes.") reached.", LOGGER_DEBUG);
return true;
}
}
return false;
}
/**
* @brief Checks if the maximum load is reached
*
@ -1118,14 +1319,26 @@ class App {
*/
function maxload_reached() {
$maxsysload = intval(get_config('system', 'maxloadavg'));
if ($maxsysload < 1)
$maxsysload = 50;
// Is the function called statically?
if (!is_object($this))
return(self::$a->maxload_reached());
if ($this->is_backend()) {
$process = "backend";
$maxsysload = intval(get_config('system', 'maxloadavg'));
if ($maxsysload < 1)
$maxsysload = 50;
} else {
$process = "frontend";
$maxsysload = intval(get_config('system','maxloadavg_frontend'));
if ($maxsysload < 1)
$maxsysload = 50;
}
$load = current_load();
if ($load) {
if (intval($load) > $maxsysload) {
logger('system: load '.$load.' too high.');
logger('system: load '.$load.' for '.$process.' tasks ('.$maxsysload.') too high.');
return true;
}
}
@ -1153,18 +1366,51 @@ class App {
logger("killed stale process");
// Calling a new instance
if ($task != "")
proc_run('php', $task);
proc_run(PRIORITY_MEDIUM, $task);
}
return true;
}
}
return false;
}
function proc_run($args) {
// Add the php path if it is a php call
if (count($args) && ($args[0] === 'php' OR is_int($args[0]))) {
// If the last worker fork was less than 10 seconds before then don't fork another one.
// This should prevent the forking of masses of workers.
if (get_config("system", "worker")) {
if ((time() - get_config("system", "proc_run_started")) < 10)
return;
// Set the timestamp of the last proc_run
set_config("system", "proc_run_started", time());
}
$args[0] = ((x($this->config,'php_path')) && (strlen($this->config['php_path'])) ? $this->config['php_path'] : 'php');
}
// add baseurl to args. cli scripts can't construct it
$args[] = $this->get_baseurl();
for($x = 0; $x < count($args); $x ++)
$args[$x] = escapeshellarg($args[$x]);
$cmdline = implode($args," ");
if(get_config('system','proc_windows'))
proc_close(proc_open('cmd /c start /b ' . $cmdline,array(),$foo,dirname(__FILE__)));
else
proc_close(proc_open($cmdline." &",array(),$foo,dirname(__FILE__)));
}
}
/**
* @brief Retrieve the App structure
*
*
* Useful in functions which require it but don't get it passed to them
*/
function get_app() {
@ -1275,7 +1521,7 @@ function check_db() {
$build = DB_UPDATE_VERSION;
}
if($build != DB_UPDATE_VERSION)
proc_run('php', 'include/dbupdate.php');
proc_run(PRIORITY_CRITICAL, 'include/dbupdate.php');
}
@ -1418,14 +1664,14 @@ function run_update_function($x) {
* and mark it uninstalled in the database (for now we'll remove it).
* Then go through the config list and if we have a plugin that isn't installed,
* call the install procedure and add it to the database.
*
*
* @param App $a
*
*/
function check_plugins(&$a) {
$r = q("SELECT * FROM `addon` WHERE `installed` = 1");
if(count($r))
if(dbm::is_result($r))
$installed = $r;
else
$installed = array();
@ -1484,17 +1730,17 @@ function get_guid($size=16, $prefix = "") {
}
}
/**
/**
* @brief Wrapper for adding a login box.
*
*
* @param bool $register
* If $register == true provide a registration link.
* This will most always depend on the value of $a->config['register_policy'].
* @param bool $hiddens
*
*
* @return string
* Returns the complete html for inserting into the page
*
*
* @hooks 'login_hook'
* string $o
*/
@ -1563,7 +1809,10 @@ function login($register = false, $hiddens=false) {
* @brief Used to end the current process, after saving session state.
*/
function killme() {
session_write_close();
if (!get_app()->is_backend())
session_write_close();
exit;
}
@ -1581,7 +1830,7 @@ function goaway($s) {
/**
* @brief Returns the user id of locally logged in user or false.
*
*
* @return int|bool user id or false
*/
function local_user() {
@ -1592,7 +1841,7 @@ function local_user() {
/**
* @brief Returns contact id of authenticated site visitor or false
*
*
* @return int|bool visitor_id or false
*/
function remote_user() {
@ -1648,13 +1897,14 @@ function get_max_import_size() {
* @brief Wrap calls to proc_close(proc_open()) and call hook
* so plugins can take part in process :)
*
* @param string $cmd program to run
*
* @param (string|integer) $cmd program to run or priority
*
* next args are passed as $cmd command line
* e.g.: proc_run("ls","-la","/tmp");
* or: proc_run(PRIORITY_HIGH, "include/notifier.php", "drop", $drop_id);
*
* @note $cmd and string args are surrounded with ""
*
*
* @hooks 'proc_run'
* array $arr
*/
@ -1665,7 +1915,7 @@ function proc_run($cmd){
$args = func_get_args();
$newargs = array();
if(! count($args))
if (!count($args))
return;
// expand any arrays
@ -1675,8 +1925,7 @@ function proc_run($cmd){
foreach($arg as $n) {
$newargs[] = $n;
}
}
else
} else
$newargs[] = $arg;
}
@ -1685,62 +1934,55 @@ function proc_run($cmd){
$arr = array('args' => $args, 'run_cmd' => true);
call_hooks("proc_run", $arr);
if(! $arr['run_cmd'])
if (!$arr['run_cmd'] OR !count($args))
return;
if(count($args) && $args[0] === 'php') {
if (get_config("system", "worker")) {
$argv = $args;
array_shift($argv);
$parameters = json_encode($argv);
$found = q("SELECT `id` FROM `workerqueue` WHERE `parameter` = '%s'",
dbesc($parameters));
if (!$found)
q("INSERT INTO `workerqueue` (`parameter`, `created`, `priority`)
VALUES ('%s', '%s', %d)",
dbesc($parameters),
dbesc(datetime_convert()),
intval(0));
// Should we quit and wait for the poller to be called as a cronjob?
if (get_config("system", "worker_dont_fork"))
return;
// Checking number of workers
$workers = q("SELECT COUNT(*) AS `workers` FROM `workerqueue` WHERE `executed` != '0000-00-00 00:00:00'");
// Get number of allowed number of worker threads
$queues = intval(get_config("system", "worker_queues"));
if ($queues == 0)
$queues = 4;
// If there are already enough workers running, don't fork another one
if ($workers[0]["workers"] >= $queues)
return;
// Now call the poller to execute the jobs that we just added to the queue
$args = array("php", "include/poller.php", "no_cron");
}
$args[0] = ((x($a->config,'php_path')) && (strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
if (!get_config("system", "worker") OR
(($args[0] != 'php') AND !is_int($args[0]))) {
$a->proc_run($args);
return;
}
// add baseurl to args. cli scripts can't construct it
$args[] = $a->get_baseurl();
for($x = 0; $x < count($args); $x ++)
$args[$x] = escapeshellarg($args[$x]);
$cmdline = implode($args," ");
if(get_config('system','proc_windows'))
proc_close(proc_open('cmd /c start /b ' . $cmdline,array(),$foo,dirname(__FILE__)));
if (is_int($args[0]))
$priority = $args[0];
else
proc_close(proc_open($cmdline." &",array(),$foo,dirname(__FILE__)));
$priority = PRIORITY_MEDIUM;
$argv = $args;
array_shift($argv);
$parameters = json_encode($argv);
$found = q("SELECT `id` FROM `workerqueue` WHERE `parameter` = '%s'",
dbesc($parameters));
if (!$found)
q("INSERT INTO `workerqueue` (`parameter`, `created`, `priority`)
VALUES ('%s', '%s', %d)",
dbesc($parameters),
dbesc(datetime_convert()),
intval($priority));
// Should we quit and wait for the poller to be called as a cronjob?
if (get_config("system", "worker_dont_fork"))
return;
// Checking number of workers
$workers = q("SELECT COUNT(*) AS `workers` FROM `workerqueue` WHERE `executed` != '0000-00-00 00:00:00'");
// Get number of allowed number of worker threads
$queues = intval(get_config("system", "worker_queues"));
if ($queues == 0)
$queues = 4;
// If there are already enough workers running, don't fork another one
if ($workers[0]["workers"] >= $queues)
return;
// Now call the poller to execute the jobs that we just added to the queue
$args = array("php", "include/poller.php", "no_cron");
$a->proc_run($args);
}
function current_theme(){
@ -1756,7 +1998,7 @@ function current_theme(){
$r = q("select theme from user where uid = %d limit 1",
intval($a->profile_uid)
);
if($r)
if(dbm::is_result($r))
$page_theme = $r[0]['theme'];
}
@ -1821,9 +2063,9 @@ function current_theme(){
/**
* @brief Return full URL to theme which is currently in effect.
*
*
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
*
* @return string
*/
function current_theme_url() {
@ -1869,7 +2111,7 @@ function feed_birthday($uid,$tz) {
intval($uid)
);
if($p && count($p)) {
if(dbm::is_result($p)) {
$tmp_dob = substr($p[0]['dob'],5);
if(intval($tmp_dob)) {
$y = datetime_convert($tz,$tz,'now','Y');
@ -2165,12 +2407,12 @@ function current_load() {
if (!is_array($load_arr))
return false;
return max($load_arr);
return max($load_arr[0], $load_arr[1]);
}
/**
* @brief get c-style args
*
*
* @return int
*/
function argc() {
@ -2179,7 +2421,7 @@ function argc() {
/**
* @brief Returns the value of a argv key
*
*
* @param int $x argv key
* @return string Value of the argv key
*/
@ -2192,12 +2434,12 @@ function argv($x) {
/**
* @brief Get the data which is needed for infinite scroll
*
*
* For invinite scroll we need the page number of the actual page
* and the the URI where the content of the next page comes from.
* This data is needed for the js part in main.js.
* Note: infinite scroll does only work for the network page (module)
*
*
* @param string $module The name of the module (e.g. "network")
* @return array Of infinite scroll data
* 'pageno' => $pageno The number of the actual page

View file

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 3.5-dev (Asparagus)
-- DB_UPDATE_VERSION 1196
-- Friendica 3.5.1-dev (Asparagus)
-- DB_UPDATE_VERSION 1205
-- ------------------------------------------
@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS `addon` (
`timestamp` bigint(20) NOT NULL DEFAULT 0,
`plugin_admin` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE attach
@ -31,12 +31,12 @@ CREATE TABLE IF NOT EXISTS `attach` (
`data` longblob NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`edited` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`allow_cid` mediumtext NOT NULL,
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
`deny_gid` mediumtext NOT NULL,
`allow_cid` mediumtext,
`allow_gid` mediumtext,
`deny_cid` mediumtext,
`deny_gid` mediumtext,
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE auth_codes
@ -48,19 +48,19 @@ CREATE TABLE IF NOT EXISTS `auth_codes` (
`expires` int(11) NOT NULL DEFAULT 0,
`scope` varchar(250) NOT NULL DEFAULT '',
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE cache
--
CREATE TABLE IF NOT EXISTS `cache` (
`k` varchar(255) NOT NULL,
`v` text NOT NULL,
`v` text,
`expire_mode` int(11) NOT NULL DEFAULT 0,
`updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`k`),
PRIMARY KEY(`k`(191)),
INDEX `updated` (`updated`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE challenge
@ -73,7 +73,7 @@ CREATE TABLE IF NOT EXISTS `challenge` (
`type` varchar(255) NOT NULL DEFAULT '',
`last_update` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE clients
@ -86,7 +86,7 @@ CREATE TABLE IF NOT EXISTS `clients` (
`icon` text,
`uid` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY(`client_id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE config
@ -95,10 +95,10 @@ CREATE TABLE IF NOT EXISTS `config` (
`id` int(10) unsigned NOT NULL auto_increment,
`cat` varchar(255) NOT NULL DEFAULT '',
`k` varchar(255) NOT NULL DEFAULT '',
`v` text NOT NULL,
`v` text,
PRIMARY KEY(`id`),
INDEX `cat_k` (`cat`(30),`k`(30))
) DEFAULT CHARSET=utf8;
UNIQUE INDEX `cat_k` (`cat`(30),`k`(30))
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE contact
@ -115,29 +115,30 @@ CREATE TABLE IF NOT EXISTS `contact` (
`name` varchar(255) NOT NULL DEFAULT '',
`nick` varchar(255) NOT NULL DEFAULT '',
`location` varchar(255) NOT NULL DEFAULT '',
`about` text NOT NULL,
`keywords` text NOT NULL,
`about` text,
`keywords` text,
`gender` varchar(32) NOT NULL DEFAULT '',
`xmpp` varchar(255) NOT NULL DEFAULT '',
`attag` varchar(255) NOT NULL DEFAULT '',
`avatar` varchar(255) NOT NULL DEFAULT '',
`photo` text NOT NULL,
`thumb` text NOT NULL,
`micro` text NOT NULL,
`site-pubkey` text NOT NULL,
`photo` text,
`thumb` text,
`micro` text,
`site-pubkey` text,
`issued-id` varchar(255) NOT NULL DEFAULT '',
`dfrn-id` varchar(255) NOT NULL DEFAULT '',
`url` varchar(255) NOT NULL DEFAULT '',
`nurl` varchar(255) NOT NULL DEFAULT '',
`addr` varchar(255) NOT NULL DEFAULT '',
`alias` varchar(255) NOT NULL DEFAULT '',
`pubkey` text NOT NULL,
`prvkey` text NOT NULL,
`pubkey` text,
`prvkey` text,
`batch` varchar(255) NOT NULL DEFAULT '',
`request` text NOT NULL,
`notify` text NOT NULL,
`poll` text NOT NULL,
`confirm` text NOT NULL,
`poco` text NOT NULL,
`request` text,
`notify` text,
`poll` text,
`confirm` text,
`poco` text,
`aes_allow` tinyint(1) NOT NULL DEFAULT 0,
`ret-aes` tinyint(1) NOT NULL DEFAULT 0,
`usehub` tinyint(1) NOT NULL DEFAULT 0,
@ -157,23 +158,24 @@ CREATE TABLE IF NOT EXISTS `contact` (
`writable` tinyint(1) NOT NULL DEFAULT 0,
`forum` tinyint(1) NOT NULL DEFAULT 0,
`prv` tinyint(1) NOT NULL DEFAULT 0,
`contact-type` int(11) unsigned NOT NULL DEFAULT 0,
`hidden` tinyint(1) NOT NULL DEFAULT 0,
`archive` tinyint(1) NOT NULL DEFAULT 0,
`pending` tinyint(1) NOT NULL DEFAULT 1,
`rating` tinyint(1) NOT NULL DEFAULT 0,
`reason` text NOT NULL,
`reason` text,
`closeness` tinyint(2) NOT NULL DEFAULT 99,
`info` mediumtext NOT NULL,
`info` mediumtext,
`profile-id` int(11) NOT NULL DEFAULT 0,
`bdyear` varchar(4) NOT NULL DEFAULT '',
`bd` date NOT NULL DEFAULT '0000-00-00',
`notify_new_posts` tinyint(1) NOT NULL DEFAULT 0,
`fetch_further_information` tinyint(1) NOT NULL DEFAULT 0,
`ffi_keyword_blacklist` mediumtext NOT NULL,
`ffi_keyword_blacklist` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid` (`uid`),
INDEX `nurl` (`nurl`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE conv
@ -181,15 +183,15 @@ CREATE TABLE IF NOT EXISTS `contact` (
CREATE TABLE IF NOT EXISTS `conv` (
`id` int(10) unsigned NOT NULL auto_increment,
`guid` varchar(64) NOT NULL DEFAULT '',
`recips` mediumtext NOT NULL,
`recips` mediumtext,
`uid` int(11) NOT NULL DEFAULT 0,
`creator` varchar(255) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`subject` mediumtext NOT NULL,
`subject` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid` (`uid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE deliverq
@ -200,7 +202,7 @@ CREATE TABLE IF NOT EXISTS `deliverq` (
`item` int(11) NOT NULL DEFAULT 0,
`contact` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE event
@ -214,26 +216,27 @@ CREATE TABLE IF NOT EXISTS `event` (
`edited` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`start` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`finish` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`summary` text NOT NULL,
`desc` text NOT NULL,
`location` text NOT NULL,
`summary` text,
`desc` text,
`location` text,
`type` varchar(255) NOT NULL DEFAULT '',
`nofinish` tinyint(1) NOT NULL DEFAULT 0,
`adjust` tinyint(1) NOT NULL DEFAULT 1,
`ignore` tinyint(1) unsigned NOT NULL DEFAULT 0,
`allow_cid` mediumtext NOT NULL,
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
`deny_gid` mediumtext NOT NULL,
`allow_cid` mediumtext,
`allow_gid` mediumtext,
`deny_cid` mediumtext,
`deny_gid` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid` (`uid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE fcontact
--
CREATE TABLE IF NOT EXISTS `fcontact` (
`id` int(10) unsigned NOT NULL auto_increment,
`guid` varchar(255) NOT NULL DEFAULT '',
`url` varchar(255) NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
`photo` varchar(255) NOT NULL DEFAULT '',
@ -247,11 +250,11 @@ CREATE TABLE IF NOT EXISTS `fcontact` (
`priority` tinyint(1) NOT NULL DEFAULT 0,
`network` varchar(32) NOT NULL DEFAULT '',
`alias` varchar(255) NOT NULL DEFAULT '',
`pubkey` text NOT NULL,
`pubkey` text,
`updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`id`),
INDEX `addr` (`addr`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE ffinder
@ -262,7 +265,7 @@ CREATE TABLE IF NOT EXISTS `ffinder` (
`cid` int(10) unsigned NOT NULL DEFAULT 0,
`fid` int(10) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE fserver
@ -271,10 +274,10 @@ CREATE TABLE IF NOT EXISTS `fserver` (
`id` int(11) NOT NULL auto_increment,
`server` varchar(255) NOT NULL DEFAULT '',
`posturl` varchar(255) NOT NULL DEFAULT '',
`key` text NOT NULL,
`key` text,
PRIMARY KEY(`id`),
INDEX `server` (`server`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE fsuggest
@ -287,10 +290,10 @@ CREATE TABLE IF NOT EXISTS `fsuggest` (
`url` varchar(255) NOT NULL DEFAULT '',
`request` varchar(255) NOT NULL DEFAULT '',
`photo` varchar(255) NOT NULL DEFAULT '',
`note` text NOT NULL,
`note` text,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE gcign
@ -302,7 +305,7 @@ CREATE TABLE IF NOT EXISTS `gcign` (
PRIMARY KEY(`id`),
INDEX `uid` (`uid`),
INDEX `gcid` (`gcid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE gcontact
@ -320,16 +323,17 @@ CREATE TABLE IF NOT EXISTS `gcontact` (
`last_contact` datetime DEFAULT '0000-00-00 00:00:00',
`last_failure` datetime DEFAULT '0000-00-00 00:00:00',
`location` varchar(255) NOT NULL DEFAULT '',
`about` text NOT NULL,
`keywords` text NOT NULL,
`about` text,
`keywords` text,
`gender` varchar(32) NOT NULL DEFAULT '',
`birthday` varchar(32) NOT NULL DEFAULT '0000-00-00',
`community` tinyint(1) NOT NULL DEFAULT 0,
`contact-type` tinyint(1) NOT NULL DEFAULT -1,
`hide` tinyint(1) NOT NULL DEFAULT 0,
`nsfw` tinyint(1) NOT NULL DEFAULT 0,
`network` varchar(255) NOT NULL DEFAULT '',
`addr` varchar(255) NOT NULL DEFAULT '',
`notify` text NOT NULL,
`notify` text,
`alias` varchar(255) NOT NULL DEFAULT '',
`generation` tinyint(3) NOT NULL DEFAULT 0,
`server_url` varchar(255) NOT NULL DEFAULT '',
@ -339,7 +343,7 @@ CREATE TABLE IF NOT EXISTS `gcontact` (
INDEX `nick` (`nick`),
INDEX `addr` (`addr`),
INDEX `updated` (`updated`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE glink
@ -355,7 +359,7 @@ CREATE TABLE IF NOT EXISTS `glink` (
INDEX `cid_uid_gcid_zcid` (`cid`,`uid`,`gcid`,`zcid`),
INDEX `gcid` (`gcid`),
INDEX `zcid` (`zcid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE group
@ -368,7 +372,7 @@ CREATE TABLE IF NOT EXISTS `group` (
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY(`id`),
INDEX `uid` (`uid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE group_member
@ -380,7 +384,7 @@ CREATE TABLE IF NOT EXISTS `group_member` (
`contact-id` int(10) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
INDEX `uid_gid_contactid` (`uid`,`gid`,`contact-id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE gserver
@ -391,7 +395,7 @@ CREATE TABLE IF NOT EXISTS `gserver` (
`nurl` varchar(255) NOT NULL DEFAULT '',
`version` varchar(255) NOT NULL DEFAULT '',
`site_name` varchar(255) NOT NULL DEFAULT '',
`info` text NOT NULL,
`info` text,
`register_policy` tinyint(1) NOT NULL DEFAULT 0,
`poco` varchar(255) NOT NULL DEFAULT '',
`noscrape` varchar(255) NOT NULL DEFAULT '',
@ -403,7 +407,7 @@ CREATE TABLE IF NOT EXISTS `gserver` (
`last_failure` datetime DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`id`),
INDEX `nurl` (`nurl`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE hook
@ -416,7 +420,7 @@ CREATE TABLE IF NOT EXISTS `hook` (
`priority` int(11) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
INDEX `hook_file_function` (`hook`(30),`file`(60),`function`(30))
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE intro
@ -428,13 +432,13 @@ CREATE TABLE IF NOT EXISTS `intro` (
`contact-id` int(11) NOT NULL DEFAULT 0,
`knowyou` tinyint(1) NOT NULL DEFAULT 0,
`duplex` tinyint(1) NOT NULL DEFAULT 0,
`note` text NOT NULL,
`note` text,
`hash` varchar(255) NOT NULL DEFAULT '',
`datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`blocked` tinyint(1) NOT NULL DEFAULT 1,
`ignore` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE item
@ -458,34 +462,36 @@ CREATE TABLE IF NOT EXISTS `item` (
`commented` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`received` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`changed` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`owner-id` int(11) NOT NULL DEFAULT 0,
`owner-name` varchar(255) NOT NULL DEFAULT '',
`owner-link` varchar(255) NOT NULL DEFAULT '',
`owner-avatar` varchar(255) NOT NULL DEFAULT '',
`author-id` int(11) NOT NULL DEFAULT 0,
`author-name` varchar(255) NOT NULL DEFAULT '',
`author-link` varchar(255) NOT NULL DEFAULT '',
`author-avatar` varchar(255) NOT NULL DEFAULT '',
`title` varchar(255) NOT NULL DEFAULT '',
`body` mediumtext NOT NULL,
`body` mediumtext,
`app` varchar(255) NOT NULL DEFAULT '',
`verb` varchar(255) NOT NULL DEFAULT '',
`object-type` varchar(255) NOT NULL DEFAULT '',
`object` text NOT NULL,
`object` text,
`target-type` varchar(255) NOT NULL DEFAULT '',
`target` text NOT NULL,
`postopts` text NOT NULL,
`target` text,
`postopts` text,
`plink` varchar(255) NOT NULL DEFAULT '',
`resource-id` varchar(255) NOT NULL DEFAULT '',
`event-id` int(11) NOT NULL DEFAULT 0,
`tag` mediumtext NOT NULL,
`attach` mediumtext NOT NULL,
`inform` mediumtext NOT NULL,
`file` mediumtext NOT NULL,
`tag` mediumtext,
`attach` mediumtext,
`inform` mediumtext,
`file` mediumtext,
`location` varchar(255) NOT NULL DEFAULT '',
`coord` varchar(255) NOT NULL DEFAULT '',
`allow_cid` mediumtext NOT NULL,
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
`deny_gid` mediumtext NOT NULL,
`allow_cid` mediumtext,
`allow_gid` mediumtext,
`deny_cid` mediumtext,
`deny_gid` mediumtext,
`private` tinyint(1) NOT NULL DEFAULT 0,
`pubmail` tinyint(1) NOT NULL DEFAULT 0,
`moderated` tinyint(1) NOT NULL DEFAULT 0,
@ -501,7 +507,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`mention` tinyint(1) NOT NULL DEFAULT 0,
`network` varchar(32) NOT NULL DEFAULT '',
`rendered-hash` varchar(32) NOT NULL DEFAULT '',
`rendered-html` mediumtext NOT NULL,
`rendered-html` mediumtext,
`global` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
INDEX `guid` (`guid`),
@ -519,15 +525,18 @@ CREATE TABLE IF NOT EXISTS `item` (
INDEX `uid_title` (`uid`,`title`),
INDEX `uid_thrparent` (`uid`,`thr-parent`),
INDEX `uid_parenturi` (`uid`,`parent-uri`),
INDEX `uid_contactid_id` (`uid`,`contact-id`,`id`),
INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`),
INDEX `gcontactid_uid_created` (`gcontact-id`,`uid`,`created`),
INDEX `authorid_created` (`author-id`,`created`),
INDEX `ownerid_created` (`owner-id`,`created`),
INDEX `wall_body` (`wall`,`body`(6)),
INDEX `uid_visible_moderated_created` (`uid`,`visible`,`moderated`,`created`),
INDEX `uid_uri` (`uid`,`uri`),
INDEX `uid_wall_created` (`uid`,`wall`,`created`),
INDEX `resource-id` (`resource-id`),
INDEX `uid_type` (`uid`,`type`),
INDEX `uid_starred` (`uid`,`starred`),
INDEX `uid_starred_id` (`uid`,`starred`,`id`),
INDEX `contactid_allowcid_allowpid_denycid_denygid` (`contact-id`,`allow_cid`(10),`allow_gid`(10),`deny_cid`(10),`deny_gid`(10)),
INDEX `uid_wall_parent_created` (`uid`,`wall`,`parent`,`created`),
INDEX `uid_type_changed` (`uid`,`type`,`changed`),
@ -537,7 +546,7 @@ CREATE TABLE IF NOT EXISTS `item` (
INDEX `uid_eventid` (`uid`,`event-id`),
INDEX `uid_authorlink` (`uid`,`author-link`),
INDEX `uid_ownerlink` (`uid`,`owner-link`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE item_id
@ -553,7 +562,7 @@ CREATE TABLE IF NOT EXISTS `item_id` (
INDEX `sid` (`sid`),
INDEX `service` (`service`),
INDEX `iid` (`iid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE locks
@ -564,7 +573,7 @@ CREATE TABLE IF NOT EXISTS `locks` (
`locked` tinyint(1) NOT NULL DEFAULT 0,
`created` datetime DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE mail
@ -579,7 +588,7 @@ CREATE TABLE IF NOT EXISTS `mail` (
`contact-id` varchar(255) NOT NULL DEFAULT '',
`convid` int(11) unsigned NOT NULL DEFAULT 0,
`title` varchar(255) NOT NULL DEFAULT '',
`body` mediumtext NOT NULL,
`body` mediumtext,
`seen` tinyint(1) NOT NULL DEFAULT 0,
`reply` tinyint(1) NOT NULL DEFAULT 0,
`replied` tinyint(1) NOT NULL DEFAULT 0,
@ -594,7 +603,7 @@ CREATE TABLE IF NOT EXISTS `mail` (
INDEX `reply` (`reply`),
INDEX `uri` (`uri`),
INDEX `parent-uri` (`parent-uri`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE mailacct
@ -607,14 +616,14 @@ CREATE TABLE IF NOT EXISTS `mailacct` (
`ssltype` varchar(16) NOT NULL DEFAULT '',
`mailbox` varchar(255) NOT NULL DEFAULT '',
`user` varchar(255) NOT NULL DEFAULT '',
`pass` text NOT NULL,
`pass` text,
`reply_to` varchar(255) NOT NULL DEFAULT '',
`action` int(11) NOT NULL DEFAULT 0,
`movetofolder` varchar(255) NOT NULL DEFAULT '',
`pubmail` tinyint(1) NOT NULL DEFAULT 0,
`last_check` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE manage
@ -625,7 +634,7 @@ CREATE TABLE IF NOT EXISTS `manage` (
`mid` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
INDEX `uid_mid` (`uid`,`mid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE notify
@ -638,7 +647,7 @@ CREATE TABLE IF NOT EXISTS `notify` (
`url` varchar(255) NOT NULL DEFAULT '',
`photo` varchar(255) NOT NULL DEFAULT '',
`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`msg` mediumtext NOT NULL,
`msg` mediumtext,
`uid` int(11) NOT NULL DEFAULT 0,
`link` varchar(255) NOT NULL DEFAULT '',
`iid` int(11) NOT NULL DEFAULT 0,
@ -646,9 +655,11 @@ CREATE TABLE IF NOT EXISTS `notify` (
`seen` tinyint(1) NOT NULL DEFAULT 0,
`verb` varchar(255) NOT NULL DEFAULT '',
`otype` varchar(16) NOT NULL DEFAULT '',
`name_cache` tinytext,
`msg_name` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid` (`uid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE notify-threads
@ -662,18 +673,18 @@ CREATE TABLE IF NOT EXISTS `notify-threads` (
PRIMARY KEY(`id`),
INDEX `master-parent-item` (`master-parent-item`),
INDEX `receiver-uid` (`receiver-uid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE oembed
--
CREATE TABLE IF NOT EXISTS `oembed` (
`url` varchar(255) NOT NULL,
`content` text NOT NULL,
`content` text,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`url`),
PRIMARY KEY(`url`(191)),
INDEX `created` (`created`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE parsed_url
@ -682,11 +693,11 @@ CREATE TABLE IF NOT EXISTS `parsed_url` (
`url` varchar(255) NOT NULL,
`guessing` tinyint(1) NOT NULL DEFAULT 0,
`oembed` tinyint(1) NOT NULL DEFAULT 0,
`content` text NOT NULL,
`content` text,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`url`,`guessing`,`oembed`),
PRIMARY KEY(`url`(191),`guessing`,`oembed`),
INDEX `created` (`created`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE pconfig
@ -696,10 +707,10 @@ CREATE TABLE IF NOT EXISTS `pconfig` (
`uid` int(11) NOT NULL DEFAULT 0,
`cat` varchar(255) NOT NULL DEFAULT '',
`k` varchar(255) NOT NULL DEFAULT '',
`v` mediumtext NOT NULL,
`v` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid_cat_k` (`uid`,`cat`(30),`k`(30))
) DEFAULT CHARSET=utf8;
UNIQUE INDEX `uid_cat_k` (`uid`,`cat`(30),`k`(30))
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE photo
@ -713,7 +724,7 @@ CREATE TABLE IF NOT EXISTS `photo` (
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`edited` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`title` varchar(255) NOT NULL DEFAULT '',
`desc` text NOT NULL,
`desc` text,
`album` varchar(255) NOT NULL DEFAULT '',
`filename` varchar(255) NOT NULL DEFAULT '',
`type` varchar(128) NOT NULL DEFAULT 'image/jpeg',
@ -723,15 +734,15 @@ CREATE TABLE IF NOT EXISTS `photo` (
`data` mediumblob NOT NULL,
`scale` tinyint(3) NOT NULL DEFAULT 0,
`profile` tinyint(1) NOT NULL DEFAULT 0,
`allow_cid` mediumtext NOT NULL,
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
`deny_gid` mediumtext NOT NULL,
`allow_cid` mediumtext,
`allow_gid` mediumtext,
`deny_cid` mediumtext,
`deny_gid` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid` (`uid`),
INDEX `resource-id` (`resource-id`),
INDEX `guid` (`guid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE poll
@ -739,19 +750,19 @@ CREATE TABLE IF NOT EXISTS `photo` (
CREATE TABLE IF NOT EXISTS `poll` (
`id` int(11) NOT NULL auto_increment,
`uid` int(11) NOT NULL DEFAULT 0,
`q0` mediumtext NOT NULL,
`q1` mediumtext NOT NULL,
`q2` mediumtext NOT NULL,
`q3` mediumtext NOT NULL,
`q4` mediumtext NOT NULL,
`q5` mediumtext NOT NULL,
`q6` mediumtext NOT NULL,
`q7` mediumtext NOT NULL,
`q8` mediumtext NOT NULL,
`q9` mediumtext NOT NULL,
`q0` mediumtext,
`q1` mediumtext,
`q2` mediumtext,
`q3` mediumtext,
`q4` mediumtext,
`q5` mediumtext,
`q6` mediumtext,
`q7` mediumtext,
`q8` mediumtext,
`q9` mediumtext,
PRIMARY KEY(`id`),
INDEX `uid` (`uid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE poll_result
@ -763,7 +774,18 @@ CREATE TABLE IF NOT EXISTS `poll_result` (
PRIMARY KEY(`id`),
INDEX `poll_id` (`poll_id`),
INDEX `choice` (`choice`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE process
--
CREATE TABLE IF NOT EXISTS `process` (
`pid` int(10) unsigned NOT NULL,
`command` varchar(32) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`pid`),
INDEX `command` (`command`)
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE profile
@ -785,34 +807,35 @@ CREATE TABLE IF NOT EXISTS `profile` (
`hometown` varchar(255) NOT NULL DEFAULT '',
`gender` varchar(32) NOT NULL DEFAULT '',
`marital` varchar(255) NOT NULL DEFAULT '',
`with` text NOT NULL,
`with` text,
`howlong` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`sexual` varchar(255) NOT NULL DEFAULT '',
`politic` varchar(255) NOT NULL DEFAULT '',
`religion` varchar(255) NOT NULL DEFAULT '',
`pub_keywords` text NOT NULL,
`prv_keywords` text NOT NULL,
`likes` text NOT NULL,
`dislikes` text NOT NULL,
`about` text NOT NULL,
`pub_keywords` text,
`prv_keywords` text,
`likes` text,
`dislikes` text,
`about` text,
`summary` varchar(255) NOT NULL DEFAULT '',
`music` text NOT NULL,
`book` text NOT NULL,
`tv` text NOT NULL,
`film` text NOT NULL,
`interest` text NOT NULL,
`romance` text NOT NULL,
`work` text NOT NULL,
`education` text NOT NULL,
`contact` text NOT NULL,
`music` text,
`book` text,
`tv` text,
`film` text,
`interest` text,
`romance` text,
`work` text,
`education` text,
`contact` text,
`homepage` varchar(255) NOT NULL DEFAULT '',
`xmpp` varchar(255) NOT NULL DEFAULT '',
`photo` varchar(255) NOT NULL DEFAULT '',
`thumb` varchar(255) NOT NULL DEFAULT '',
`publish` tinyint(1) NOT NULL DEFAULT 0,
`net-publish` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
INDEX `hometown` (`hometown`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE profile_check
@ -825,7 +848,7 @@ CREATE TABLE IF NOT EXISTS `profile_check` (
`sec` varchar(255) NOT NULL DEFAULT '',
`expire` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE push_subscriber
@ -840,7 +863,7 @@ CREATE TABLE IF NOT EXISTS `push_subscriber` (
`last_update` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`secret` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE queue
@ -851,7 +874,7 @@ CREATE TABLE IF NOT EXISTS `queue` (
`network` varchar(32) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`content` mediumtext NOT NULL,
`content` mediumtext,
`batch` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
INDEX `cid` (`cid`),
@ -859,7 +882,7 @@ CREATE TABLE IF NOT EXISTS `queue` (
INDEX `last` (`last`),
INDEX `network` (`network`),
INDEX `batch` (`batch`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE register
@ -872,7 +895,7 @@ CREATE TABLE IF NOT EXISTS `register` (
`password` varchar(255) NOT NULL DEFAULT '',
`language` varchar(16) NOT NULL DEFAULT '',
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE search
@ -884,7 +907,7 @@ CREATE TABLE IF NOT EXISTS `search` (
PRIMARY KEY(`id`),
INDEX `uid` (`uid`),
INDEX `term` (`term`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE session
@ -892,12 +915,12 @@ CREATE TABLE IF NOT EXISTS `search` (
CREATE TABLE IF NOT EXISTS `session` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`sid` varchar(255) NOT NULL DEFAULT '',
`data` text NOT NULL,
`data` text,
`expire` int(10) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
INDEX `sid` (`sid`),
INDEX `expire` (`expire`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE sign
@ -905,12 +928,12 @@ CREATE TABLE IF NOT EXISTS `session` (
CREATE TABLE IF NOT EXISTS `sign` (
`id` int(10) unsigned NOT NULL auto_increment,
`iid` int(10) unsigned NOT NULL DEFAULT 0,
`signed_text` mediumtext NOT NULL,
`signature` text NOT NULL,
`signed_text` mediumtext,
`signature` text,
`signer` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY(`id`),
INDEX `iid` (`iid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE spam
@ -927,7 +950,7 @@ CREATE TABLE IF NOT EXISTS `spam` (
INDEX `spam` (`spam`),
INDEX `ham` (`ham`),
INDEX `term` (`term`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE term
@ -952,7 +975,7 @@ CREATE TABLE IF NOT EXISTS `term` (
INDEX `uid_otype_type_term_global_created` (`uid`,`otype`,`type`,`term`,`global`,`created`),
INDEX `otype_type_term_tid` (`otype`,`type`,`term`,`tid`),
INDEX `guid` (`guid`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE thread
@ -962,6 +985,8 @@ CREATE TABLE IF NOT EXISTS `thread` (
`uid` int(10) unsigned NOT NULL DEFAULT 0,
`contact-id` int(11) unsigned NOT NULL DEFAULT 0,
`gcontact-id` int(11) unsigned NOT NULL DEFAULT 0,
`owner-id` int(11) unsigned NOT NULL DEFAULT 0,
`author-id` int(11) unsigned NOT NULL DEFAULT 0,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`edited` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`commented` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
@ -994,20 +1019,20 @@ CREATE TABLE IF NOT EXISTS `thread` (
INDEX `wall_private_received` (`wall`,`private`,`received`),
INDEX `uid_created` (`uid`,`created`),
INDEX `uid_commented` (`uid`,`commented`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE tokens
--
CREATE TABLE IF NOT EXISTS `tokens` (
`id` varchar(40) NOT NULL,
`secret` text NOT NULL,
`secret` text,
`client_id` varchar(20) NOT NULL DEFAULT '',
`expires` int(11) NOT NULL DEFAULT 0,
`scope` varchar(200) NOT NULL DEFAULT '',
`uid` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE user
@ -1027,10 +1052,10 @@ CREATE TABLE IF NOT EXISTS `user` (
`default-location` varchar(255) NOT NULL DEFAULT '',
`allow_location` tinyint(1) NOT NULL DEFAULT 0,
`theme` varchar(255) NOT NULL DEFAULT '',
`pubkey` text NOT NULL,
`prvkey` text NOT NULL,
`spubkey` text NOT NULL,
`sprvkey` text NOT NULL,
`pubkey` text,
`prvkey` text,
`spubkey` text,
`sprvkey` text,
`verified` tinyint(1) unsigned NOT NULL DEFAULT 0,
`blocked` tinyint(1) unsigned NOT NULL DEFAULT 0,
`blockwall` tinyint(1) unsigned NOT NULL DEFAULT 0,
@ -1040,6 +1065,7 @@ CREATE TABLE IF NOT EXISTS `user` (
`cntunkmail` int(11) NOT NULL DEFAULT 10,
`notify-flags` int(11) unsigned NOT NULL DEFAULT 65535,
`page-flags` int(11) unsigned NOT NULL DEFAULT 0,
`account-type` int(11) unsigned NOT NULL DEFAULT 0,
`prvnets` tinyint(1) NOT NULL DEFAULT 0,
`pwdreset` varchar(255) NOT NULL DEFAULT '',
`maxreq` int(11) NOT NULL DEFAULT 10,
@ -1050,14 +1076,14 @@ CREATE TABLE IF NOT EXISTS `user` (
`expire_notification_sent` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`service_class` varchar(32) NOT NULL DEFAULT '',
`def_gid` int(11) NOT NULL DEFAULT 0,
`allow_cid` mediumtext NOT NULL,
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
`deny_gid` mediumtext NOT NULL,
`openidserver` text NOT NULL,
`allow_cid` mediumtext,
`allow_gid` mediumtext,
`deny_cid` mediumtext,
`deny_gid` mediumtext,
`openidserver` text,
PRIMARY KEY(`uid`),
INDEX `nickname` (`nickname`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE userd
@ -1067,19 +1093,19 @@ CREATE TABLE IF NOT EXISTS `userd` (
`username` varchar(255) NOT NULL,
PRIMARY KEY(`id`),
INDEX `username` (`username`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;
--
-- TABLE workerqueue
--
CREATE TABLE IF NOT EXISTS `workerqueue` (
`id` int(11) NOT NULL auto_increment,
`parameter` text NOT NULL,
`parameter` text,
`priority` tinyint(3) unsigned NOT NULL DEFAULT 0,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`pid` int(11) NOT NULL DEFAULT 0,
`executed` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY(`id`),
INDEX `created` (`created`)
) DEFAULT CHARSET=utf8;
) DEFAULT CHARSET=utf8mb4;

View file

@ -1,202 +1,612 @@
Friendica BBCode tags reference
========================
* [Home](help)
* [Creating posts](help/Text_editor)
Inline
-----
## Inline
<style>
table.bbcodes {
margin: 1em 0;
background-color: #f9f9f9;
border: 1px solid #aaa;
border-collapse: collapse;
color: #000;
width: 100%;
}
<pre>[b]bold[/b]</pre> : <strong>bold</strong>
table.bbcodes > tr > th,
table.bbcodes > tr > td,
table.bbcodes > * > tr > th,
table.bbcodes > * > tr > td {
border: 1px solid #aaa;
padding: 0.2em 0.4em
}
<pre>[i]italic[/i]</pre> : <em>italic</em>
table.bbcodes > tr > th,
table.bbcodes > * > tr > th {
background-color: #f2f2f2;
text-align: center;
width: 50%
}
</style>
<pre>[u]underlined[/u]</pre> : <u>underlined</u>
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[b]bold[/b]</td>
<td><strong>bold</strong></td>
</tr>
<tr>
<td>[i]italic[/i]</td>
<td><em>italic</em></td>
</tr>
<tr>
<td>[u]underlined[/u]</td>
<td><u>underlined</u></td>
</tr>
<tr>
<td>[s]strike[/s]</td>
<td><strike>strike</strike></td>
</tr>
<tr>
<td>[o]overline[/o]</td>
<td><span class="overline">overline</span></td>
</tr>
<tr>
<td>[color=red]red[/color]</td>
<td><span style="color: red;">red</span></td>
</tr>
<tr>
<td>[url=http://www.friendica.com]Friendica[/url]</td>
<td><a href="http://www.friendica.com" target="external-link">Friendica</a></td>
</tr>
<tr>
<td>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto"></td>
</tr>
<tr>
<td>[img=64x32]http://friendica.com/sites/default/files/friendika-32.png[/img]<br>
<br>Note: provided height is simply discarded.</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" style="width: 64px;"></td>
</tr>
<tr>
<td>[size=xx-small]small text[/size]</td>
<td><span style="font-size: xx-small;">small text</span></td>
</tr>
<tr>
<td>[size=xx-large]big text[/size]</td>
<td><span style="font-size: xx-large;">big text</span></td>
</tr>
<tr>
<td>[size=20]exact size[/size] (size can be any number, in pixel)</td>
<td><span style="font-size: 20px;">exact size</span></td>
</tr>
<tr>
<td>[font=serif]Serif font[/font]</td>
<td><span style="font-family: serif;">Serif font</span></td>
</tr>
</table>
<pre>[s]strike[/s]</pre> : <strike>strike</strike>
### Links
<pre>[color=red]red[/color]</pre> : <span style="color: red;">red</span>
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[url]http://friendica.com[/url]</td>
<td><a href="http://friendica.com">http://friendica.com</a></td>
</tr>
<tr>
<td>[url=http://friendica.com]Friendica[/url]</td>
<td><a href="http://friendica.com">Friendica</a></td>
</tr>
<tr>
<td>[bookmark]http://friendica.com[/bookmark]<br><br>
#^[url]http://friendica.com[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">http://friendica.com</a></h4></span></td>
</tr>
<tr>
<td>[bookmark=http://friendica.com]Bookmark[/bookmark]<br><br>
#^[url=http://friendica.com]Bookmark[/url]<br><br>
#[url=http://friendica.com]^[/url][url=http://friendica.com]Bookmark[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">Bookmark</a></h4></span></td>
</tr>
<tr>
<td>[url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora post with GUID[/url]</td>
<td><a href="/display/f16d77b0630f0134740c0cc47a0ea02a" target="_blank">Diaspora post with GUID</a></td>
</tr>
<tr>
<td>#Friendica</td>
<td>#<a href="/search?tag=Friendica">Friendica</a></td>
</tr>
<tr>
<td>@Mention</td>
<td>@<a href="javascript:void(0)">Mention</a></td>
</tr>
<tr>
<td>acct:account@friendica.host.com (WebFinger)</td>
<td><a href="/acctlink?addr=account@friendica.host.com" target="extlink">acct:account@friendica.host.com</a></td>
</tr>
<tr>
<td>[mail]user@mail.example.com[/mail]</td>
<td><a href="mailto:user@mail.example.com">user@mail.example.com</a></td>
</tr>
<tr>
<td>[mail=user@mail.example.com]Send an email to User[/mail]</td>
<td><a href="mailto:user@mail.example.com">Send an email to User</a></td>
</tr>
</table>
<pre>[url=http://www.friendica.com]Friendica[/url]</pre> : <a href="http://www.friendica.com" target="external-link">Friendica</a>
## Blocks
<pre>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</pre> : <img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto">
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[p]A paragraph of text[/p]</td>
<td><p>A paragraph of text</p></td>
</tr>
<tr>
<td>Inline [code]code[/code] in a paragraph</td>
<td>Inline <key>code</key> in a paragraph</td>
</tr>
<tr>
<td>[code]Multi<br>line<br>code[/code]</td>
<td><code>Multi
line
code</code></td>
</tr>
<tr>
<td>[code=php]function text_highlight($s,$lang)[/code]</td>
<td><code><div class="hl-main"><ol class="hl-main"><li><span class="hl-code">&nbsp;</span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">text_highlight</span><span class="hl-brackets">(</span><span class="hl-var">$s</span><span class="hl-code">,</span><span class="hl-var">$lang</span><span class="hl-brackets">)</span></li></ol></div></code></td>
</tr>
<tr>
<td>[quote]quote[/quote]</td>
<td><blockquote>quote</blockquote></td>
</tr>
<tr>
<td>[quote=Author]Author? Me? No, no, no...[/quote]</td>
<td><strong class="author">Author wrote:</strong><blockquote>Author? Me? No, no, no...</blockquote></td>
</tr>
<tr>
<td>[center]Centered text[/center]</td>
<td><div style="text-align:center;">Centered text</div></td>
</tr>
<tr>
<td>You should not read any further if you want to be surprised.[spoiler]There is a happy end.[/spoiler]</td>
<td>
<div class="wall-item-container">
You should not read any further if you want to be surprised.<br>
<span id="spoiler-wrap-0716e642" class="spoiler-wrap fakelink" onclick="openClose('spoiler-0716e642');">Click to open/close</span>
<blockquote class="spoiler" id="spoiler-0716e642" style="display: none;">There is a happy end.</blockquote>
<div class="body-attach"><div class="clear"></div></div>
</div>
</td>
</tr>
<tr>
<td>[spoiler=Author]Spoiler quote[/spoiler]</td>
<td>
<div class="wall-item-container">
<strong class="spoiler">Author wrote:</strong><br>
<span id="spoiler-wrap-a893765a" class="spoiler-wrap fakelink" onclick="openClose('spoiler-a893765a');">Click to open/close</span>
<blockquote class="spoiler" id="spoiler-a893765a" style="display: none;">Spoiler quote</blockquote>
<div class="body-attach"><div class="clear"></div></div>
</div>
</td>
</tr>
<tr>
<td>[hr] (horizontal line)</td>
<td><hr></td>
</tr>
</table>
<pre>[size=xx-small]small text[/size]</pre> : <span style="font-size: xx-small;">small text</span>
### Titles
<pre>[size=xx-large]big text[/size]</pre> : <span style="font-size: xx-large;">big text</span>
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[h1]Title 1[/h1]</td>
<td><h1>Title 1</h1></td>
</tr>
<tr>
<td>[h2]Title 2[/h2]</td>
<td><h2>Title 2</h2></td>
</tr>
<tr>
<td>[h3]Title 3[/h3]</td>
<td><h3>Title 3</h3></td>
</tr>
<tr>
<td>[h4]Title 4[/h4]</td>
<td><h4>Title 4</h4></td>
</tr>
<tr>
<td>[h5]Title 5[/h5]</td>
<td><h5>Title 5</h5></td>
</tr>
<tr>
<td>[h6]Title 6[/h6]</td>
<td><h6>Title 6</h6></td>
</tr>
</table>
<pre>[size=20]exact size[/size] (size can be any number, in pixel)</pre> : <span style="font-size: 20px;">exact size</span>
### Tables
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[table]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Header 1[/th]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Header 2[/th]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Header 2[/th]<br>
&nbsp;&nbsp;[/tr]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 1[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 2[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 3[/td]<br>
&nbsp;&nbsp;[/tr]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 4[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 5[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 6[/td]<br>
&nbsp;&nbsp;[/tr]<br>
[/table]</td>
<td>
<table>
<tbody>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>[table border=0]</td>
<td>
<table border="0">
<tbody>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>[table border=1]</td>
<td>
<table border="1">
<tbody>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
### Lists
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[ul]<br>
&nbsp;&nbsp;[li] First list element<br>
&nbsp;&nbsp;[li] Second list element<br>
[/ul]<br>
[list]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listbullet" style="list-style-type: circle;">
<li>First list element</li>
<li>Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[ol]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/ol]<br>
[list=1]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listdecimal" style="list-style-type: decimal;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listnone" style="list-style-type: none;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=i]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listlowerroman" style="list-style-type: lower-roman;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=I]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listupperroman" style="list-style-type: upper-roman;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=a]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listloweralpha" style="list-style-type: lower-alpha;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=A]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listupperalpha" style="list-style-type: upper-alpha;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
</table>
Block
-----
<pre>[code]code[/code]</pre>
<code>code</code>
<p style="clear:both;">&nbsp;</p>
<pre>[quote]quote[/quote]</pre>
<blockquote>quote</blockquote>
<p style="clear:both;">&nbsp;</p>
<pre>[quote=Author]Author? Me? No, no, no...[/quote]</pre>
<strong class="author">Author wrote:</strong><blockquote>Author? Me? No, no, no...</blockquote>
<p style="clear:both;">&nbsp;</p>
<pre>[center]centered text[/center]</pre>
<div style="text-align:center;">centered text</div>
<p style="clear:both;">&nbsp;</p>
<pre>You should not read any further if you want to be surprised.[spoiler]There is a happy end.[/spoiler]</pre>
You should not read any further if you want to be surprised.<br />*click to open/close*
(The text between thhe opening and the closing of the spoiler tag will be visible once the link is clicked. So *"There is a happy end."* wont be visible until the spoiler is uncovered.)
<p style="clear:both;">&nbsp;</p>
**Table**
<pre>[table border=1]
[tr]
[th]Tables now[/th]
[/tr]
[tr]
[td]Have headers[/td]
[/tr]
[/table]</pre>
<table border="1"><tbody><tr><th>Tables now</th></tr><tr><td>Have headers</td></tr></tbody></table>
<p style="clear:both;">&nbsp;</p>
**List**
<pre>[list]
[*] First list element
[*] Second list element
[/list]</pre>
<ul class="listbullet" style="list-style-type: circle;">
<li> First list element<br>
</li>
<li> Second list element</li>
</ul>
[list] is equivalent to [ul] (unordered list).
[ol] can be used instead of [list] to show an ordered list:
<pre>[ol]
[*] First list element
[*] Second list element
[/ol]</pre>
<ul class="listdecimal" style="list-style-type: decimal;"><li> First list element<br></li><li> Second list element</li></ul>
For more options on ordered lists, you can define the style of numeration on [list] argument:
<pre>[list=1]</pre> : decimal
<pre>[list=i]</pre> : lover case roman
<pre>[list=I]</pre> : upper case roman
<pre>[list=a]</pre> : lover case alphabetic
<pre>[list=A] </pre> : upper case alphabetic
Embed
------
## Embed
You can embed video, audio and more in a message.
<pre>[video]url[/video]</pre>
<pre>[audio]url[/audio]</pre>
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[video]url[/video]</td>
<td>Where *url* can be an url to youtube, vimeo, soundcloud, or other sites wich supports oembed or opengraph specifications.</td>
</tr>
<tr>
<td>[video]Video file url[/video]
[audio]Audio file url[/audio]</td>
<td>Full URL to an ogg/ogv/oga/ogm/webm/mp4/mp3 file. An HTML5 player will be used to show it.</td>
</tr>
<tr>
<td>[youtube]Youtube URL[/youtube]</td>
<td>Youtube video OEmbed display. May not embed an actual player.</td>
</tr>
<tr>
<td>[youtube]Youtube video ID[/youtube]</td>
<td>Youtube player iframe embed.</td>
</tr>
<tr>
<td>[vimeo]Vimeo URL[/vimeo]</td>
<td>Vimeo video OEmbed display. May not embed an actual player.</td>
</tr>
<tr>
<td>[vimeo]Vimeo video ID[/vimeo]</td>
<td>Vimeo player iframe embed.</td>
</tr>
<tr>
<td>[iframe]URL[/iframe]</td>
<td>General embed, iframe size is limited by the theme size for video players.</td>
</tr>
<tr>
<td>[url]*url*[/url]</td>
<td>If *url* supports oembed or opengraph specifications the embedded object will be shown (eg, documents from scribd).
Page title with a link to *url* will be shown.</td>
</tr>
</table>
Where *url* can be an url to youtube, vimeo, soundcloud, or other sites wich supports oembed or opengraph specifications.
*url* can be also full url to an ogg file. HTML5 tag will be used to show it.
## Map
<pre>[url]*url*[/url]</pre>
This require "openstreetmap" or "Google Maps" addon version 1.3 or newer.
If the addon isn't activated, the raw coordinates are shown instead.
If *url* supports oembed or opengraph specifications the embedded object will be shown (eg, documents from scribd).
Page title with a link to *url* will be shown.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[map]address[/map]</td>
<td>Embeds a map centered on this address.</td>
</tr>
<tr>
<td>[map=lat,long]</td>
<td>Embeds a map centered on those coordinates.</td>
</tr>
<tr>
<td>[map]</td>
<td>Embeds a map centered on the post's location.</td>
</tr>
</table>
Map
---
## Abstract for longer posts
<pre>[map]address[/map]</pre>
<pre>[map=lat,long]</pre>
If you want to spread your post to several third party networks you can have the problem that these networks have a length limitation like on Twitter.
You can embed maps from coordinates or addresses.
This require "openstreetmap" addon version 1.3 or newer.
-----------------------------------------------------------
Abstract for longer posts
-------------------------
If you want to spread your post to several third party networks you can have the problem that these networks have (for example) a length limitation.
(Like on Twitter)
Friendica is using a semi intelligent mechanism to generate a fitting abstract.
But it can be interesting to define an own abstract that will only be displayed on the external network.
This is done with the [abstract]-element.
Example:
<pre>[abstract]Totally interesting! A must-see! Please click the link![/abstract]
I want to tell you a really boring story that you really never wanted
to hear.</pre>
Twitter would display the text "Totally interesting! A must-see! Please click the link!".
On Friendica you would only see the text after "I want to tell you a really ..."
Friendica is using a semi intelligent mechanism to generate a fitting abstract.
But it can be interesting to define a custom abstract that will only be displayed on the external network.
This is done with the [abstract]-element.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[abstract]Totally interesting! A must-see! Please click the link![/abstract]<br>
I want to tell you a really boring story that you really never wanted to hear.</td>
<td>Twitter would display the text <blockquote>Totally interesting! A must-see! Please click the link!</blockquote>
On Friendica you would only see the text after <blockquote>I want to tell you a really ...</blockquote></td>
</tr>
</table>
It is even possible to define abstracts for separate networks:
<pre>
[abstract]Hi friends Here are my newest pictures![abstract]
[abstract=twit]Hi my dear Twitter followers. Do you want to see my new
pictures?[abstract]
[abstract=apdn]Helly my dear followers on ADN. I made sone new pictures
that I wanted to share with you.[abstract]
Today I was in the woods and took some real cool pictures ...
</pre>
For Twitter and App.net the system will use the defined abstracts.
For other networks (e.g. when you are using the "statusnet" connector that is used to post to GNU Social) the general abstract element will be used.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>
[abstract]Hi friends Here are my newest pictures![/abstract]<br>
[abstract=twit]Hi my dear Twitter followers. Do you want to see my new
pictures?[/abstract]<br>
[abstract=apdn]Helly my dear followers on ADN. I made sone new pictures
that I wanted to share with you.[/abstract]<br>
Today I was in the woods and took some real cool pictures ...</td>
<td>For Twitter and App.net the system will use the defined abstracts.<br>
For other networks (e.g. when you are using the "statusnet" connector that is used to post to your GNU Social account) the general abstract element will be used.</td>
</tr>
</table>
If you use (for example) the "buffer" connector to post to Facebook or Google+ you can use this element to define an abstract for a longer blogpost that you don't want to post completely to these networks.
Networks like Facebook or Google+ aren't length limited.
For this reason the [abstract] element isn't used.
Networks like Facebook or Google+ aren't length limited.
For this reason the [abstract] element isn't used.
Instead you have to name the explicit network:
<pre>
[abstract]These days I had a strange encounter ...[abstract]
[abstract=goog]Helly my dear Google+ followers. You have to read my
newest blog post![abstract]
[abstract=face]Hello my Facebook friends. These days happened something
really cool.[abstract]
While taking pictures in the woods I had a really strange encounter ... </pre>
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>
[abstract]These days I had a strange encounter...[/abstract]<br>
[abstract=goog]Helly my dear Google+ followers. You have to read my newest blog post![/abstract]<br>
[abstract=face]Hello my Facebook friends. These days happened something really cool.[/abstract]<br>
While taking pictures in the woods I had a really strange encounter...</td>
<td>Google and Facebook will show the respective abstracts while the other networks will show the default one.<br>
<br>Meanwhile, Friendica won't show any of the abstracts.</td>
</tr>
</table>
The [abstract] element isn't working with the native OStatus connection or with connectors where we post the HTML.
(Like Tumblr, Wordpress or Pump.io)
The [abstract] element isn't working with connectors where we post the HTML like Tumblr, Wordpress or Pump.io.
For the native connections--that is to e.g. Friendica, Hubzilla, Diaspora or GNU Social--the full posting is used and the contacts instance will display the posting as desired.
Special
-------
## Special
If you need to put literal bbcode in a message, [noparse], [nobb] or [pre] are used to escape bbcode:
<pre>[noparse][b]bold[/b][/noparse]</pre> : [b]bold[/b]
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>If you need to put literal bbcode in a message, [noparse], [nobb] or [pre] are used to escape bbcode:
<ul>
<li>[noparse][b]bold[/b][/noparse]</li>
<li>[nobb][b]bold[/b][/nobb]</li>
<li>[pre][b]bold[/b][/pre]</li>
</ul>
</td>
<td>[b]bold[/b]</td>
</tr>
<tr>
<td>[nosmile] is used to disable smilies on a post by post basis<br>
<br>
[nosmile] ;-) :-O
</td>
<td>;-) :-O</td>
</tr>
<tr>
<td>Custom inline styles<br>
<br>
[style=text-shadow: 0 0 4px #CC0000;]You can change all the CSS properties of this block.[/style]</td>
<td><span style="text-shadow: 0 0 4px #cc0000;;">You can change all the CSS properties of this block.</span></td>
</tr>
<tr>
<td>Custom class block<br>
<br>
[class=custom]If the class exists, this block will have the custom class style applied.[/class]</td>
<td><pre>&lt;span class="custom"&gt;If the class exists,<br> this block will have the custom class<br> style applied.&lt;/span&gt;</pre></td>
</tr>
</table>

View file

@ -16,7 +16,7 @@ Contact us
The discussion of Friendica development takes place in the following Friendica forums:
* The main [forum for Friendica development](https://friendika.openmindspace.org/profile/friendicadevelopers)
* The main [forum for Friendica development](https://helpers.pyxis.uberspace.de/profile/developers)
* The [forum for Friendica theme development](https://friendica.eu/profile/ftdevs)
Help other users
@ -79,7 +79,7 @@ If you want to get involved here:
* Look at the first steps that were made (e.g. the clean theme).
Ask us to find out whom to talk to about their experiences.
* Talk to design people if you know any.
* Let us know about your plans [in the dev forum](https://friendika.openmindspace.org/profile/friendicadevelopers) and the [theme developer forum](https://friendica.eu/profile/ftdevs).
* Let us know about your plans [in the dev forum](https://helpers.pyxis.uberspace.de/profile/developers) and the [theme developer forum](https://friendica.eu/profile/ftdevs).
Do not worry about cross-posting.
###Client software

View file

@ -28,7 +28,7 @@ Friendica Documentation and Resources
**Admin Manual**
* [Install](help/Install)
* [Settings](help/Settings)
* [Settings & Admin Panel](help/Settings)
* [Installing Connectors (Twitter/GNU Social)](help/Installing-Connectors)
* [Install an ejabberd server (XMPP chat) with synchronized credentials](help/install-ejabberd)
* [Message Flow](help/Message-Flow)

View file

@ -10,7 +10,7 @@ Not every PHP/MySQL hosting provider will be able to support Friendica.
Many will.
But **please** review the requirements and confirm these with your hosting provider prior to installation.
Also if you encounter installation issues, please let us know via the [helper](http://helpers.pyxis.uberspace.de/profile/helpers) or the [developer](https://friendika.openmindspace.org/profile/friendicadevelopers) forum or [file an issue](https://github.com/friendica/friendica/issues).
Also if you encounter installation issues, please let us know via the [helper](http://helpers.pyxis.uberspace.de/profile/helpers) or the [developer](https://helpers.pyxis.uberspace.de/profile/developers) forum or [file an issue](https://github.com/friendica/friendica/issues).
Please be as clear as you can about your operating environment and provide as much detail as possible about any error messages you may see, so that we can prevent it from happening in the future.
Due to the large variety of operating systems and PHP platforms in existence we may have only limited ability to debug your PHP installation or acquire any missing modules - but we will do our best to solve any general code issues.
If you do not have a Friendica account yet, you can register a temporary one at [tryfriendica.de](https://tryfriendica.de) and join the forums mentioned above from there.
@ -26,12 +26,12 @@ Requirements
---
* Apache with mod-rewrite enabled and "Options All" so you can use a local .htaccess file
* PHP 5.2+. The later the better. You'll need 5.3 for encryption of key exchange conversations. On a Windows environment, 5.2+ might not work as the function dns_get_record() is only available with version 5.3.
* PHP 5.4+.
* PHP *command line* access with register_argc_argv set to true in the php.ini file
* curl, gd, mysql, hash and openssl extensions
* some form of email server or email gateway such that PHP mail() works
* mcrypt (optional; used for server-to-server message encryption)
* Mysql 5.x or an equivalant alternative for MySQL (MariaDB etc.)
* Mysql 5.5.3+ or an equivalant alternative for MySQL (MariaDB, Percona Server etc.)
* the ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows) (Note: other options are presented in Section 7 of this document.)
* Installation into a top-level domain or sub-domain (without a directory/path component in the URL) is preferred. Directory paths will not be as convenient to use and have not been thoroughly tested.
* If your hosting provider doesn't allow Unix shell access, you might have trouble getting everything to work.

View file

@ -9,7 +9,8 @@ This number should decrease quickly.
The second is the messages which could for various reasons not being delivered.
They will be resend later.
You can have a quick glance into that second queus in the "Inspect Queue" section of the admin panel.
If you have activated the background workers, there might be a third number representing the count of jobs queued for the workers.
If you have activated the background workers, there is a third number representing the count of jobs queued for the workers.
These worker tasks are prioritised and are done accordingly.
Then you get an overview of the accounts on your node, which can be moderated in the "Users" section of the panel.
As well as an overview of the currently active addons

View file

@ -104,6 +104,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original
* max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain"
* include_entities: "true" shows entities for pictures and links (Default: false)
* friendica_verbose: "true" enables different error returns (default: "false")
#### Unsupported parameters
* skip_status
@ -116,6 +117,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original
* since_id: minimal id
* max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain"
* friendica_verbose: "true" enables different error returns (default: "false")
---
### direct_messages/conversation (*; AUTH)
@ -127,6 +129,18 @@ Shows all direct messages of a conversation
* max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain"
* uri: URI of the conversation
* friendica_verbose: "true" enables different error returns (default: "false")
---
### direct_messages/sent (*; AUTH)
#### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
* max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain"
* include_entities: "true" shows entities for pictures and links (Default: false)
* friendica_verbose: "true" enables different error returns (default: "false")
---
### direct_messages/new (POST,PUT; AUTH)
@ -138,14 +152,22 @@ Shows all direct messages of a conversation
* title: Title of the direct message
---
### direct_messages/sent (*; AUTH)
### direct_messages/destroy (POST,DELETE; AUTH)
#### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
* max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain"
* include_entities: "true" shows entities for pictures and links (Default: false)
* id: id of the message to be deleted
* include_entities: optional, currently not yet implemented
* friendica_parenturi: optional, can be used for increased safety to delete only intended messages
* friendica_verbose: "true" enables different error returns (default: "false")
#### Return values
On success:
* JSON return as defined for Twitter API not yet implemented
* on friendica_verbose=true: JSON return {"result":"ok","message":"message deleted"}
On error:
HTTP 400 BadRequest
* on friendica_verbose=true: different JSON returns {"result":"error","message":"xyz"}
---
### favorites (*; AUTH)
@ -694,6 +716,65 @@ xml
</photos>
```
---
### friendica/direct_messages_setseen (GET; AUTH)
#### Parameters
* id: id of the message to be updated as seen
#### Return values
On success:
* JSON return {"result":"ok","message":"message set to seen"}
On error:
* different JSON returns {"result":"error","message":"xyz"}
---
### friendica/direct_messages_search (GET; AUTH)
#### Parameters
* searchstring: string for which the API call should search as '%searchstring%' in field 'body' of all messages of the authenticated user (caption ignored)
#### Return values
Returns only tested with JSON, XML might work as well.
On success:
* JSON return {"success":"true","search_results": array of found messages}
* JSOn return {"success":"false","search_results":"nothing found"}
On error:
* different JSON returns {"result":"error","message":"searchstring not specified"}
---
### friendica/profile/show (GET; AUTH)
show data of all profiles or a single profile of the authenticated user
#### Parameters
* profile_id: id of the profile to be returned (optional, if omitted all profiles are returned by default)
#### Return values
On success: Array of:
* multi_profiles: true if user has activated multi_profiles
* global_dir: URL of the global directory set in server settings
* friendica_owner: user data of the authenticated user
* profiles: array of the profile data
On error:
HTTP 403 Forbidden: when no authentication provided
HTTP 400 Bad Request: if given profile_id is not in db or not assigned to authenticated user
General description of profile data in API returns:
* profile_id
* profile_name
* is_default: true if this is the public profile
* hide_friends: true if friends are hidden
* profile_photo
* profile_thumb
* publish: true if published on the server's local directory
* net_publish: true if published to global_dir
* description ... homepage: different data fields from 'profile' table in database
* users: array with the users allowed to view this profile (empty if is_default=true)
---
## Not Implemented API calls
@ -718,7 +799,6 @@ The following API calls from the Twitter API aren't implemented neither in Frien
* statuses/lookup
* direct_messages/show
* search/tweets
* direct_messages/destroy
* friendships/no_retweets/ids
* friendships/incoming
* friendships/outgoing

View file

@ -4,6 +4,7 @@ Table fcontact
| Field | Description | Type | Null | Key | Default | Extra |
| -------- | ------------- | ---------------- | ---- | --- | ------------------- | --------------- |
| id | sequential ID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| guid | unique id | varchar(64) | NO | | | |
| url | | varchar(255) | NO | | | |
| name | | varchar(255) | NO | | | |
| photo | | varchar(255) | NO | | | |

View file

@ -24,9 +24,11 @@ Table item
| owner-name | Name of the owner of this item | varchar(255) | NO | | | |
| owner-link | Link to the profile page of the owner of this item | varchar(255) | NO | | | |
| owner-avatar | Link to the avatar picture of the owner of this item | varchar(255) | NO | | | |
| owner-id | Link to the contact table with uid=0 of the owner of this item | int(11) | NO | MUL | 0 | |
| author-name | Name of the author of this item | varchar(255) | NO | | | |
| author-link | Link to the profile page of the author of this item | varchar(255) | NO | | | |
| author-avatar | Link to the avatar picture of the author of this item | varchar(255) | NO | | | |
| author-id | Link to the contact table with uid=0 of the author of this item | int(11) | NO | MUL | 0 | |
| title | item title | varchar(255) | NO | | | |
| body | item body content | mediumtext | NO | | NULL | |
| app | application which generated this item | varchar(255) | NO | | | |

View file

@ -1,22 +1,24 @@
Table notify
============
| Field | Description | Type | Null | Key | Default | Extra |
| ------ | --------------------------------- | ------------ | ---- | --- | ------------------- | --------------- |
| id | sequential ID | int(11) | NO | PRI | NULL | auto_increment |
| hash | | varchar(64) | NO | | | |
| type | | int(11) | NO | | 0 | |
| name | | varchar(255) | NO | | | |
| url | | varchar(255) | NO | | | |
| photo | | varchar(255) | NO | | | |
| date | | datetime | NO | | 0000-00-00 00:00:00 | |
| msg | | mediumtext | NO | | NULL | |
| uid | user.id of the owner of this data | int(11) | NO | MUL | 0 | |
| link | | varchar(255) | NO | | | |
| parent | | int(11) | NO | | 0 | |
| seen | | tinyint(1) | NO | | 0 | |
| verb | | varchar(255) | NO | | | |
| otype | | varchar(16) | NO | | | |
| iid | item.id | int(11) | NO | | 0 | |
| Field | Description | Type | Null | Key | Default | Extra |
| ---------- | --------------------------------- | ------------ | ---- | --- | ------------------- | --------------- |
| id | sequential ID | int(11) | NO | PRI | NULL | auto_increment |
| hash | | varchar(64) | NO | | | |
| type | | int(11) | NO | | 0 | |
| name | | varchar(255) | NO | | | |
| url | | varchar(255) | NO | | | |
| photo | | varchar(255) | NO | | | |
| date | | datetime | NO | | 0000-00-00 00:00:00 | |
| msg | | mediumtext | YES | | NULL | |
| uid | user.id of the owner of this data | int(11) | NO | MUL | 0 | |
| link | | varchar(255) | NO | | | |
| iid | item.id | int(11) | NO | | 0 | |
| parent | | int(11) | NO | | 0 | |
| seen | | tinyint(1) | NO | | 0 | |
| verb | | varchar(255) | NO | | | |
| otype | | varchar(16) | NO | | | |
| name_cache | Cached bbcode parsing of name | tinytext | YES | | NULL | |
| msg_cache | Cached bbcode parsing of msg | mediumtext | YES | | NULL | |
Return to [database documentation](help/database)

View file

@ -7,6 +7,8 @@ Table thread
| uid | | int(10) unsigned | NO | MUL | 0 | |
| contact-id | | int(11) unsigned | NO | | 0 | |
| gcontact-id | Global Contact | int(11) unsigned | NO | | 0 | |
| owner-id | Item owner | int(11) unsigned | NO | MUL | 0 | |
| author-id | Item author | int(11) unsigned | NO | MUL | 0 | |
| created | | datetime | NO | MUL | 0000-00-00 00:00:00 | |
| edited | | datetime | NO | | 0000-00-00 00:00:00 | |
| commented | | datetime | NO | MUL | 0000-00-00 00:00:00 | |

View file

@ -3,195 +3,612 @@ Referenz der Friendica BBCode Tags
* [Zur Startseite der Hilfe](help)
Inline Tags
-----
## Inline
<style>
table.bbcodes {
margin: 1em 0;
background-color: #f9f9f9;
border: 1px solid #aaa;
border-collapse: collapse;
color: #000;
width: 100%;
}
table.bbcodes > tr > th,
table.bbcodes > tr > td,
table.bbcodes > * > tr > th,
table.bbcodes > * > tr > td {
border: 1px solid #aaa;
padding: 0.2em 0.4em
}
table.bbcodes > tr > th,
table.bbcodes > * > tr > th {
background-color: #f2f2f2;
text-align: center;
width: 50%
}
</style>
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[b]fett[/b]</td>
<td><strong>fett</strong></td>
</tr>
<tr>
<td>[i]kursiv[/i]</td>
<td><em>kursiv</em></td>
</tr>
<tr>
<td>[u]unterstrichen[/u]</td>
<td><u>unterstrichen</u></td>
</tr>
<tr>
<td>[s]durchgestrichen[/s]</td>
<td><strike>durchgestrichen</strike></td>
</tr>
<tr>
<td>[o]&uuml;berstrichen[/o]</td>
<td><span class="overline">&uuml;berstrichen</span></td>
</tr>
<tr>
<td>[color=red]rot[/color]</td>
<td><span style="color: red;">rot</span></td>
</tr>
<tr>
<td>[url=http://www.friendica.com]Friendica[/url]</td>
<td><a href="http://www.friendica.com" target="external-link">Friendica</a></td>
</tr>
<tr>
<td>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto"></td>
</tr>
<tr>
<td>[img=64x32]http://friendica.com/sites/default/files/friendika-32.png[/img]<br>
<br>Note: provided height is simply discarded.</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" style="width: 64px;"></td>
</tr>
<tr>
<td>[size=xx-small]kleiner Text[/size]</td>
<td><span style="font-size: xx-small;">kleiner Text</span></td>
</tr>
<tr>
<td>[size=xx-large]gro&szlig;er Text[/size]</td>
<td><span style="font-size: xx-large;">gro&szlig;er Text</span></td>
</tr>
<tr>
<td>[size=20]exakte Gr&ouml;&szlig;e[/size] (die Gr&ouml;&szlig;e kann beliebig in Pixeln gew&auml;lt werden)</td>
<td><span style="font-size: 20px;">exakte Gr&ouml;&szlig;e</span></td>
</tr>
<tr>
<td>[font=serif]Serife Schriftart[/font]</td>
<td><span style="font-family: serif;">Serife Schriftart</span></td>
</tr>
</table>
### Links
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[url]http://friendica.com[/url]</td>
<td><a href="http://friendica.com">http://friendica.com</a></td>
</tr>
<tr>
<td>[url=http://friendica.com]Friendica[/url]</td>
<td><a href="http://friendica.com">Friendica</a></td>
</tr>
<tr>
<td>[bookmark]http://friendica.com[/bookmark]<br><br>
#^[url]http://friendica.com[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">http://friendica.com</a></h4></span></td>
</tr>
<tr>
<td>[bookmark=http://friendica.com]Lesezeichen[/bookmark]<br><br>
#^[url=http://friendica.com]Lesezeichen[/url]<br><br>
#[url=http://friendica.com]^[/url][url=http://friendica.com]Lesezeichen[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">Lesezeichen</a></h4></span></td>
</tr>
<tr>
<td>[url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora Beitrag mit GUID[/url]</td>
<td><a href="/display/f16d77b0630f0134740c0cc47a0ea02a" target="_blank">Diaspora Beitrag mit GUID</a></td>
</tr>
<tr>
<td>#Friendica</td>
<td>#<a href="/search?tag=Friendica">Friendica</a></td>
</tr>
<tr>
<td>@Erw&auml;hnung</td>
<td>@<a href="javascript:void(0)">Erw&auml;hnung</a></td>
</tr>
<tr>
<td>acct:account@friendica.host.com (WebFinger)</td>
<td><a href="/acctlink?addr=account@friendica.host.com" target="extlink">acct:account@friendica.host.com</a></td>
</tr>
<tr>
<td>[mail]user@mail.example.com[/mail]</td>
<td><a href="mailto:user@mail.example.com">user@mail.example.com</a></td>
</tr>
<tr>
<td>[mail=user@mail.example.com]Eine E-Mail senden[/mail]</td>
<td><a href="mailto:user@mail.example.com">Eine E-Mail senden</a></td>
</tr>
</table>
## Blocks
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[p]Ein Absatz mit Text[/p]</td>
<td><p>Ein Absatz mit Text</p></td>
</tr>
<tr>
<td>Eingebetteter [code]Programmcode[/code] im Text</td>
<td>Eingebetteter <key>Programmcode</key> im Text</td>
</tr>
<tr>
<td>[code]Programmcode<br>&uuml;ber<br>mehrere<br>Zeilen[/code]</td>
<td><code>Programmcode
&uuml;ber
mehrere
Zeilen</code></td>
</tr>
<tr>
<td>[code=php]function text_highlight($s,$lang)[/code]</td>
<td><code><div class="hl-main"><ol class="hl-main"><li><span class="hl-code">&nbsp;</span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">text_highlight</span><span class="hl-brackets">(</span><span class="hl-var">$s</span><span class="hl-code">,</span><span class="hl-var">$lang</span><span class="hl-brackets">)</span></li></ol></div></code></td>
</tr>
<tr>
<td>[quote]Zitat[/quote]</td>
<td><blockquote>Zitat</blockquote></td>
</tr>
<tr>
<td>[quote=Autor]Autor? Ich? Nein, niemals...[/quote]</td>
<td><strong class="Autor">Autor hat geschrieben:</strong><blockquote>Autor? Ich? Nein, niemals...</blockquote></td>
</tr>
<tr>
<td>[center]zentrierter Text[/center]</td>
<td><div style="text-align:center;">zentrierter Text</div></td>
</tr>
<tr>
<td>Du solltest nicht weiter lesen, wenn du das Ende des Films nicht vorher erfahren willst. [spoiler]Es gibt ein Happy End.[/spoiler]</td>
<td>
<div class="wall-item-container">
Du solltest nicht weiter lesen, wenn du das Ende des Films nicht vorher erfahren willst. <br>
<span id="spoiler-wrap-0716e642" class="spoiler-wrap fakelink" onclick="openClose('spoiler-0716e642');">Zum &ouml;ffnen/schlie&szlig;en klicken</span>
<blockquote class="spoiler" id="spoiler-0716e642" style="display: none;">Es gibt ein Happy End.</blockquote>
<div class="body-attach"><div class="clear"></div></div>
</div>
</td>
</tr>
<tr>
<td>[spoiler=Autor]Spoiler Alarm[/spoiler]</td>
<td>
<div class="wall-item-container">
<strong class="spoiler">Autor hat geschrieben</strong><br>
<span id="spoiler-wrap-a893765a" class="spoiler-wrap fakelink" onclick="openClose('spoiler-a893765a');">Zum &ouml;ffnen/schlie&szlig;en klicken</span>
<blockquote class="spoiler" id="spoiler-a893765a" style="display: none;">Spoiler Alarm</blockquote>
<div class="body-attach"><div class="clear"></div></div>
</div>
</td>
</tr>
<tr>
<td>[hr] (horizontale Linie)</td>
<td><hr></td>
</tr>
</table>
### &Uuml;berschriften
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[h1]Titel 1[/h1]</td>
<td><h1>Titel 1</h1></td>
</tr>
<tr>
<td>[h2]Titel 2[/h2]</td>
<td><h2>Titel 2</h2></td>
</tr>
<tr>
<td>[h3]Titel 3[/h3]</td>
<td><h3>Titel 3</h3></td>
</tr>
<tr>
<td>[h4]Titel 4[/h4]</td>
<td><h4>Titel 4</h4></td>
</tr>
<tr>
<td>[h5]Titel 5[/h5]</td>
<td><h5>Titel 5</h5></td>
</tr>
<tr>
<td>[h6]Titel 6[/h6]</td>
<td><h6>Titel 6</h6></td>
</tr>
</table>
### Tabellen
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[table]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Kopfzeile 1[/th]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Kopfzeile 2[/th]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Kopfzeile 2[/th]<br>
&nbsp;&nbsp;[/tr]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Zelle 1[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Zelle 2[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Zelle 3[/td]<br>
&nbsp;&nbsp;[/tr]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Zelle 4[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Zelle 5[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Zelle 6[/td]<br>
&nbsp;&nbsp;[/tr]<br>
[/table]</td>
<td>
<table>
<tbody>
<tr>
<th>Kopfzeile 1</th>
<th>Kopfzeile 2</th>
<th>Kopfzeile 3</th>
</tr>
<tr>
<td>Zelle 1</td>
<td>Zelle 2</td>
<td>Zelle 3</td>
</tr>
<tr>
<td>Zelle 4</td>
<td>Zelle 5</td>
<td>Zelle 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>[table border=0]</td>
<td>
<table border="0">
<tbody>
<tr>
<th>Kopfzeile 1</th>
<th>Kopfzeile 2</th>
<th>Kopfzeile 3</th>
</tr>
<tr>
<td>Zelle 1</td>
<td>Zelle 2</td>
<td>Zelle 3</td>
</tr>
<tr>
<td>Zelle 4</td>
<td>Zelle 5</td>
<td>Zelle 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>[table border=1]</td>
<td>
<table border="1">
<tbody>
<tr>
<th>Kopfzeile 1</th>
<th>Kopfzeile 2</th>
<th>Kopfzeile 3</th>
</tr>
<tr>
<td>Zelle 1</td>
<td>Zelle 2</td>
<td>Zelle 3</td>
</tr>
<tr>
<td>Zelle 4</td>
<td>Zelle 5</td>
<td>Zelle 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
### Listen
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[ul]<br>
&nbsp;&nbsp;[li] Erstes Listenelement<br>
&nbsp;&nbsp;[li] Zweites Listenelement<br>
[/ul]<br>
[list]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/list]</td>
<td>
<ul class="listbullet" style="list-style-type: circle;">
<li>Erstes Listenelement</li>
<li>Zweites Listenelement</li>
</ul>
</td>
</tr>
<tr>
<td>[ol]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/ol]<br>
[list=1]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/list]</td>
<td>
<ul class="listdecimal" style="list-style-type: decimal;">
<li> Erstes Listenelement</li>
<li> Zweites Listenelement</li>
</ul>
</td>
</tr>
<tr>
<td>[list=]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/list]</td>
<td>
<ul class="listnone" style="list-style-type: none;">
<li> Erstes Listenelement</li>
<li> Zweites Listenelement</li>
</ul>
</td>
</tr>
<tr>
<td>[list=i]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/list]</td>
<td>
<ul class="listlowerroman" style="list-style-type: lower-roman;">
<li> Erstes Listenelement</li>
<li> Zweites Listenelement</li>
</ul>
</td>
</tr>
<tr>
<td>[list=I]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/list]</td>
<td>
<ul class="listupperroman" style="list-style-type: upper-roman;">
<li> Erstes Listenelement</li>
<li> Zweites Listenelement</li>
</ul>
</td>
</tr>
<tr>
<td>[list=a]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/list]</td>
<td>
<ul class="listloweralpha" style="list-style-type: lower-alpha;">
<li> Erstes Listenelement</li>
<li> Zweites Listenelement</li>
</ul>
</td>
</tr>
<tr>
<td>[list=A]<br>
&nbsp;&nbsp;[*] Erstes Listenelement<br>
&nbsp;&nbsp;[*] Zweites Listenelement<br>
[/list]</td>
<td>
<ul class="listupperalpha" style="list-style-type: upper-alpha;">
<li> Erstes Listenelement</li>
<li> Zweites Listenelement</li>
</ul>
</td>
</tr>
</table>
## Einbetten
Du kannst Videos, Musikdateien und weitere Dinge in Beitr&auml;gen einbinden.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[video]url[/video]</td>
<td>Wobei die *url* eine URL von youtube, vimeo, soundcloud oder einer anderen Plattform sein kann, die die opengraph Spezifikationen unterst&uuml;tzt.</td>
</tr>
<tr>
<td>[video]URL der Videodatei[/video]
[audio]URL der Musikdatei[/audio]</td>
<td>Die komplette URL einer ogg/ogv/oga/ogm/webm/mp4/mp3 Datei angeben, diese wird dann mit einem HTML5-Player angezeigt.</td>
</tr>
<tr>
<td>[youtube]Youtube URL[/youtube]</td>
<td>Youtube Video mittels OEmbed anzeigen. Kann u.U, den Player nicht einbetten.</td>
</tr>
<tr>
<td>[youtube]Youtube video ID[/youtube]</td>
<td>Youtube-Player im iframe einbinden.</td>
</tr>
<tr>
<td>[vimeo]Vimeo URL[/vimeo]</td>
<td>Vimeo Video mittels OEmbed anzeigen. Kann u.U, den Player nicht einbetten.</td>
</tr>
<tr>
<td>[vimeo]Vimeo video ID[/vimeo]</td>
<td>Vimeo-Player im iframe einbinden.</td>
</tr>
<tr>
<td>[iframe]URL[/iframe]</td>
<td>General embed, iframe size is limited by the theme size for video players.</td>
</tr>
<tr>
<td>[url]*url*[/url]</td>
<td>Wenn *url* die OEmbed- oder Opengraph-Spezifikationen unterst&uuml;tzt, wird das Objekt eingebettet (z.B. Dokumente von scribd).
Ansonsten wird der Titel der Seite mit der URL verlinkt.</td>
</tr>
</table>
## Karten
Das Einbetten von Karten ben&ouml;tigt das "openstreetmap" oder das "Google Maps" Addon.
Wenn keines der Addons aktiv ist, werden stattde&szlig;en die Kordinaten angezeigt-
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[map]Adresse[/map]</td>
<td>Bindet eine Karte ein, auf der die angegebene Adresse zentriert ist.</td>
</tr>
<tr>
<td>[map=lat,long]</td>
<td>Bindet eine Karte ein, die auf die angegebenen Koordinaten zentriert ist.</td>
</tr>
<tr>
<td>[map]</td>
<td>Bindet eine Karte ein, die auf die Position des Beitrags zentriert ist.</td>
</tr>
</table>
## Zusammenfassungen f&uuml;r lange Beitr&auml;ge
Wenn du deine Beitr&auml;ge auf anderen Netzwerken von Drittanbietern verbreiten m&ouml;chtest, z.B. Twitter, k&ouml;nntest du Probleme mit deren Zeichenbegrenzung haben.
Friendica verwendet einen semi-inelligenten Mechanismus um passende Zusammenfassungen zu erstellen.
Du kannst allerdings auch selbst die Zusammenfassungen erstellen, die auf den unterschiedlichen Netzwerken angezeigt werden.
Um dies zu tun, verwendest du den [abstract]-Tag.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>[abstract]Unglaublich interessant! Muss man gesehen haben! Unbedingt dem Link folgen![/abstract]<br>
Ich m&ouml;chte euch eine unglaublich langweilige Geschichte erz&auml;hlen, die ihr sicherlich niemals h&ouml;ren wolltet.</td>
<td>Auf Twitter w&uuml;rde folgender Text verlffentlicht werden <blockquote>Unglaublich interessant! Muss man gesehen haben! Unbedingt dem Link folgen!</blockquote>
Wohingegen auf Friendica folgendes stehen w&uuml;rde <blockquote>Ich m&ouml;chte euch eine unglaublich langweilige Geschichte erz&auml;hlen, die ihr sicherlich niemals h&ouml;ren wolltet.</blockquote></td>
</tr>
</table>
Wenn du magst, kannst du auch unterschiedliche Zusammenfassungen f&uuml;r die unterschiedlichen Netzwerke verwenden.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>
[abstract]Hey Leute, hier sind meines neuesten Bilder![/abstract]<br>
[abstract=twit]Hallo liebe Twitter Follower. Wollt ihr meine neuesten Bilder sehen?[/abstract]<br>
[abstract=apdn]Moin liebe Follower auf ADN. Ich habe einige neue Bilder gemacht, die ich euch gerne zeigen will.[/abstract]<br>
Heute war ich im Wald unterwegs und habe einige wirklich sch&ouml;ne Bilder gemacht...</td>
<td>F&uuml;r Twitter und App.net wird Friendica in diesem Fall die speziell definierten Zusammenfassungen Verwenden. F&uuml;r andere Netzwerke (wie z.B. bei der Verwendung des GNU Social Konnektors zum Ver&ouml;ffentlichen auf deinen GNU Social Account) w&uuml;rde die allgemeine Zusammenfassung verwenden.</td>
</tr>
</table>
Wenn du beispielsweise den "buffer"-Konnektor verwendest um Beitr&auml;ge nach Facebook und Google+ zu senden, dort aber nicht den gesamten Blogbeitrag posten willst sondern nur einen Anrei&szlig;er, kannst du dies mit dem [abstract]-Tag realisieren.
Bei Netzwerken wie Facebook oder Google+, die selbst kein Zeichenlimit haben wird das [abstract]-Element allerdings nicht grunds&auml;tzlich verwendet.
Daher m&uuml;ssen diese Netzwerke explizit genannt werden.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>
[abstract]Dieser Tage hatte ich eine ungew&ouml;hnliche Begegnung...[/abstract]<br>
[abstract=goog]Hey liebe Google+ Follower. Habt ich schon meinen neuesten Blog-Beitrag gelesen?[/abstract]<br>
[abstract=face]Hallo liebe Facebook Freunde. Letztens ist mir etwas wirklich sch&ouml;nes pa&szlig;iert.[/abstract]<br>
Als ich die Bilder im Wald aufgenommen habe, hatte ich eine wirklich ungew&ouml;hnliche Begegnung...</td>
<td>Auf Google und Facebook w&uuml;rde nun die entsprechende Zusammenfassung verbreitet. F&uuml;r andere Netzwerke w&uuml;rde die allgemeine Zusammenfassung verwendet werden.<br>
<br>Auf Friendica wird weiterhin keine Zusammenfassung angezeigt.</td>
</tr>
</table>
F&uuml;r Verbindungen zu Netzwerken, zu denen Friendica den HTML Code postet, wie Tumblr, Wordpress oder Pump.io wird das [abstract] Element nicht verwendet.
Bei nativen Verbindungen; das hei&szlig;t zu z.B. Friendica, Hubzilla, Diaspora oder GNU Social Kontakten; wird der ungek&uuml;rzte Beitrag &uuml;bertragen.
Die Instanz des Kontakts k&uuml;mmert sich um die Darstellung.
## Special
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Ergebnis</th>
</tr>
<tr>
<td>Wenn du verhindern m&ouml;chtest, da&szlig; der BBCode in einer Nachricht interpretiert wird, kannst du die [noparse], [nobb] oder [pre] Tag verwenden:<br>
<ul>
<li>[noparse][b]fett[/b][/noparse]</li>
<li>[nobb][b]fett[/b][/nobb]</li>
<li>[pre][b]fett[/b][/pre]</li>
</ul>
</td>
<td>[b]fett[/b]</td>
</tr>
<tr>
<td>[nosmile] kann verwendet werden um f&uuml;r einen Beitrag das umsetzen von Smilies zu verhindern.<br>
<br>
[nosmile] ;-) :-O
</td>
<td>;-) :-O</td>
</tr>
<tr>
<td>Benutzerdefinierte Inline-Styles<br>
<br>
[style=text-shadow: 0 0 4px #CC0000;]Du kannst alle CSS-Eigenschaften eines Blocks &auml;ndern-[/style]</td>
<td><span style="text-shadow: 0 0 4px #cc0000;;">Du kannst alle CSS-Eigenschaften eines Blocks &auml;ndern-</span></td>
</tr>
<tr>
<td>Benutzerdefinierte CSS Klassen<br>
<br>
[class=custom]Wenn die vergebene Klasse in den CSS Anweisungen existiert, wird sie angewandt.[/class]</td>
<td><pre>&lt;span class="custom"&gt;Wenn die<br>
vergebene Klasse in den CSS Anweisungen<br>
existiert,wird sie angewandt.&lt;/span&gt;</pre></td>
</tr>
</table>
<pre>[b]fett[/b]</pre> : <strong>fett</strong>
<pre>[i]kursiv[/i]</pre> : <em>kursiv</em>
<pre>[u]unterstrichen[/u]</pre> : <u>unterstrichen</u>
<pre>[s]durchgestrichen[/s]</pre> : <strike>durchgestrichen</strike>
<pre>[color=red]rot[/color]</pre> : <span style="color: red;">rot</span>
<pre>[url=http://www.friendica.com]Friendica[/url]</pre> : <a href="http://www.friendica.com" target="external-link">Friendica</a>
<pre>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</pre> : <img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto">
<pre>[size=xx-small]kleiner Text[/size]</pre> : <span style="font-size: xx-small;">kleiner Text</span>
<pre>[size=xx-large]gro&szlig; Text[/size]</pre> : <span style="font-size: xx-large;">gro&szlig;er Text</span>
<pre>[size=20]exakte Textgr&ouml;&szlig;e[/size] (Textgr&ouml;&szlig;e kann jede Zahl sein, in Pixeln)</pre> : <span style="font-size: 20px;">exakte Gr&ouml;&szlig;e</span>
Block Tags
-----
<pre>[code]Code[/code]</pre>
<code>Code</code>
<p style="clear:both;">&nbsp;</p>
<pre>[quote]Zitat[/quote]</pre>
<blockquote>Zitat</blockquote>
<p style="clear:both;">&nbsp;</p>
<pre>[quote=Autor]Der Autor? Ich? Nein, nein, nein...[/quote]</pre>
<strong class="author">Autor hat geschrieben:</strong><blockquote>Der Autor? Ich? Nein, nein, nein...</blockquote>
<p style="clear:both;">&nbsp;</p>
<pre>[center]zentrierter Text[/center]</pre>
<div style="text-align:center;">zentrierter Text</div>
<p style="clear:both;">&nbsp;</p>
<pre>Wer überrascht werden möchte sollte nicht weiter lesen.[spoiler]Es gibt ein Happy End.[/spoiler]</pre>
Wer überrascht werden möchte sollte nicht weiter lesen.<br />*klicken zum öffnen/schließen*
(Der Text zweischen dem öffnenden und dem schließenden Teil des spoiler Tags wird nicht angezeigt, bis der Link angeklickt wurde. In dem Fall wird *"Es gibt ein Happy End."* also erst angezeigt, wenn der Spoiler verraten wird.)
<p style="clear:both;">&nbsp;</p>
**Tabelle**
<pre>[table border=1]
[tr]
[th]Tabellenzeile[/th]
[/tr]
[tr]
[td]haben &Uuml;berschriften[/td]
[/tr]
[/table]</pre>
<table border="1"><tbody><tr><th>Tabellenzeile</th></tr><tr><td>haben &Uuml;berschriften</td></tr></tbody></table>
<p style="clear:both;">&nbsp;</p>
**Listen**
<pre>[list]
[*] Erstes Listenelement
[*] Zweites Listenelement
[/list]</pre>
<ul class="listbullet" style="list-style-type: circle;">
<li> Erstes Listenelement<br>
</li>
<li> Zweites Listenelement</li>
</ul>
[list] ist Equivalent zu [ul] (unsortierte Liste).
[ol] kann anstelle von [list] verwendet werden um eine sortierte Liste zu erzeugen:
<pre>[ol]
[*] Erstes Listenelement
[*] Zweites Listenelement
[/ol]</pre>
<ul class="listdecimal" style="list-style-type: decimal;"><li>Erstes Listenelement<br></li><li> Zweites Listenelement</li></ul>
F&uuml;r weitere Optionen von sortierten Listen kann man den Stil der Numerierung der Liste definieren:
<pre>[list=1]</pre> : dezimal
<pre>[list=i]</pre> : r&ouml;misch, Kleinbuchstaben
<pre>[list=I]</pre> : r&ouml;misch, Gro&szlig;buchstaben
<pre>[list=a]</pre> : alphabetisch, Kleinbuchstaben
<pre>[list=A] </pre> : alphabethisch, Gro&szlig;buchstaben
Einbettung von Inhalten
------
Man kann viele Dinge, z.B. Video und Audio Dateine, in Nachrichten einbetten.
<pre>[video]url[/video]</pre>
<pre>[audio]url[/audio]</pre>
Wobei die *url* von youtube, vimeo, soundcloud oder einer anderen Seite stammen kann die die oembed oder opengraph Spezifikationen unterst&uuml;tzt.
Au&szlig;erdem kann *url* die genaue url zu einer ogg Datei sein, die dann per HTML5 eingebunden wird.
<pre>[url]*url*[/url]</pre>
Wenn *url* entweder oembed oder opengraph unterstützt wird das eingebettete Objekt (z.B. ein Dokument von scribd) eingebunden.
Der Titel der Seite mit einem Link zur *url* wird ebenfalls angezeigt.
Um eine Karte in einen Beitrag einzubinden, muss das *openstreetmap* Addon aktiviert werden. Ist dies der Fall, kann mit
<pre>[map]Broadway 26, New York[/map]</pre>
eine Karte von [OpenStreetmap](http://openstreetmap.org) eingebettet werden. Zur Identifikation des Ortes können entweder seine Koordinaten in der Form
<pre>[map=lat,long]</pre>
oder eine Adresse in obiger Form verwendet werden.
Zusammenfassung für längere Beiträge
------------------------------------
Wenn man seine Beiträge über mehrere Netzwerke verbreiten möchte, hat man häufig das Problem, dass diese Netzwerke z.B. eine Längenbeschränkung haben.
(Z.B. Twitter).
Friendica benutzt zum Erzeugen eines Anreißtextes eine halbwegs intelligente Logik.
Es kann aber dennoch von Interesse sein, eine eigene Zusammenfassung zu erstellen, die nur auf dem Fremdnetzwerk dargestellt wird.
Dies geschieht mit dem [abstract]-Element.
Beispiel:
<pre>[abstract]Total spannend! Unbedingt diesen Link anklicken![/abstract]
Hier erzähle ich euch eine total langweilige Geschichte, die ihr noch
nie hören wolltet.</pre>
Auf Twitter würde das "Total spannend! Unbedingt diesen Link anklicken!" stehen, auf Friendica würde nur der Text nach "Hier erzähle ..." erscheinen.
Es ist sogar möglich, für einzelne Netzwerke eigene Zusammenfassungen zu erstellen:
<pre>
[abstract]Hallo Leute, hier meine neuesten Bilder![abstract]
[abstract=twit]Hallo Twitter-User, hier meine neuesten Bilder![abstract]
[abstract=apdn]Hallo App.net-User, hier meine neuesten Bilder![abstract]
Ich war heute wieder im Wald unterwegs und habe tolle Bilder geschossen ...
</pre>
Für Twitter und App.net nimmt das System die entsprechenden Texte.
Bei anderen Netzwerken, bei denen der Inhalt gekürzt wird (z.B. beim "statusnet"-Connector, der für das Posten nach GNU Social verwendet wird) wird dann die Zusammenfassung unter [abstract] verwendet.
Wenn man z.B. den "buffer"-Connector verwendet, um nach Facebook oder Google+ zu posten, kann man dieses Element ebenfalls verwenden, wenn man z.B. einen längeren Blogbeitrag erstellt hat, aber ihn nicht komplett in diese Netzwerke posten möchte.
Netzwerke wie Facebook oder Google+ sind nicht in der Postinglänge beschränkt.
Aus diesem Grund greift nicht die [abstract]-Zusammenfassung. Stattdessen muss man das Netzwerk explizit angeben:
<pre>
[abstract]Ich habe neulich wieder etwas erlebt, was ich euch mitteilen möchte.[abstract]
[abstract=goog]Hallo meine Google+-Kreislinge. Ich habe neulich wieder
etwas erlebt, was ich euch mitteilen möchte.[abstract]
[abstract=face]Hallo Facebook-Freunde! Ich habe neulich wieder etwas
erlebt, was ich euch mitteilen möchte.[abstract]
Beim Bildermachen im Wald habe ich neulich eine interessante Person
getroffen ... </pre>
Das [abstract]-Element greift nicht bei der nativen OStatus-Verbindung oder bei Connectoren, die den HTML-Text posten wie z.B. die Connectoren zu Tumblr, Wordpress oder Pump.io.
Spezielle Tags
-------
Wenn Du &uuml;ber BBCode Tags in einer Nachricht schreiben m&ouml;chtest, kannst Du [noparse], [nobb] oder [pre] verwenden um den BBCode Tags vor der Evaluierung zu sch&uuml;tzen:
<pre>[noparse][b]fett[/b][/noparse]</pre> : [b]fett[/b]

View file

@ -29,7 +29,7 @@ Friendica - Dokumentation und Ressourcen
**Technische Dokumentation**
* [Installation](help/Install)
* [Konfigurationen](help/Settings)
* [Konfigurationen & Admin-Panel](help/Settings)
* [Plugins](help/Plugins)
* [Konnektoren (Connectors) installieren (Twitter/GNU Social)](help/Installing-Connectors)
* [Installation eines ejabberd Servers (XMPP-Chat) mit synchronisierten Anmeldedaten](help/install-ejabberd) (EN)

View file

@ -9,8 +9,9 @@ Diese Zahl sollte sich relativ schnell sinken.
Die zweite Zahl gibt die Anzahl von Nachrichten an, die nicht zugestellt werden konnten.
Die Zustellung wird zu einem späteren Zeitpunkt noch einmal versucht.
Unter dem Punkt "Warteschlange Inspizieren" kannst du einen schnellen Blick auf die zweite Warteschlange werfen.
Solltest du für die Hintergrundprozesse die Worker aktiviert haben, könntest du eine dritte Zahl angezeigt bekommen.
Solltest du für die Hintergrundprozesse die Worker aktiviert haben, wird eine dritte Zahl angezeigt.
Diese repräsentiert die Anzahl der Aufgaben, die die Worker noch vor sich haben.
Die Aufgaben der Worker sind priorisiert und werden anhand dieser Prioritäten abgearbeitet.
Des weiteren findest du eine Übersicht über die Accounts auf dem Friendica Knoten, die unter dem Punkt "Nutzer" moderiert werden können.
Sowie eine Liste der derzeit aktivierten Addons.

View file

@ -1,20 +1,19 @@
Config values that can only be set in .htconfig.php
===================================================
There are some config values that haven't found their way into the administration page. This has several reasons. Maybe they are part of a
current development that isn't considered stable and will be added later in the administration page when it is considered safe. Or it triggers
something that isn't expected to be of public interest. Or it is for testing purposes only.
There are some config values that haven't found their way into the administration page.
This has several reasons.
Maybe they are part of a current development that isn't considered stable and will be added later in the administration page when it is considered safe.
Or it triggers something that isn't expected to be of public interest. Or it is for testing purposes only.
**Attention:** Please be warned that you shouldn't use one of these values without the knowledge what it could trigger. Especially don't do that with
undocumented values.
**Attention:** Please be warned that you shouldn't use one of these values without the knowledge what it could trigger.
Especially don't do that with undocumented values.
The header of the section describes the category, the value is the parameter. Example: To set the directory value please add this
line to your .htconfig.php:
The header of the section describes the category, the value is the parameter.
Example: To set the directory value please add this line to your .htconfig.php:
$a->config['system']['directory'] = 'http://dir.friendi.ca';
## Jabber ##
* debug (Boolean) - Enable debug level for the jabber account synchronisation.
* logfile - Logfile for the jabber account synchronisation.
@ -23,7 +22,7 @@ line to your .htconfig.php:
* birthday_input_format - Default value is "ymd".
* block_local_dir (Boolean) - Blocks the access to the directory of the local users.
* default_service_class -
* default_service_class -
* delivery_batch_count - Number of deliveries per process. Default value is 1. (Disabled when using the worker)
* diaspora_test (Boolean) - For development only. Disables the message transfer.
* directory - The path to global directory. If not set then "http://dir.friendi.ca" is used.
@ -40,6 +39,9 @@ line to your .htconfig.php:
* max_batch_queue - Default value is 1000.
* max_processes_backend - Maximum number of concurrent database processes for background tasks. Default value is 5.
* max_processes_frontend - Maximum number of concurrent database processes for foreground tasks. Default value is 20.
* memcache (Boolean) - Use memcache. To use memcache the PECL extension "memcache" has to be installed and activated.
* memcache_host - Hostname of the memcache daemon. Default is '127.0.0.1'.
* memcache_port- Portnumberof the memcache daemon. Default is 11211.
* no_oembed (Boolean) - Don't use OEmbed to fetch more information about a link.
* no_oembed_rich_content (Boolean) - Don't show the rich content (e.g. embedded PDF).
* no_smilies (Boolean) - Don't show smilies.
@ -48,16 +50,17 @@ line to your .htconfig.php:
* ostatus_poll_timeframe - Defines how old an item can be to try to complete the conversation with it.
* paranoia (Boolean) - Log out users if their IP address changed.
* permit_crawling (Boolean) - Restricts the search for not logged in users to one search per minute.
* profiler (Boolean) - Enable internal timings to help optimize code. Needed for "rendertime" addon. Default is false.
* free_crawls - Number of "free" searches when "permit_crawling" is activated (Default value is 10)
* crawl_permit_period - Period in seconds between allowed searches when the number of free searches is reached and "permit_crawling" is activated (Default value is 60)
* png_quality - Default value is 8.
* proc_windows (Boolean) - Should be enabled if Friendica is running under Windows.
* proxy_cache_time - Time after which the cache is cleared. Default value is one day.
* pushpoll_frequency -
* pushpoll_frequency -
* qsearch_limit - Default value is 100.
* relay_server - Experimental Diaspora feature. Address of the relay server where public posts should be send to. For example https://podrelay.net
* relay_subscribe (Boolean) - Enables the receiving of public posts from the relay. They will be included in the search and on the community page when it is set up to show all public items.
* relay_scope - Can be "all" or "tags". "all" means that every public post should be received. "tags" means that only posts witt selected tags should be received.
* relay_scope - Can be "all" or "tags". "all" means that every public post should be received. "tags" means that only posts with selected tags should be received.
* relay_server_tags - Comma separated list of tags for the "tags" subscription (see "relay_scrope")
* relay_user_tags (Boolean) - If enabled, the tags from the saved searches will used for the "tags" subscription in addition to the "relay_server_tags".
* remove_multiplicated_lines (Boolean) - If enabled, multiple linefeeds in items are stripped to a single one.
@ -67,11 +70,12 @@ line to your .htconfig.php:
* throttle_limit_week - Maximum number of posts that a user can send per week with the API.
* throttle_limit_month - Maximum number of posts that a user can send per month with the API.
* wall-to-wall_share (Boolean) - Displays forwarded posts like "wall-to-wall" posts.
* worker_cooldown - Cooldown time after each worker function call. Default value is 0 seconds.
* xrd_timeout - Timeout for fetching the XRD links. Default value is 20 seconds.
## service_class ##
* upgrade_link -
* upgrade_link -
## experimentals ##
@ -83,19 +87,15 @@ line to your .htconfig.php:
# Administrator Options #
Enabling the admin panel for an account, and thus making the account holder
admin of the node, is done by setting the variable
Enabling the admin panel for an account, and thus making the account holder admin of the node, is done by setting the variable
$a->config['admin_email'] = "someone@example.com";
where you have to match the email address used for the account with the one you
enter to the .htconfig file. If more then one account should be able to access
the admin panel, seperate the email addresses with a comma.
Where you have to match the email address used for the account with the one you enter to the .htconfig file.
If more then one account should be able to access the admin panel, seperate the email addresses with a comma.
$a->config['admin_email'] = "someone@example.com,someonelese@example.com";
If you want to have a more personalized closing line for the notification
emails you can set a variable for the admin_name.
If you want to have a more personalized closing line for the notification emails you can set a variable for the admin_name.
$a->config['admin_name'] = "Marvin";

View file

@ -27,7 +27,7 @@ Friendica Documentation and Resources
**Technical Documentation**
* [Install](help/Install)
* [Settings](help/Settings)
* [Settings & Admin Panel](help/Settings)
* [Plugins](help/Plugins)
* [Installing Connectors (Twitter/GNU Social)](help/Installing-Connectors)
* [Install an ejabberd server (XMPP chat) with synchronized credentials](help/install-ejabberd)

View file

@ -24,12 +24,12 @@ If you want to get your work into the source tree yourself, feel free to do so a
The process is simple and friendica ships with all the tools necessary.
The location of the translated files in the source tree is
/view/LNG-CODE/
/view/lang/LNG-CODE/
where LNG-CODE is the language code used, e.g. de for German or fr for French.
The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses.
To do so, place the file in the directory mentioned above and use the "po2php" utility from the util directory of your friendica installation.
Assuming you want to convert the German localization which is placed in view/de/message.po you would do the following.
Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following.
1. Navigate at the command prompt to the base directory of your
friendica installation
@ -37,9 +37,9 @@ Assuming you want to convert the German localization which is placed in view/de/
2. Execute the po2php script, which will place the translation
in the strings.php file that is used by friendica.
$> php util/po2php.php view/de/messages.po
$> php util/po2php.php view/lang/de/messages.po
The output of the script will be placed at view/de/strings.php where
The output of the script will be placed at view/lang/de/strings.php where
friendica is expecting it, so you can test your translation immediately.
3. Visit your friendica page to check if it still works in the language you
@ -50,7 +50,7 @@ Assuming you want to convert the German localization which is placed in view/de/
not give any output if the file is ok but might give a hint for
searching the bug in the file.
$> php view/de/strings.php
$> php view/lang/de/strings.php
4. commit the two files with a meaningful commit message to your git
repository, push it to your fork of the friendica repository at github and

34
doc/upgrade.md Normal file
View file

@ -0,0 +1,34 @@
# Considerations before upgrading Friendica
* [Home](help)
## MySQL >= 5.7.4
Starting from MySQL version 5.7.4, the IGNORE keyword in ALTER TABLE statements is ignored.
This prevents automatic table deduplication if a UNIQUE index is added to a Friendica table's structure.
If a DB update fails for you while creating a UNIQUE index, make sure to manually deduplicate the table before trying the update again.
### Manual deduplication
There are two main ways of doing it, either by manually removing the duplicates or by recreating the table.
Manually removing the duplicates is usually faster if they're not too numerous.
To manually remove the duplicates, you need to know the UNIQUE index columns available in `database.sql`.
```SQL
SELECT GROUP_CONCAT(id), <index columns>, count(*) as count FROM users
GROUP BY <index columns> HAVING count >= 2;
/* delete or merge duplicate from above query */;
```
If there are too many rows to handle manually, you can create a new table with the same structure as the table with duplicates and insert the existing content with INSERT IGNORE.
To recreate the table you need to know the table structure available in `database.sql`.
```SQL
CREATE TABLE <table_name>_new <rest of the CREATE TABLE>;
INSERT IGNORE INTO <table_name>_new SELECT * FROM <table_name>;
DROP TABLE <table_name>;
RENAME TABLE <table_name>_new TO <table_name>;
```
This method is slower overall, but it is better suited for large numbers of duplicates.

View file

@ -16,6 +16,11 @@ $db_user = 'mysqlusername';
$db_pass = 'mysqlpassword';
$db_data = 'mysqldatabasename';
// Set the database connection charset to UTF8.
// Changing this value will likely corrupt the special characters.
// You have been warned.
$a->config['system']['db_charset'] = "utf8mb4";
// Choose a legal default timezone. If you are unsure, use "America/Los_Angeles".
// It can be changed later and only applies to timestamps for anonymous viewers.

View file

@ -45,10 +45,10 @@ function user_remove($uid) {
// don't delete yet, will be done later when contacts have deleted my stuff
// q("DELETE FROM `user` WHERE `uid` = %d", intval($uid));
q("UPDATE `user` SET `account_removed` = 1, `account_expires_on` = UTC_TIMESTAMP() WHERE `uid` = %d", intval($uid));
proc_run('php', "include/notifier.php", "removeme", $uid);
proc_run(PRIORITY_HIGH, "include/notifier.php", "removeme", $uid);
// Send an update to the directory
proc_run('php', "include/directory.php", $r[0]['url']);
proc_run(PRIORITY_LOW, "include/directory.php", $r[0]['url']);
if($uid == local_user()) {
unset($_SESSION['authenticated']);
@ -159,7 +159,7 @@ function mark_for_death($contact) {
}
else {
/// @todo
/// @todo
/// We really should send a notification to the owner after 2-3 weeks
/// so they won't be surprised when the contact vanishes and can take
/// remedial action if this was a serious mistake or glitch
@ -196,6 +196,7 @@ function unmark_for_death($contact) {
* @brief Get contact data for a given profile link
*
* The function looks at several places (contact table and gcontact table) for the contact
* It caches its result for the same script execution to prevent duplicate calls
*
* @param string $url The profile link
* @param int $uid User id
@ -204,35 +205,45 @@ function unmark_for_death($contact) {
* @return array Contact data
*/
function get_contact_details_by_url($url, $uid = -1, $default = array()) {
if ($uid == -1)
static $cache = array();
if ($uid == -1) {
$uid = local_user();
}
if (isset($cache[$url][$uid])) {
return $cache[$url][$uid];
}
// Fetch contact data from the contact table for the given user
$r = q("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`,
`keywords`, `gender`, `photo`, `thumb`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `bd` AS `birthday`, `self`
$r = q("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
`keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d",
dbesc(normalise_link($url)), intval($uid));
// Fetch the data from the contact table with "uid=0" (which is filled automatically)
if (!$r)
$r = q("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`,
`keywords`, `gender`, `photo`, `thumb`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `bd` AS `birthday`, 0 AS `self`
$r = q("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
`keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
FROM `contact` WHERE `nurl` = '%s' AND `uid` = 0",
dbesc(normalise_link($url)));
// Fetch the data from the gcontact table
if (!$r)
$r = q("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`,
`keywords`, `gender`, `photo`, `photo` AS `thumb`, `community` AS `forum`, 0 AS `prv`, `community`, `birthday`, 0 AS `self`
$r = q("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
`keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
FROM `gcontact` WHERE `nurl` = '%s'",
dbesc(normalise_link($url)));
if ($r) {
// If there is more than one entry we filter out the connector networks
if (count($r) > 1)
foreach ($r AS $id => $result)
if ($result["network"] == NETWORK_STATUSNET)
if (count($r) > 1) {
foreach ($r AS $id => $result) {
if ($result["network"] == NETWORK_STATUSNET) {
unset($r[$id]);
}
}
}
$profile = array_shift($r);
@ -251,19 +262,40 @@ function get_contact_details_by_url($url, $uid = -1, $default = array()) {
$profile["bd"] = $current_year."-".$month."-".$day;
$current = $current_year."-".$current_month."-".$current_day;
if ($profile["bd"] < $current)
if ($profile["bd"] < $current) {
$profile["bd"] = (++$current_year)."-".$month."-".$day;
} else
}
} else {
$profile["bd"] = "0000-00-00";
}
} else {
$profile = $default;
if (!isset($profile["thumb"]) AND isset($profile["photo"]))
$profile["thumb"] = $profile["photo"];
}
if (($profile["photo"] == "") AND isset($default["photo"])) {
$profile["photo"] = $default["photo"];
}
if (($profile["name"] == "") AND isset($default["name"])) {
$profile["name"] = $default["name"];
}
if (($profile["network"] == "") AND isset($default["network"])) {
$profile["network"] = $default["network"];
}
if (($profile["thumb"] == "") AND isset($profile["photo"])) {
$profile["thumb"] = $profile["photo"];
}
if (($profile["micro"] == "") AND isset($profile["thumb"])) {
$profile["micro"] = $profile["thumb"];
}
if ((($profile["addr"] == "") OR ($profile["name"] == "")) AND ($profile["gid"] != 0) AND
in_array($profile["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS)))
proc_run('php',"include/update_gcontact.php", $profile["gid"]);
in_array($profile["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
proc_run(PRIORITY_LOW, "include/update_gcontact.php", $profile["gid"]);
}
// Show contact details of Diaspora contacts only if connected
if (($profile["cid"] == 0) AND ($profile["network"] == NETWORK_DIASPORA)) {
@ -273,87 +305,93 @@ function get_contact_details_by_url($url, $uid = -1, $default = array()) {
$profile["birthday"] = "0000-00-00";
}
return($profile);
$cache[$url][$uid] = $profile;
return $profile;
}
if(! function_exists('contact_photo_menu')){
function contact_photo_menu($contact, $uid = 0) {
if (! function_exists('contact_photo_menu')) {
function contact_photo_menu($contact, $uid = 0)
{
$a = get_app();
$contact_url="";
$pm_url="";
$status_link="";
$photos_link="";
$posts_link="";
$contact_drop_link = "";
$poke_link="";
$contact_url = '';
$pm_url = '';
$status_link = '';
$photos_link = '';
$posts_link = '';
$contact_drop_link = '';
$poke_link = '';
if ($uid == 0)
if ($uid == 0) {
$uid = local_user();
}
if ($contact["uid"] != $uid) {
if ($contact['uid'] != $uid) {
if ($uid == 0) {
$profile_link = zrl($contact['url']);
$menu = Array('profile' => array(t("View Profile"), $profile_link, true));
$menu = Array('profile' => array(t('View Profile'), $profile_link, true));
return $menu;
}
$r = q("SELECT * FROM `contact` WHERE `nurl` = '%s' AND `network` = '%s' AND `uid` = %d",
dbesc($contact["nurl"]), dbesc($contact["network"]), intval($uid));
if ($r)
dbesc($contact['nurl']), dbesc($contact['network']), intval($uid));
if ($r) {
return contact_photo_menu($r[0], $uid);
else {
} else {
$profile_link = zrl($contact['url']);
$connlnk = 'follow/?url='.$contact['url'];
$menu = Array(
'profile' => array(t("View Profile"), $profile_link, true),
'follow' => array(t("Connect/Follow"), $connlnk, true)
);
$menu = array(
'profile' => array(t('View Profile'), $profile_link, true),
'follow' => array(t('Connect/Follow'), $connlnk, true)
);
return $menu;
}
}
$sparkle = false;
if($contact['network'] === NETWORK_DFRN) {
if ($contact['network'] === NETWORK_DFRN) {
$sparkle = true;
$profile_link = $a->get_baseurl() . '/redir/' . $contact['id'];
}
else
} else {
$profile_link = $contact['url'];
if($profile_link === 'mailbox')
$profile_link = '';
if($sparkle) {
$status_link = $profile_link . "?url=status";
$photos_link = $profile_link . "?url=photos";
$profile_link = $profile_link . "?url=profile";
}
if (in_array($contact["network"], array(NETWORK_DFRN, NETWORK_DIASPORA)))
$pm_url = $a->get_baseurl() . '/message/new/' . $contact['id'];
if ($profile_link === 'mailbox') {
$profile_link = '';
}
if ($contact["network"] == NETWORK_DFRN)
if ($sparkle) {
$status_link = $profile_link . '?url=status';
$photos_link = $profile_link . '?url=photos';
$profile_link = $profile_link . '?url=profile';
}
if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_DIASPORA))) {
$pm_url = $a->get_baseurl() . '/message/new/' . $contact['id'];
}
if ($contact['network'] == NETWORK_DFRN) {
$poke_link = $a->get_baseurl() . '/poke/?f=&c=' . $contact['id'];
}
$contact_url = $a->get_baseurl() . '/contacts/' . $contact['id'];
$posts_link = $a->get_baseurl() . "/contacts/" . $contact['id'] . '/posts';
$contact_drop_link = $a->get_baseurl() . "/contacts/" . $contact['id'] . '/drop?confirm=1';
$posts_link = $a->get_baseurl() . '/contacts/' . $contact['id'] . '/posts';
$contact_drop_link = $a->get_baseurl() . '/contacts/' . $contact['id'] . '/drop?confirm=1';
/**
* menu array:
* "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
*/
$menu = Array(
$menu = array(
'status' => array(t("View Status"), $status_link, true),
'profile' => array(t("View Profile"), $profile_link, true),
'photos' => array(t("View Photos"), $photos_link,true),
'network' => array(t("Network Posts"), $posts_link,false),
'edit' => array(t("Edit Contact"), $contact_url, false),
'photos' => array(t("View Photos"), $photos_link, true),
'network' => array(t("Network Posts"), $posts_link, false),
'edit' => array(t("View Contact"), $contact_url, false),
'drop' => array(t("Drop Contact"), $contact_drop_link, false),
'pm' => array(t("Send PM"), $pm_url, false),
'poke' => array(t("Poke"), $poke_link, false),
@ -366,9 +404,11 @@ function contact_photo_menu($contact, $uid = 0) {
$menucondensed = array();
foreach ($menu AS $menuname=>$menuitem)
if ($menuitem[1] != "")
foreach ($menu AS $menuname => $menuitem) {
if ($menuitem[1] != '') {
$menucondensed[$menuname] = $menuitem;
}
}
return $menucondensed;
}}
@ -410,9 +450,20 @@ function contacts_not_grouped($uid,$start = 0,$count = 0) {
return $r;
}
function get_contact($url, $uid = 0) {
/**
* @brief Fetch the contact id for a given url and user
*
* @param string $url Contact URL
* @param integer $uid The user id for the contact
* @param boolean $no_update Don't update the contact
*
* @return integer Contact ID
*/
function get_contact($url, $uid = 0, $no_update = false) {
require_once("include/Scrape.php");
logger("Get contact data for url ".$url." and user ".$uid." - ".App::callstack(), LOGGER_DEBUG);;
$data = array();
$contactid = 0;
@ -442,8 +493,9 @@ function get_contact($url, $uid = 0) {
$update_photo = ($contact[0]['avatar-date'] < datetime_convert('','','now -7 days'));
//$update_photo = ($contact[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
if (!$update_photo)
if (!$update_photo OR $no_update) {
return($contactid);
}
} elseif ($uid != 0)
return 0;
@ -451,17 +503,27 @@ function get_contact($url, $uid = 0) {
$data = probe_url($url);
// Does this address belongs to a valid network?
if (!in_array($data["network"], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA)))
return 0;
if (!in_array($data["network"], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA))) {
if ($uid != 0)
return 0;
// Get data from the gcontact table
$r = q("SELECT `name`, `nick`, `url`, `photo`, `addr`, `alias`, `network` FROM `gcontact` WHERE `nurl` = '%s'",
dbesc(normalise_link($url)));
if (!$r)
return 0;
$data = $r[0];
}
$url = $data["url"];
if ($contactid == 0) {
q("INSERT INTO `contact` (`uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
`name`, `nick`, `photo`, `network`, `pubkey`, `rel`, `priority`,
`batch`, `request`, `confirm`, `poco`,
`batch`, `request`, `confirm`, `poco`, `name-date`, `uri-date`,
`writable`, `blocked`, `readonly`, `pending`)
VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', 1, 0, 0, 0)",
VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', 1, 0, 0, 0)",
intval($uid),
dbesc(datetime_convert()),
dbesc($data["url"]),
@ -480,7 +542,9 @@ function get_contact($url, $uid = 0) {
dbesc($data["batch"]),
dbesc($data["request"]),
dbesc($data["confirm"]),
dbesc($data["poco"])
dbesc($data["poco"]),
dbesc(datetime_convert()),
dbesc(datetime_convert())
);
$contact = q("SELECT `id` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d ORDER BY `id` LIMIT 2",
@ -490,6 +554,16 @@ function get_contact($url, $uid = 0) {
return 0;
$contactid = $contact[0]["id"];
// Update the newly created contact from data in the gcontact table
$r = q("SELECT `location`, `about`, `keywords`, `gender` FROM `gcontact` WHERE `nurl` = '%s'",
dbesc(normalise_link($data["url"])));
if ($r) {
logger("Update contact ".$data["url"]);
q("UPDATE `contact` SET `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `id` = %d",
dbesc($r["location"]), dbesc($r["about"]), dbesc($r["keywords"]),
dbesc($r["gender"]), intval($contactid));
}
}
if ((count($contact) > 1) AND ($uid == 0) AND ($contactid != 0) AND ($url != ""))
@ -501,16 +575,27 @@ function get_contact($url, $uid = 0) {
update_contact_avatar($data["photo"],$uid,$contactid);
q("UPDATE `contact` SET `addr` = '%s', `alias` = '%s', `name` = '%s', `nick` = '%s',
`name-date` = '%s', `uri-date` = '%s' WHERE `id` = %d",
dbesc($data["addr"]),
dbesc($data["alias"]),
dbesc($data["name"]),
dbesc($data["nick"]),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($contactid)
);
$r = q("SELECT `addr`, `alias`, `name`, `nick` FROM `contact` WHERE `id` = %d", intval($contactid));
// This condition should always be true
if (!dbm::is_result($r))
return $contactid;
// Only update if there had something been changed
if (($data["addr"] != $r[0]["addr"]) OR
($data["alias"] != $r[0]["alias"]) OR
($data["name"] != $r[0]["name"]) OR
($data["nick"] != $r[0]["nick"]))
q("UPDATE `contact` SET `addr` = '%s', `alias` = '%s', `name` = '%s', `nick` = '%s',
`name-date` = '%s', `uri-date` = '%s' WHERE `id` = %d",
dbesc($data["addr"]),
dbesc($data["alias"]),
dbesc($data["name"]),
dbesc($data["nick"]),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($contactid)
);
return $contactid;
}
@ -599,11 +684,11 @@ function posts_from_contact($a, $contact_id) {
$r = q("SELECT `item`.`uri`, `item`.*, `item`.`id` AS `item_id`,
`author-name` AS `name`, `owner-avatar` AS `photo`,
`owner-link` AS `url`, `owner-avatar` AS `thumb`
FROM `item` FORCE INDEX (`uid_contactid_created`)
FROM `item` FORCE INDEX (`uid_contactid_id`)
WHERE `item`.`uid` = %d AND `contact-id` = %d
AND `author-link` IN ('%s', '%s')
AND NOT `deleted` AND NOT `moderated` AND `visible`
ORDER BY `item`.`created` DESC LIMIT %d, %d",
ORDER BY `item`.`id` DESC LIMIT %d, %d",
intval(local_user()),
intval($contact_id),
dbesc(str_replace("https://", "http://", $contact["url"])),
@ -651,4 +736,50 @@ function formatted_location($profile) {
return $location;
}
/**
* @brief Returns the account type name
*
* The function can be called with either the user or the contact array
*
* @param array $contact contact or user array
*/
function account_type($contact) {
// There are several fields that indicate that the contact or user is a forum
// "page-flags" is a field in the user table,
// "forum" and "prv" are used in the contact table. They stand for PAGE_COMMUNITY and PAGE_PRVGROUP.
// "community" is used in the gcontact table and is true if the contact is PAGE_COMMUNITY or PAGE_PRVGROUP.
if((isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_COMMUNITY))
|| (isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_PRVGROUP))
|| (isset($contact['forum']) && intval($contact['forum']))
|| (isset($contact['prv']) && intval($contact['prv']))
|| (isset($contact['community']) && intval($contact['community'])))
$type = ACCOUNT_TYPE_COMMUNITY;
else
$type = ACCOUNT_TYPE_PERSON;
// The "contact-type" (contact table) and "account-type" (user table) are more general then the chaos from above.
if (isset($contact["contact-type"]))
$type = $contact["contact-type"];
if (isset($contact["account-type"]))
$type = $contact["account-type"];
switch($type) {
case ACCOUNT_TYPE_ORGANISATION:
$account_type = t("Organisation");
break;
case ACCOUNT_TYPE_NEWS:
$account_type = t('News');
break;
case ACCOUNT_TYPE_COMMUNITY:
$account_type = t("Forum");
break;
default:
$account_type = "";
break;
}
return $account_type;
}
?>

View file

@ -2,7 +2,7 @@
namespace Friendica\Core;
/**
* @file include/Core/Config.php
*
*
* @brief Contains the class with methods for system configuration
*/
@ -32,9 +32,9 @@ class Config {
public static function load($family) {
global $a;
$r = q("SELECT `v`, `k` FROM `config` WHERE `cat` = '%s'", dbesc($family));
if(count($r)) {
foreach($r as $rr) {
$r = q("SELECT `v`, `k` FROM `config` WHERE `cat` = '%s' ORDER BY `cat`, `k`, `id`", dbesc($family));
if (count($r)) {
foreach ($r as $rr) {
$k = $rr['k'];
if ($family === 'config') {
$a->config[$k] = $rr['v'];
@ -70,74 +70,38 @@ class Config {
* If true the config is loaded from the db and not from the cache (default: false)
* @return mixed Stored value or null if it does not exist
*/
public static function get($family, $key, $default_value=null, $refresh = false) {
public static function get($family, $key, $default_value = null, $refresh = false) {
global $a;
if(! $instore) {
if (!$refresh) {
// Looking if the whole family isn't set
if(isset($a->config[$family])) {
if($a->config[$family] === '!<unset>!') {
if (isset($a->config[$family])) {
if ($a->config[$family] === '!<unset>!') {
return $default_value;
}
}
if(isset($a->config[$family][$key])) {
if($a->config[$family][$key] === '!<unset>!') {
if (isset($a->config[$family][$key])) {
if ($a->config[$family][$key] === '!<unset>!') {
return $default_value;
}
return $a->config[$family][$key];
}
}
// If APC is enabled then fetch the data from there, else try XCache
/*if (function_exists("apc_fetch") AND function_exists("apc_exists"))
if (apc_exists($family."|".$key)) {
$val = apc_fetch($family."|".$key);
$a->config[$family][$key] = $val;
if ($val === '!<unset>!')
return false;
else
return $val;
}
elseif (function_exists("xcache_fetch") AND function_exists("xcache_isset"))
if (xcache_isset($family."|".$key)) {
$val = xcache_fetch($family."|".$key);
$a->config[$family][$key] = $val;
if ($val === '!<unset>!')
return false;
else
return $val;
}
*/
$ret = q("SELECT `v` FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1",
$ret = q("SELECT `v` FROM `config` WHERE `cat` = '%s' AND `k` = '%s' ORDER BY `id` DESC LIMIT 1",
dbesc($family),
dbesc($key)
);
if(count($ret)) {
if (count($ret)) {
// manage array value
$val = (preg_match("|^a:[0-9]+:{.*}$|s", $ret[0]['v'])?unserialize( $ret[0]['v']):$ret[0]['v']);
$a->config[$family][$key] = $val;
// If APC is enabled then store the data there, else try XCache
/*if (function_exists("apc_store"))
apc_store($family."|".$key, $val, 600);
elseif (function_exists("xcache_set"))
xcache_set($family."|".$key, $val, 600);*/
return $val;
}
else {
} else {
$a->config[$family][$key] = '!<unset>!';
// If APC is enabled then store the data there, else try XCache
/*if (function_exists("apc_store"))
apc_store($family."|".$key, '!<unset>!', 600);
elseif (function_exists("xcache_set"))
xcache_set($family."|".$key, '!<unset>!', 600);*/
}
return $default_value;
}
@ -158,48 +122,38 @@ class Config {
* The value to store
* @return mixed Stored $value or false if the database update failed
*/
public static function set($family,$key,$value) {
public static function set($family, $key, $value) {
global $a;
// If $a->config[$family] has been previously set to '!<unset>!', then
// $a->config[$family][$key] will evaluate to $a->config[$family][0], and
// $a->config[$family][$key] = $value will be equivalent to
// $a->config[$family][0] = $value[0] (this causes infuriating bugs),
// so unset the family before assigning a value to a family's key
if($a->config[$family] === '!<unset>!')
unset($a->config[$family]);
$stored = self::get($family, $key);
// manage array value
$dbvalue = (is_array($value)?serialize($value):$value);
$dbvalue = (is_bool($dbvalue) ? intval($dbvalue) : $dbvalue);
if(is_null(self::get($family,$key,null,true))) {
$a->config[$family][$key] = $value;
$ret = q("INSERT INTO `config` ( `cat`, `k`, `v` ) VALUES ( '%s', '%s', '%s' ) ",
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
if($ret)
return $value;
return $ret;
if ($stored == $value) {
return true;
}
$ret = q("UPDATE `config` SET `v` = '%s' WHERE `cat` = '%s' AND `k` = '%s'",
dbesc($dbvalue),
dbesc($family),
dbesc($key)
);
$a->config[$family][$key] = $value;
// If APC is enabled then store the data there, else try XCache
/*if (function_exists("apc_store"))
apc_store($family."|".$key, $value, 600);
elseif (function_exists("xcache_set"))
xcache_set($family."|".$key, $value, 600);*/
// manage array value
$dbvalue = (is_array($value) ? serialize($value) : $value);
$dbvalue = (is_bool($dbvalue) ? intval($dbvalue) : $dbvalue);
if($ret)
if (is_null($stored)) {
$ret = q("INSERT INTO `config` (`cat`, `k`, `v`) VALUES ('%s', '%s', '%s') ON DUPLICATE KEY UPDATE `v` = '%s'",
dbesc($family),
dbesc($key),
dbesc($dbvalue),
dbesc($dbvalue)
);
} else {
$ret = q("UPDATE `config` SET `v` = '%s' WHERE `cat` = '%s' AND `k` = '%s'",
dbesc($dbvalue),
dbesc($family),
dbesc($key)
);
}
if ($ret) {
return $value;
}
return $ret;
}
@ -215,20 +169,16 @@ class Config {
* The configuration key to delete
* @return mixed
*/
public static function delete($family,$key) {
public static function delete($family, $key) {
global $a;
if(x($a->config[$family],$key))
if (x($a->config[$family],$key)) {
unset($a->config[$family][$key]);
}
$ret = q("DELETE FROM `config` WHERE `cat` = '%s' AND `k` = '%s'",
dbesc($family),
dbesc($key)
);
// If APC is enabled then delete the data from there, else try XCache
/*if (function_exists("apc_delete"))
apc_delete($family."|".$key);
elseif (function_exists("xcache_unset"))
xcache_unset($family."|".$key);*/
return $ret;
}

View file

@ -27,14 +27,14 @@ class PConfig {
* The category of the configuration value
* @return void
*/
public static function load($uid,$family) {
public static function load($uid, $family) {
global $a;
$r = q("SELECT `v`,`k` FROM `pconfig` WHERE `cat` = '%s' AND `uid` = %d",
$r = q("SELECT `v`,`k` FROM `pconfig` WHERE `cat` = '%s' AND `uid` = %d ORDER BY `cat`, `k`, `id`",
dbesc($family),
intval($uid)
);
if(count($r)) {
foreach($r as $rr) {
if (count($r)) {
foreach ($r as $rr) {
$k = $rr['k'];
$a->config[$uid][$family][$k] = $rr['v'];
}
@ -67,71 +67,35 @@ class PConfig {
global $a;
if(! $instore) {
if (!$refresh) {
// Looking if the whole family isn't set
if(isset($a->config[$uid][$family])) {
if($a->config[$uid][$family] === '!<unset>!') {
if (isset($a->config[$uid][$family])) {
if ($a->config[$uid][$family] === '!<unset>!') {
return $default_value;
}
}
if(isset($a->config[$uid][$family][$key])) {
if($a->config[$uid][$family][$key] === '!<unset>!') {
if (isset($a->config[$uid][$family][$key])) {
if ($a->config[$uid][$family][$key] === '!<unset>!') {
return $default_value;
}
return $a->config[$uid][$family][$key];
}
}
// If APC is enabled then fetch the data from there, else try XCache
/*if (function_exists("apc_fetch") AND function_exists("apc_exists"))
if (apc_exists($uid."|".$family."|".$key)) {
$val = apc_fetch($uid."|".$family."|".$key);
$a->config[$uid][$family][$key] = $val;
if ($val === '!<unset>!')
return false;
else
return $val;
}
elseif (function_exists("xcache_get") AND function_exists("xcache_isset"))
if (xcache_isset($uid."|".$family."|".$key)) {
$val = xcache_get($uid."|".$family."|".$key);
$a->config[$uid][$family][$key] = $val;
if ($val === '!<unset>!')
return false;
else
return $val;
}*/
$ret = q("SELECT `v` FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1",
$ret = q("SELECT `v` FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' ORDER BY `id` DESC LIMIT 1",
intval($uid),
dbesc($family),
dbesc($key)
);
if(count($ret)) {
if (count($ret)) {
$val = (preg_match("|^a:[0-9]+:{.*}$|s", $ret[0]['v'])?unserialize( $ret[0]['v']):$ret[0]['v']);
$a->config[$uid][$family][$key] = $val;
// If APC is enabled then store the data there, else try XCache
/*if (function_exists("apc_store"))
apc_store($uid."|".$family."|".$key, $val, 600);
elseif (function_exists("xcache_set"))
xcache_set($uid."|".$family."|".$key, $val, 600);*/
return $val;
}
else {
} else {
$a->config[$uid][$family][$key] = '!<unset>!';
// If APC is enabled then store the data there, else try XCache
/*if (function_exists("apc_store"))
apc_store($uid."|".$family."|".$key, '!<unset>!', 600);
elseif (function_exists("xcache_set"))
xcache_set($uid."|".$family."|".$key, '!<unset>!', 600);*/
}
return $default_value;
}
@ -154,43 +118,41 @@ class PConfig {
* The value to store
* @return mixed Stored $value or false
*/
public static function set($uid,$family,$key,$value) {
public static function set($uid, $family, $key, $value) {
global $a;
// manage array value
$dbvalue = (is_array($value)?serialize($value):$value);
$stored = self::get($uid, $family, $key);
if(is_null(self::get($uid,$family,$key,null, true))) {
$a->config[$uid][$family][$key] = $value;
$ret = q("INSERT INTO `pconfig` ( `uid`, `cat`, `k`, `v` ) VALUES ( %d, '%s', '%s', '%s' ) ",
intval($uid),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
if($ret)
return $value;
return $ret;
if ($stored == $value) {
return true;
}
$ret = q("UPDATE `pconfig` SET `v` = '%s' WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s'",
dbesc($dbvalue),
intval($uid),
dbesc($family),
dbesc($key)
);
// manage array value
$dbvalue = (is_array($value) ? serialize($value):$value);
$a->config[$uid][$family][$key] = $value;
// If APC is enabled then store the data there, else try XCache
/*if (function_exists("apc_store"))
apc_store($uid."|".$family."|".$key, $value, 600);
elseif (function_exists("xcache_set"))
xcache_set($uid."|".$family."|".$key, $value, 600);*/
if (is_null($stored)) {
$ret = q("INSERT INTO `pconfig` (`uid`, `cat`, `k`, `v`) VALUES (%d, '%s', '%s', '%s') ON DUPLICATE KEY UPDATE `v` = '%s'",
intval($uid),
dbesc($family),
dbesc($key),
dbesc($dbvalue),
dbesc($dbvalue)
);
} else {
$ret = q("UPDATE `pconfig` SET `v` = '%s' WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s'",
dbesc($dbvalue),
intval($uid),
dbesc($family),
dbesc($key)
);
}
if($ret)
if ($ret) {
return $value;
}
return $ret;
}
@ -210,13 +172,17 @@ class PConfig {
public static function delete($uid,$family,$key) {
global $a;
if(x($a->config[$uid][$family],$key))
if (x($a->config[$uid][$family], $key)) {
unset($a->config[$uid][$family][$key]);
}
$ret = q("DELETE FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s'",
intval($uid),
dbesc($family),
dbesc($key)
);
return $ret;
}
}

View file

@ -30,8 +30,8 @@ class Emailer {
// generate a mime boundary
$mimeBoundary =rand(0,9)."-"
.rand(10000000000,99999999999)."-"
.rand(10000000000,99999999999)."=:"
.rand(100000000,999999999)."-"
.rand(100000000,999999999)."=:"
.rand(10000,99999);
// generate a multipart/alternative message header

View file

@ -26,6 +26,7 @@ class ForumManager {
* 'name' => forum name
* 'id' => number of the key from the array
* 'micro' => contact photo in format micro
* 'thumb' => contact photo in format thumb
*/
public static function get_list($uid, $showhidden = true, $lastitem, $showprivate = false) {
@ -38,7 +39,7 @@ class ForumManager {
$select = '(`forum` OR `prv`)';
}
$contacts = q("SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro` FROM `contact`
$contacts = q("SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro`, `contact`.`thumb` FROM `contact`
WHERE `network`= 'dfrn' AND $select AND `uid` = %d
AND NOT `blocked` AND NOT `hidden` AND NOT `pending` AND NOT `archive`
AND `success_update` > `failure_update`
@ -55,6 +56,7 @@ class ForumManager {
'name' => $contact['name'],
'id' => $contact['id'],
'micro' => $contact['micro'],
'thumb' => $contact['thumb'],
);
}
return($forumlist);
@ -86,7 +88,7 @@ class ForumManager {
$total = count($contacts);
$visible_forums = 10;
if(count($contacts)) {
if(dbm::is_result($contacts)) {
$id = 0;

View file

@ -1,21 +1,24 @@
<?php
/**
* @file include/NotificationsManager.php
* @brief Methods for read and write notifications from/to database
* or for formatting notifications
*/
require_once('include/html2plain.php');
require_once("include/datetime.php");
require_once("include/bbcode.php");
/**
* @brief Read and write notifications from/to database
* @brief Methods for read and write notifications from/to database
* or for formatting notifications
*/
class NotificationsManager {
private $a;
public function __construct() {
$this->a = get_app();
}
private $a;
public function __construct() {
$this->a = get_app();
}
/**
* @brief set some extra note properties
*
@ -28,109 +31,780 @@ class NotificationsManager {
* - msg_html: message as html string
* - msg_plain: message as plain text string
*/
private function _set_extra($notes) {
$rets = array();
foreach($notes as $n) {
$local_time = datetime_convert('UTC',date_default_timezone_get(),$n['date']);
$n['timestamp'] = strtotime($local_time);
$n['date_rel'] = relative_date($n['date']);
$n['msg_html'] = bbcode($n['msg'], false, false, false, false);
$n['msg_plain'] = explode("\n",trim(html2plain($n['msg_html'], 0)))[0];
$rets[] = $n;
}
return $rets;
}
private function _set_extra($notes) {
$rets = array();
foreach($notes as $n) {
$local_time = datetime_convert('UTC',date_default_timezone_get(),$n['date']);
$n['timestamp'] = strtotime($local_time);
$n['date_rel'] = relative_date($n['date']);
$n['msg_html'] = bbcode($n['msg'], false, false, false, false);
$n['msg_plain'] = explode("\n",trim(html2plain($n['msg_html'], 0)))[0];
$rets[] = $n;
}
return $rets;
}
/**
* @brief get all notifications for local_user()
*
* @param array $filter optional Array "column name"=>value: filter query by columns values
* @param string $order optional Space separated list of column to sort by. prepend name with "+" to sort ASC, "-" to sort DESC. Default to "-date"
* @param string $limit optional Query limits
*
* @return array of results or false on errors
*/
public function getAll($filter = array(), $order="-date", $limit="") {
$filter_str = array();
$filter_sql = "";
foreach($filter as $column => $value) {
$filter_str[] = sprintf("`%s` = '%s'", $column, dbesc($value));
}
if (count($filter_str)>0) {
$filter_sql = "AND ".implode(" AND ", $filter_str);
}
$aOrder = explode(" ", $order);
$asOrder = array();
foreach($aOrder as $o) {
$dir = "asc";
if ($o[0]==="-") {
$dir = "desc";
$o = substr($o,1);
}
if ($o[0]==="+") {
$dir = "asc";
$o = substr($o,1);
}
$asOrder[] = "$o $dir";
}
$order_sql = implode(", ", $asOrder);
if ($limit!="") $limit = " LIMIT ".$limit;
$r = q("SELECT * FROM `notify` WHERE `uid` = %d $filter_sql ORDER BY $order_sql $limit",
/**
* @brief Get all notifications for local_user()
*
* @param array $filter optional Array "column name"=>value: filter query by columns values
* @param string $order optional Space separated list of column to sort by. prepend name with "+" to sort ASC, "-" to sort DESC. Default to "-date"
* @param string $limit optional Query limits
*
* @return array of results or false on errors
*/
public function getAll($filter = array(), $order="-date", $limit="") {
$filter_str = array();
$filter_sql = "";
foreach($filter as $column => $value) {
$filter_str[] = sprintf("`%s` = '%s'", $column, dbesc($value));
}
if (count($filter_str)>0) {
$filter_sql = "AND ".implode(" AND ", $filter_str);
}
$aOrder = explode(" ", $order);
$asOrder = array();
foreach($aOrder as $o) {
$dir = "asc";
if ($o[0]==="-") {
$dir = "desc";
$o = substr($o,1);
}
if ($o[0]==="+") {
$dir = "asc";
$o = substr($o,1);
}
$asOrder[] = "$o $dir";
}
$order_sql = implode(", ", $asOrder);
if($limit!="")
$limit = " LIMIT ".$limit;
$r = q("SELECT * FROM `notify` WHERE `uid` = %d $filter_sql ORDER BY $order_sql $limit",
intval(local_user())
);
if(dbm::is_result($r))
return $this->_set_extra($r);
return false;
}
/**
* @brief Get one note for local_user() by $id value
*
* @param int $id
* @return array note values or null if not found
*/
public function getByID($id) {
$r = q("SELECT * FROM `notify` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($id),
intval(local_user())
);
if ($r!==false && count($r)>0) return $this->_set_extra($r);
return false;
}
/**
* @brief get one note for local_user() by $id value
*
* @param int $id
* @return array note values or null if not found
*/
public function getByID($id) {
$r = q("SELECT * FROM `notify` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($id),
intval(local_user())
);
if($r!==false && count($r)>0) {
return $this->_set_extra($r)[0];
}
return null;
}
/**
* @brief set seen state of $note of local_user()
*
* @param array $note
* @param bool $seen optional true or false, default true
* @return bool true on success, false on errors
*/
public function setSeen($note, $seen = true) {
return q("UPDATE `notify` SET `seen` = %d WHERE ( `link` = '%s' OR ( `parent` != 0 AND `parent` = %d AND `otype` = '%s' )) AND `uid` = %d",
intval($seen),
dbesc($note['link']),
intval($note['parent']),
dbesc($note['otype']),
intval(local_user())
);
}
/**
* @brief set seen state of all notifications of local_user()
*
* @param bool $seen optional true or false. default true
* @return bool true on success, false on error
*/
public function setAllSeen($seen = true) {
return q("UPDATE `notify` SET `seen` = %d WHERE `uid` = %d",
intval($seen),
if(dbm::is_result($r)) {
return $this->_set_extra($r)[0];
}
return null;
}
/**
* @brief set seen state of $note of local_user()
*
* @param array $note
* @param bool $seen optional true or false, default true
* @return bool true on success, false on errors
*/
public function setSeen($note, $seen = true) {
return q("UPDATE `notify` SET `seen` = %d WHERE ( `link` = '%s' OR ( `parent` != 0 AND `parent` = %d AND `otype` = '%s' )) AND `uid` = %d",
intval($seen),
dbesc($note['link']),
intval($note['parent']),
dbesc($note['otype']),
intval(local_user())
);
}
}
/**
* @brief set seen state of all notifications of local_user()
*
* @param bool $seen optional true or false. default true
* @return bool true on success, false on error
*/
public function setAllSeen($seen = true) {
return q("UPDATE `notify` SET `seen` = %d WHERE `uid` = %d",
intval($seen),
intval(local_user())
);
}
/**
* @brief List of pages for the Notifications TabBar
*
* @param app $a The
* @return array with with notifications TabBar data
*/
public function getTabs() {
$tabs = array(
array(
'label' => t('System'),
'url'=>'notifications/system',
'sel'=> (($this->a->argv[1] == 'system') ? 'active' : ''),
'id' => 'system-tab',
'accesskey' => 'y',
),
array(
'label' => t('Network'),
'url'=>'notifications/network',
'sel'=> (($this->a->argv[1] == 'network') ? 'active' : ''),
'id' => 'network-tab',
'accesskey' => 'w',
),
array(
'label' => t('Personal'),
'url'=>'notifications/personal',
'sel'=> (($this->a->argv[1] == 'personal') ? 'active' : ''),
'id' => 'personal-tab',
'accesskey' => 'r',
),
array(
'label' => t('Home'),
'url' => 'notifications/home',
'sel'=> (($this->a->argv[1] == 'home') ? 'active' : ''),
'id' => 'home-tab',
'accesskey' => 'h',
),
array(
'label' => t('Introductions'),
'url' => 'notifications/intros',
'sel'=> (($this->a->argv[1] == 'intros') ? 'active' : ''),
'id' => 'intro-tab',
'accesskey' => 'i',
),
);
return $tabs;
}
/**
* @brief Format the notification query in an usable array
*
* @param array $notifs The array from the db query
* @param string $ident The notifications identifier (e.g. network)
* @return array
* string 'label' => The type of the notification
* string 'link' => URL to the source
* string 'image' => The avatar image
* string 'text' => The notification text
* string 'when' => Relative date of the notification
* bool 'seen' => Is the notification marked as "seen"
*/
private function formatNotifs($notifs, $ident = "") {
$notif = array();
$arr = array();
if (dbm::is_result($notifs)) {
foreach ($notifs as $it) {
// Because we use different db tables for the notification query
// we have sometimes $it['unseen'] and sometimes $it['seen].
// So we will have to transform $it['unseen']
if($it['unseen'])
$it['seen'] = ($it['unseen'] > 0 ? false : true);
// Depending on the identifier of the notification we need to use different defaults
switch ($ident) {
case 'system':
$default_item_label = 'notify';
$default_item_link = $this->a->get_baseurl(true).'/notify/view/'. $it['id'];
$default_item_image = proxy_url($it['photo'], false, PROXY_SIZE_MICRO);
$default_item_text = strip_tags(bbcode($it['msg']));
$default_item_when = relative_date($it['date']);
$default_tpl = $tpl_notify;
break;
case 'home':
$default_item_label = 'comment';
$default_item_link = $this->a->get_baseurl(true).'/display/'.$it['pguid'];
$default_item_image = proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO);
$default_item_text = sprintf( t("%s commented on %s's post"), $it['author-name'], $it['pname']);
$default_item_when = relative_date($it['created']);
$default_tpl = $tpl_item_comments;
break;
default:
$default_item_label = (($it['id'] == $it['parent']) ? 'post' : 'comment');
$default_item_link = $this->a->get_baseurl(true).'/display/'.$it['pguid'];
$default_item_image = proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO);
$default_item_text = (($it['id'] == $it['parent'])
? sprintf( t("%s created a new post"), $it['author-name'])
: sprintf( t("%s commented on %s's post"), $it['author-name'], $it['pname']));
$default_item_when = relative_date($it['created']);
$default_tpl = (($it['id'] == $it['parent']) ? $tpl_item_posts : $tpl_item_comments);
}
// Transform the different types of notification in an usable array
switch($it['verb']){
case ACTIVITY_LIKE:
$notif = array(
'label' => 'like',
'link' => $this->a->get_baseurl(true).'/display/'.$it['pguid'],
'$image' => proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO),
'text' => sprintf( t("%s liked %s's post"), $it['author-name'], $it['pname']),
'when' => relative_date($it['created']),
'seen' => $it['seen']
);
break;
case ACTIVITY_DISLIKE:
$notif = array(
'label' => 'dislike',
'link' => $this->a->get_baseurl(true).'/display/'.$it['pguid'],
'image' => proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO),
'text' => sprintf( t("%s disliked %s's post"), $it['author-name'], $it['pname']),
'when' => relative_date($it['created']),
'seen' => $it['seen']
);
break;
case ACTIVITY_ATTEND:
$notif = array(
'label' => 'attend',
'link' => $this->a->get_baseurl(true).'/display/'.$it['pguid'],
'image' => proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO),
'text' => sprintf( t("%s is attending %s's event"), $it['author-name'], $it['pname']),
'when' => relative_date($it['created']),
'seen' => $it['seen']
);
break;
case ACTIVITY_ATTENDNO:
$notif = array(
'label' => 'attendno',
'link' => $this->a->get_baseurl(true).'/display/'.$it['pguid'],
'image' => proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO),
'text' => sprintf( t("%s is not attending %s's event"), $it['author-name'], $it['pname']),
'when' => relative_date($it['created']),
'seen' => $it['seen']
);
break;
case ACTIVITY_ATTENDMAYBE:
$notif = array(
'label' => 'attendmaybe',
'link' => $this->a->get_baseurl(true).'/display/'.$it['pguid'],
'image' => proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO),
'text' => sprintf( t("%s may attend %s's event"), $it['author-name'], $it['pname']),
'when' => relative_date($it['created']),
'seen' => $it['seen']
);
break;
case ACTIVITY_FRIEND:
$xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">";
$obj = parse_xml_string($xmlhead.$it['object']);
$it['fname'] = $obj->title;
$notif = array(
'label' => 'friend',
'link' => $this->a->get_baseurl(true).'/display/'.$it['pguid'],
'image' => proxy_url($it['author-avatar'], false, PROXY_SIZE_MICRO),
'text' => sprintf( t("%s is now friends with %s"), $it['author-name'], $it['fname']),
'when' => relative_date($it['created']),
'seen' => $it['seen']
);
break;
default:
$notif = array(
'label' => $default_item_label,
'link' => $default_item_link,
'image' => $default_item_image,
'text' => $default_item_text,
'when' => $default_item_when,
'seen' => $it['seen']
);
}
$arr[] = $notif;
}
}
return $arr;
}
/**
* @brief Total number of network notifications
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @return int Number of network notifications
*/
private function networkTotal($seen = 0) {
$sql_seen = "";
if($seen === 0)
$sql_seen = " AND `item`.`unseen` = 1 ";
$r = q("SELECT COUNT(*) AS `total`
FROM `item` INNER JOIN `item` AS `pitem` ON `pitem`.`id`=`item`.`parent`
WHERE `item`.`visible` = 1 AND `pitem`.`parent` != 0 AND
`item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 0
$sql_seen",
intval(local_user())
);
if(dbm::is_result($r))
return $r[0]['total'];
return 0;
}
/**
* @brief Get network notifications
*
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @param int $start Start the query at this point
* @param int $limit Maximum number of query results
*
* @return array with
* string 'ident' => Notification identifier
* int 'total' => Total number of available network notifications
* array 'notifications' => Network notifications
*/
public function networkNotifs($seen = 0, $start = 0, $limit = 80) {
$ident = 'network';
$total = $this->networkTotal($seen);
$notifs = array();
$sql_seen = "";
if($seen === 0)
$sql_seen = " AND `item`.`unseen` = 1 ";
$r = q("SELECT `item`.`id`,`item`.`parent`, `item`.`verb`, `item`.`author-name`, `item`.`unseen`,
`item`.`author-link`, `item`.`author-avatar`, `item`.`created`, `item`.`object` AS `object`,
`pitem`.`author-name` AS `pname`, `pitem`.`author-link` AS `plink`, `pitem`.`guid` AS `pguid`
FROM `item` INNER JOIN `item` AS `pitem` ON `pitem`.`id`=`item`.`parent`
WHERE `item`.`visible` = 1 AND `pitem`.`parent` != 0 AND
`item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 0
$sql_seen
ORDER BY `item`.`created` DESC LIMIT %d, %d ",
intval(local_user()),
intval($start),
intval($limit)
);
if(dbm::is_result($r))
$notifs = $this->formatNotifs($r, $ident);
$arr = array (
'notifications' => $notifs,
'ident' => $ident,
'total' => $total,
);
return $arr;
}
/**
* @brief Total number of system notifications
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @return int Number of system notifications
*/
private function systemTotal($seen = 0) {
$sql_seen = "";
if($seen === 0)
$sql_seen = " AND `seen` = 0 ";
$r = q("SELECT COUNT(*) AS `total` FROM `notify` WHERE `uid` = %d $sql_seen",
intval(local_user())
);
if(dbm::is_result($r))
return $r[0]['total'];
return 0;
}
/**
* @brief Get system notifications
*
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @param int $start Start the query at this point
* @param int $limit Maximum number of query results
*
* @return array with
* string 'ident' => Notification identifier
* int 'total' => Total number of available system notifications
* array 'notifications' => System notifications
*/
public function systemNotifs($seen = 0, $start = 0, $limit = 80) {
$ident = 'system';
$total = $this->systemTotal($seen);
$notifs = array();
$sql_seen = "";
if($seen === 0)
$sql_seen = " AND `seen` = 0 ";
$r = q("SELECT `id`, `photo`, `msg`, `date`, `seen` FROM `notify`
WHERE `uid` = %d $sql_seen ORDER BY `date` DESC LIMIT %d, %d ",
intval(local_user()),
intval($start),
intval($limit)
);
if(dbm::is_result($r))
$notifs = $this->formatNotifs($r, $ident);
$arr = array (
'notifications' => $notifs,
'ident' => $ident,
'total' => $total,
);
return $arr;
}
/**
* @brief Addional SQL query string for the personal notifications
*
* @return string The additional sql query
*/
private function _personal_sql_extra() {
$myurl = $this->a->get_baseurl(true) . '/profile/'. $this->a->user['nickname'];
$myurl = substr($myurl,strpos($myurl,'://')+3);
$myurl = str_replace(array('www.','.'),array('','\\.'),$myurl);
$diasp_url = str_replace('/profile/','/u/',$myurl);
$sql_extra = sprintf(" AND ( `item`.`author-link` regexp '%s' or `item`.`tag` regexp '%s' or `item`.`tag` regexp '%s' ) ",
dbesc($myurl . '$'),
dbesc($myurl . '\\]'),
dbesc($diasp_url . '\\]')
);
return $sql_extra;
}
/**
* @brief Total number of personal notifications
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @return int Number of personal notifications
*/
private function personalTotal($seen = 0) {
$sql_seen = "";
$sql_extra = $this->_personal_sql_extra();
if($seen === 0)
$sql_seen = " AND `item`.`unseen` = 1 ";
$r = q("SELECT COUNT(*) AS `total`
FROM `item` INNER JOIN `item` AS `pitem` ON `pitem`.`id`=`item`.`parent`
WHERE `item`.`visible` = 1
$sql_extra
$sql_seen
AND `item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 0 " ,
intval(local_user())
);
if(dbm::is_result($r))
return $r[0]['total'];
return 0;
}
/**
* @brief Get personal notifications
*
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @param int $start Start the query at this point
* @param int $limit Maximum number of query results
*
* @return array with
* string 'ident' => Notification identifier
* int 'total' => Total number of available personal notifications
* array 'notifications' => Personal notifications
*/
public function personalNotifs($seen = 0, $start = 0, $limit = 80) {
$ident = 'personal';
$total = $this->personalTotal($seen);
$sql_extra = $this->_personal_sql_extra();
$notifs = array();
$sql_seen = "";
if($seen === 0)
$sql_seen = " AND `item`.`unseen` = 1 ";
$r = q("SELECT `item`.`id`,`item`.`parent`, `item`.`verb`, `item`.`author-name`, `item`.`unseen`,
`item`.`author-link`, `item`.`author-avatar`, `item`.`created`, `item`.`object` AS `object`,
`pitem`.`author-name` AS `pname`, `pitem`.`author-link` AS `plink`, `pitem`.`guid` AS `pguid`,
FROM `item` INNER JOIN `item` AS `pitem` ON `pitem`.`id`=`item`.`parent`
WHERE `item`.`visible` = 1
$sql_extra
$sql_seen
AND `item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 0
ORDER BY `item`.`created` DESC LIMIT %d, %d " ,
intval(local_user()),
intval($start),
intval($limit)
);
if(dbm::is_result($r))
$notifs = $this->formatNotifs($r, $ident);
$arr = array (
'notifications' => $notifs,
'ident' => $ident,
'total' => $total,
);
return $arr;
}
/**
* @brief Total number of home notifications
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @return int Number of home notifications
*/
private function homeTotal($seen = 0) {
$sql_seen = "";
if($seen === 0)
$sql_seen = " AND `item`.`unseen` = 1 ";
$r = q("SELECT COUNT(*) AS `total` FROM `item`
WHERE `item`.`visible` = 1 AND
`item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 1
$sql_seen",
intval(local_user())
);
if(dbm::is_result($r))
return $r[0]['total'];
return 0;
}
/**
* @brief Get home notifications
*
* @param int|string $seen
* If 0 only include notifications into the query
* which aren't marked as "seen"
* @param int $start Start the query at this point
* @param int $limit Maximum number of query results
*
* @return array with
* string 'ident' => Notification identifier
* int 'total' => Total number of available home notifications
* array 'notifications' => Home notifications
*/
public function homeNotifs($seen = 0, $start = 0, $limit = 80) {
$ident = 'home';
$total = $this->homeTotal($seen);
$notifs = array();
$sql_seen = "";
if($seen === 0)
$sql_seen = " AND `item`.`unseen` = 1 ";
$r = q("SELECT `item`.`id`,`item`.`parent`, `item`.`verb`, `item`.`author-name`, `item`.`unseen`,
`item`.`author-link`, `item`.`author-avatar`, `item`.`created`, `item`.`object` as `object`,
`pitem`.`author-name` as `pname`, `pitem`.`author-link` as `plink`, `pitem`.`guid` as `pguid`
FROM `item` INNER JOIN `item` as `pitem` ON `pitem`.`id`=`item`.`parent`
WHERE `item`.`visible` = 1 AND
`item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 1
$sql_seen
ORDER BY `item`.`created` DESC LIMIT %d, %d ",
intval(local_user()),
intval($start),
intval($limit)
);
if(dbm::is_result($r))
$notifs = $this->formatNotifs($r, $ident);
$arr = array (
'notifications' => $notifs,
'ident' => $ident,
'total' => $total,
);
return $arr;
}
/**
* @brief Total number of introductions
* @param bool $all
* If false only include introductions into the query
* which aren't marked as ignored
* @return int Number of introductions
*/
private function introTotal($all = false) {
$sql_extra = "";
if(!$all)
$sql_extra = " AND `ignore` = 0 ";
$r = q("SELECT COUNT(*) AS `total` FROM `intro`
WHERE `intro`.`uid` = %d $sql_extra AND `intro`.`blocked` = 0 ",
intval($_SESSION['uid'])
);
if(dbm::is_result($r))
return $r[0]['total'];
return 0;
}
/**
* @brief Get introductions
*
* @param bool $all
* If false only include introductions into the query
* which aren't marked as ignored
* @param int $start Start the query at this point
* @param int $limit Maximum number of query results
*
* @return array with
* string 'ident' => Notification identifier
* int 'total' => Total number of available introductions
* array 'notifications' => Introductions
*/
public function introNotifs($all = false, $start = 0, $limit = 80) {
$ident = 'introductions';
$total = $this->introTotal($seen);
$notifs = array();
$sql_extra = "";
if(!$all)
$sql_extra = " AND `ignore` = 0 ";
/// @todo Fetch contact details by "get_contact_details_by_url" instead of queries to contact, fcontact and gcontact
$r = q("SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*, `fcontact`.`name` AS `fname`,`fcontact`.`url` AS `furl`,`fcontact`.`photo` AS `fphoto`,`fcontact`.`request` AS `frequest`,
`gcontact`.`location` AS `glocation`, `gcontact`.`about` AS `gabout`,
`gcontact`.`keywords` AS `gkeywords`, `gcontact`.`gender` AS `ggender`,
`gcontact`.`network` AS `gnetwork`
FROM `intro`
LEFT JOIN `contact` ON `contact`.`id` = `intro`.`contact-id`
LEFT JOIN `gcontact` ON `gcontact`.`nurl` = `contact`.`nurl`
LEFT JOIN `fcontact` ON `intro`.`fid` = `fcontact`.`id`
WHERE `intro`.`uid` = %d $sql_extra AND `intro`.`blocked` = 0
LIMIT %d, %d",
intval($_SESSION['uid']),
intval($start),
intval($limit)
);
if(dbm::is_result($r))
$notifs = $this->formatIntros($r);
$arr = array (
'ident' => $ident,
'total' => $total,
'notifications' => $notifs,
);
return $arr;
}
/**
* @brief Format the notification query in an usable array
*
* @param array $intros The array from the db query
* @return array with the introductions
*/
private function formatIntros($intros) {
$knowyou = '';
foreach($intros as $it) {
// There are two kind of introduction. Contacts suggested by other contacts and normal connection requests.
// We have to distinguish between these two because they use different data.
// Contact suggestions
if($it['fid']) {
$return_addr = bin2hex($this->a->user['nickname'] . '@' . $this->a->get_hostname() . (($this->a->path) ? '/' . $this->a->path : ''));
$intro = array(
'label' => 'friend_suggestion',
'notify_type' => t('Friend Suggestion'),
'intro_id' => $it['intro_id'],
'madeby' => $it['name'],
'contact_id' => $it['contact-id'],
'photo' => ((x($it,'fphoto')) ? proxy_url($it['fphoto'], false, PROXY_SIZE_SMALL) : "images/person-175.jpg"),
'name' => $it['fname'],
'url' => zrl($it['furl']),
'hidden' => $it['hidden'] == 1,
'post_newfriend' => (intval(get_pconfig(local_user(),'system','post_newfriend')) ? '1' : 0),
'knowyou' => $knowyou,
'note' => $it['note'],
'request' => $it['frequest'] . '?addr=' . $return_addr,
);
// Normal connection requests
} else {
// Probe the contact url to get missing data
$ret = probe_url($it["url"]);
if ($it['gnetwork'] == "")
$it['gnetwork'] = $ret["network"];
// Don't show these data until you are connected. Diaspora is doing the same.
if($it['gnetwork'] === NETWORK_DIASPORA) {
$it['glocation'] = "";
$it['gabout'] = "";
$it['ggender'] = "";
}
$intro = array(
'label' => (($it['network'] !== NETWORK_OSTATUS) ? 'friend_request' : 'follower'),
'notify_type' => (($it['network'] !== NETWORK_OSTATUS) ? t('Friend/Connect Request') : t('New Follower')),
'dfrn_id' => $it['issued-id'],
'uid' => $_SESSION['uid'],
'intro_id' => $it['intro_id'],
'contact_id' => $it['contact-id'],
'photo' => ((x($it,'photo')) ? proxy_url($it['photo'], false, PROXY_SIZE_SMALL) : "images/person-175.jpg"),
'name' => $it['name'],
'location' => bbcode($it['glocation'], false, false),
'about' => bbcode($it['gabout'], false, false),
'keywords' => $it['gkeywords'],
'gender' => $it['ggender'],
'hidden' => $it['hidden'] == 1,
'post_newfriend' => (intval(get_pconfig(local_user(),'system','post_newfriend')) ? '1' : 0),
'url' => $it['url'],
'zrl' => zrl($it['url']),
'addr' => $ret['addr'],
'network' => $it['gnetwork'],
'knowyou' => $it['knowyou'],
'note' => $it['note'],
);
}
$arr[] = $intro;
}
return $arr;
}
}

File diff suppressed because it is too large Load diff

1139
include/Probe.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,335 +1,5 @@
<?php
require_once('library/HTML5/Parser.php');
require_once('include/crypto.php');
require_once('include/feed.php');
if(! function_exists('scrape_dfrn')) {
function scrape_dfrn($url, $dont_probe = false) {
$a = get_app();
$ret = array();
logger('scrape_dfrn: url=' . $url);
// Try to fetch the data from noscrape. This is faster than parsing the HTML
$noscrape = str_replace("/hcard/", "/noscrape/", $url);
$noscrapejson = fetch_url($noscrape);
$noscrapedata = array();
if ($noscrapejson) {
$noscrapedata = json_decode($noscrapejson, true);
if (is_array($noscrapedata)) {
if ($noscrapedata["nick"] != "")
return($noscrapedata);
else
unset($noscrapedata["nick"]);
} else
$noscrapedata = array();
}
$s = fetch_url($url);
if (!$s)
return $ret;
if (!$dont_probe) {
$probe = probe_url($url);
if (isset($probe["addr"]))
$ret["addr"] = $probe["addr"];
}
$headers = $a->get_curl_headers();
logger('scrape_dfrn: headers=' . $headers, LOGGER_DEBUG);
$lines = explode("\n",$headers);
if(count($lines)) {
foreach($lines as $line) {
// don't try and run feeds through the html5 parser
if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
return ret;
}
}
try {
$dom = HTML5_Parser::parse($s);
} catch (DOMException $e) {
logger('scrape_dfrn: parse error: ' . $e);
}
if(! $dom)
return $ret;
$items = $dom->getElementsByTagName('link');
// get DFRN link elements
foreach($items as $item) {
$x = $item->getAttribute('rel');
if(($x === 'alternate') && ($item->getAttribute('type') === 'application/atom+xml'))
$ret['feed_atom'] = $item->getAttribute('href');
if(substr($x,0,5) == "dfrn-") {
$ret[$x] = $item->getAttribute('href');
}
if($x === 'lrdd') {
$decoded = urldecode($item->getAttribute('href'));
if(preg_match('/acct:([^@]*)@/',$decoded,$matches))
$ret['nick'] = $matches[1];
}
}
// Pull out hCard profile elements
$largest_photo = 0;
$items = $dom->getElementsByTagName('*');
foreach($items as $item) {
if(attribute_contains($item->getAttribute('class'), 'vcard')) {
$level2 = $item->getElementsByTagName('*');
foreach($level2 as $x) {
if(attribute_contains($x->getAttribute('class'),'fn')) {
$ret['fn'] = $x->textContent;
}
if((attribute_contains($x->getAttribute('class'),'photo'))
|| (attribute_contains($x->getAttribute('class'),'avatar'))) {
$size = intval($x->getAttribute('width'));
// dfrn prefers 175, so if we find this, we set largest_size so it can't be topped.
if(($size > $largest_photo) || ($size == 175) || (! $largest_photo)) {
$ret['photo'] = $x->getAttribute('src');
$largest_photo = (($size == 175) ? 9999 : $size);
}
}
if(attribute_contains($x->getAttribute('class'),'key')) {
$ret['key'] = $x->textContent;
}
}
}
}
return array_merge($ret, $noscrapedata);
}}
if(! function_exists('validate_dfrn')) {
function validate_dfrn($a) {
$errors = 0;
if(! x($a,'key'))
$errors ++;
if(! x($a,'dfrn-request'))
$errors ++;
if(! x($a,'dfrn-confirm'))
$errors ++;
if(! x($a,'dfrn-notify'))
$errors ++;
if(! x($a,'dfrn-poll'))
$errors ++;
return $errors;
}}
if(! function_exists('scrape_meta')) {
function scrape_meta($url) {
$a = get_app();
$ret = array();
logger('scrape_meta: url=' . $url);
$s = fetch_url($url);
if(! $s)
return $ret;
$headers = $a->get_curl_headers();
logger('scrape_meta: headers=' . $headers, LOGGER_DEBUG);
$lines = explode("\n",$headers);
if(count($lines)) {
foreach($lines as $line) {
// don't try and run feeds through the html5 parser
if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
return ret;
}
}
try {
$dom = HTML5_Parser::parse($s);
} catch (DOMException $e) {
logger('scrape_meta: parse error: ' . $e);
}
if(! $dom)
return $ret;
$items = $dom->getElementsByTagName('meta');
// get DFRN link elements
foreach($items as $item) {
$x = $item->getAttribute('name');
if(substr($x,0,5) == "dfrn-")
$ret[$x] = $item->getAttribute('content');
}
return $ret;
}}
if(! function_exists('scrape_vcard')) {
function scrape_vcard($url) {
$a = get_app();
$ret = array();
logger('scrape_vcard: url=' . $url);
$s = fetch_url($url);
if(! $s)
return $ret;
$headers = $a->get_curl_headers();
$lines = explode("\n",$headers);
if(count($lines)) {
foreach($lines as $line) {
// don't try and run feeds through the html5 parser
if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
return ret;
}
}
try {
$dom = HTML5_Parser::parse($s);
} catch (DOMException $e) {
logger('scrape_vcard: parse error: ' . $e);
}
if(! $dom)
return $ret;
// Pull out hCard profile elements
$largest_photo = 0;
$items = $dom->getElementsByTagName('*');
foreach($items as $item) {
if(attribute_contains($item->getAttribute('class'), 'vcard')) {
$level2 = $item->getElementsByTagName('*');
foreach($level2 as $x) {
if(attribute_contains($x->getAttribute('class'),'fn'))
$ret['fn'] = $x->textContent;
if((attribute_contains($x->getAttribute('class'),'photo'))
|| (attribute_contains($x->getAttribute('class'),'avatar'))) {
$size = intval($x->getAttribute('width'));
if(($size > $largest_photo) || (! $largest_photo)) {
$ret['photo'] = $x->getAttribute('src');
$largest_photo = $size;
}
}
if((attribute_contains($x->getAttribute('class'),'nickname'))
|| (attribute_contains($x->getAttribute('class'),'uid'))) {
$ret['nick'] = $x->textContent;
}
}
}
}
return $ret;
}}
if(! function_exists('scrape_feed')) {
function scrape_feed($url) {
$a = get_app();
$ret = array();
$cookiejar = tempnam(get_temppath(), 'cookiejar-scrape-feed-');
$s = fetch_url($url, false, $redirects, 0, Null, $cookiejar);
unlink($cookiejar);
$headers = $a->get_curl_headers();
$code = $a->get_curl_code();
logger('scrape_feed: returns: ' . $code . ' headers=' . $headers, LOGGER_DEBUG);
if(! $s) {
logger('scrape_feed: no data returned for ' . $url);
return $ret;
}
$lines = explode("\n",$headers);
if(count($lines)) {
foreach($lines as $line) {
if(stristr($line,'content-type:')) {
if(stristr($line,'application/atom+xml') || stristr($s,'<feed')) {
$ret['feed_atom'] = $url;
return $ret;
}
if(stristr($line,'application/rss+xml') || stristr($s,'<rss')) {
$ret['feed_rss'] = $url;
return $ret;
}
}
}
// perhaps an RSS version 1 feed with a generic or incorrect content-type?
if(stristr($s,'</item>')) {
$ret['feed_rss'] = $url;
return $ret;
}
}
$basename = implode('/', array_slice(explode('/',$url),0,3)) . '/';
$doc = new DOMDocument();
@$doc->loadHTML($s);
$xpath = new DomXPath($doc);
$base = $xpath->query("//base");
foreach ($base as $node) {
$attr = array();
if ($node->attributes->length)
foreach ($node->attributes as $attribute)
$attr[$attribute->name] = $attribute->value;
if ($attr["href"] != "")
$basename = $attr["href"] ;
}
$list = $xpath->query("//link");
foreach ($list as $node) {
$attr = array();
if ($node->attributes->length)
foreach ($node->attributes as $attribute)
$attr[$attribute->name] = $attribute->value;
if (($attr["rel"] == "alternate") AND ($attr["type"] == "application/atom+xml"))
$ret["feed_atom"] = $attr["href"];
if (($attr["rel"] == "alternate") AND ($attr["type"] == "application/rss+xml"))
$ret["feed_rss"] = $attr["href"];
}
// Drupal and perhaps others only provide relative URLs. Turn them into absolute.
if(x($ret,'feed_atom') && (! strstr($ret['feed_atom'],'://')))
$ret['feed_atom'] = $basename . $ret['feed_atom'];
if(x($ret,'feed_rss') && (! strstr($ret['feed_rss'],'://')))
$ret['feed_rss'] = $basename . $ret['feed_rss'];
return $ret;
}}
require_once('include/Probe.php');
/**
*
@ -349,594 +19,17 @@ function scrape_feed($url) {
*
*/
define ( 'PROBE_NORMAL', 0);
define ( 'PROBE_DIASPORA', 1);
define('PROBE_NORMAL', 0);
define('PROBE_DIASPORA', 1);
function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
require_once('include/email.php');
$result = array();
if ($mode == PROBE_DIASPORA)
$network = NETWORK_DIASPORA;
else
$network = "";
if (!$url)
return $result;
$data = Probe::uri($url, $network);
$result = Cache::get("probe_url:".$mode.":".$url);
if (!is_null($result)) {
$result = unserialize($result);
return $result;
}
$original_url = $url;
$network = null;
$diaspora = false;
$diaspora_base = '';
$diaspora_guid = '';
$diaspora_key = '';
$has_lrdd = false;
$email_conversant = false;
$connectornetworks = false;
$appnet = false;
if (strpos($url,'twitter.com')) {
$connectornetworks = true;
$network = NETWORK_TWITTER;
}
$lastfm = ((strpos($url,'last.fm/user') !== false) ? true : false);
$at_addr = ((strpos($url,'@') !== false) ? true : false);
if((!$appnet) && (!$lastfm) && !$connectornetworks) {
if(strpos($url,'mailto:') !== false && $at_addr) {
$url = str_replace('mailto:','',$url);
$links = array();
}
else
$links = lrdd($url);
if ((count($links) == 0) AND strstr($url, "/index.php")) {
$url = str_replace("/index.php", "", $url);
$links = lrdd($url);
}
if (count($links)) {
$has_lrdd = true;
logger('probe_url: found lrdd links: ' . print_r($links,true), LOGGER_DATA);
foreach($links as $link) {
if($link['@attributes']['rel'] === NAMESPACE_ZOT)
$zot = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === NAMESPACE_DFRN)
$dfrn = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'salmon')
$notify = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === NAMESPACE_FEED)
$poll = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
$hcard = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
$profile = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0')
$poco = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') {
$diaspora_base = unamp($link['@attributes']['href']);
$diaspora = true;
}
if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') {
$diaspora_guid = unamp($link['@attributes']['href']);
$diaspora = true;
}
if($link['@attributes']['rel'] === 'diaspora-public-key') {
$diaspora_key = base64_decode(unamp($link['@attributes']['href']));
if(strstr($diaspora_key,'RSA '))
$pubkey = rsatopem($diaspora_key);
else
$pubkey = $diaspora_key;
$diaspora = true;
}
if(($link['@attributes']['rel'] === 'http://ostatus.org/schema/1.0/subscribe') AND ($mode == PROBE_NORMAL)) {
$diaspora = false;
}
}
// Status.Net can have more than one profile URL. We need to match the profile URL
// to a contact on incoming messages to prevent spam, and we won't know which one
// to match. So in case of two, one of them is stored as an alias. Only store URL's
// and not webfinger user@host aliases. If they've got more than two non-email style
// aliases, let's hope we're lucky and get one that matches the feed author-uri because
// otherwise we're screwed.
$backup_alias = "";
foreach($links as $link) {
if($link['@attributes']['rel'] === 'alias') {
if(strpos($link['@attributes']['href'],'@') === false) {
if(isset($profile)) {
$alias_url = $link['@attributes']['href'];
if(($alias_url !== $profile) AND ($backup_alias == "") AND
($alias_url !== str_replace("/index.php", "", $profile)))
$backup_alias = $alias_url;
if(($alias_url !== $profile) AND !strstr($alias_url, "index.php") AND
($alias_url !== str_replace("/index.php", "", $profile)))
$alias = $alias_url;
}
else
$profile = unamp($link['@attributes']['href']);
}
}
}
if ($alias == "")
$alias = $backup_alias;
// If the profile is different from the url then the url is abviously an alias
if (($alias == "") AND ($profile != "") AND !$at_addr AND (normalise_link($profile) != normalise_link($url)))
$alias = $url;
}
elseif($mode == PROBE_NORMAL) {
// Check email
$orig_url = $url;
if((strpos($orig_url,'@')) && validate_email($orig_url)) {
$x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1",
intval(local_user())
);
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
intval(local_user())
);
if(count($x) && count($r)) {
$mailbox = construct_mailbox_name($r[0]);
$password = '';
openssl_private_decrypt(hex2bin($r[0]['pass']),$password,$x[0]['prvkey']);
$mbox = email_connect($mailbox,$r[0]['user'],$password);
if(! $mbox)
logger('probe_url: email_connect failed.');
unset($password);
}
if($mbox) {
$msgs = email_poll($mbox,$orig_url);
logger('probe_url: searching ' . $orig_url . ', ' . count($msgs) . ' messages found.', LOGGER_DEBUG);
if(count($msgs)) {
$addr = $orig_url;
$network = NETWORK_MAIL;
$name = substr($url,0,strpos($url,'@'));
$phost = substr($url,strpos($url,'@')+1);
$profile = 'http://' . $phost;
// fix nick character range
$vcard = array('fn' => $name, 'nick' => $name, 'photo' => avatar_img($url));
$notify = 'smtp ' . random_string();
$poll = 'email ' . random_string();
$priority = 0;
$x = email_msg_meta($mbox,$msgs[0]);
if(stristr($x[0]->from,$orig_url))
$adr = imap_rfc822_parse_adrlist($x[0]->from,'');
elseif(stristr($x[0]->to,$orig_url))
$adr = imap_rfc822_parse_adrlist($x[0]->to,'');
if(isset($adr)) {
foreach($adr as $feadr) {
if((strcasecmp($feadr->mailbox,$name) == 0)
&&(strcasecmp($feadr->host,$phost) == 0)
&& (strlen($feadr->personal))) {
$personal = imap_mime_header_decode($feadr->personal);
$vcard['fn'] = "";
foreach($personal as $perspart)
if ($perspart->charset != "default")
$vcard['fn'] .= iconv($perspart->charset, 'UTF-8//IGNORE', $perspart->text);
else
$vcard['fn'] .= $perspart->text;
$vcard['fn'] = notags($vcard['fn']);
}
}
}
}
imap_close($mbox);
}
}
}
}
if($mode == PROBE_NORMAL) {
if(strlen($zot)) {
$s = fetch_url($zot);
if($s) {
$j = json_decode($s);
if($j) {
$network = NETWORK_ZOT;
$vcard = array(
'fn' => $j->fullname,
'nick' => $j->nickname,
'photo' => $j->photo
);
$profile = $j->url;
$notify = $j->post;
$pubkey = $j->pubkey;
$poll = 'N/A';
}
}
}
if(strlen($dfrn)) {
$ret = scrape_dfrn(($hcard) ? $hcard : $dfrn, true);
if(is_array($ret) && x($ret,'dfrn-request')) {
$network = NETWORK_DFRN;
$request = $ret['dfrn-request'];
$confirm = $ret['dfrn-confirm'];
$notify = $ret['dfrn-notify'];
$poll = $ret['dfrn-poll'];
$vcard = array();
$vcard['fn'] = $ret['fn'];
$vcard['nick'] = $ret['nick'];
$vcard['photo'] = $ret['photo'];
}
}
}
// Scrape the public key from the hcard.
// Diaspora will remove it from the webfinger somewhere in the future.
if (($hcard != "") AND ($pubkey == "")) {
$ret = scrape_dfrn(($hcard) ? $hcard : $dfrn, true);
if (isset($ret["key"])) {
$hcard_key = $ret["key"];
if(strstr($hcard_key,'RSA '))
$pubkey = rsatopem($hcard_key);
else
$pubkey = $hcard_key;
}
}
if($diaspora && $diaspora_base && $diaspora_guid) {
$diaspora_notify = $diaspora_base.'receive/users/'.$diaspora_guid;
if($mode == PROBE_DIASPORA || !$notify || ($notify == $diaspora_notify)) {
$notify = $diaspora_notify;
$batch = $diaspora_base . 'receive/public' ;
}
if(strpos($url,'@'))
$addr = str_replace('acct:', '', $url);
}
if($network !== NETWORK_ZOT && $network !== NETWORK_DFRN && $network !== NETWORK_MAIL) {
if($diaspora)
$network = NETWORK_DIASPORA;
elseif($has_lrdd AND ($notify))
$network = NETWORK_OSTATUS;
if(strpos($url,'@'))
$addr = str_replace('acct:', '', $url);
$priority = 0;
if($hcard && ! $vcard) {
$vcard = scrape_vcard($hcard);
// Google doesn't use absolute url in profile photos
if((x($vcard,'photo')) && substr($vcard['photo'],0,1) == '/') {
$h = @parse_url($hcard);
if($h)
$vcard['photo'] = $h['scheme'] . '://' . $h['host'] . $vcard['photo'];
}
logger('probe_url: scrape_vcard: ' . print_r($vcard,true), LOGGER_DATA);
}
if($diaspora && $addr) {
// Diaspora returns the name as the nick. As the nick will never be updated,
// let's use the Diaspora nickname (the first part of the handle) as the nick instead
$addr_parts = explode('@', $addr);
$vcard['nick'] = $addr_parts[0];
}
if($lastfm) {
$profile = $url;
$poll = str_replace(array('www.','last.fm/'),array('','ws.audioscrobbler.com/1.0/'),$url) . '/recenttracks.rss';
$vcard['nick'] = basename($url);
$vcard['fn'] = $vcard['nick'] . t(' on Last.fm');
$network = NETWORK_FEED;
}
if(! x($vcard,'fn'))
if(x($vcard,'nick'))
$vcard['fn'] = $vcard['nick'];
$check_feed = false;
if(stristr($url,'tumblr.com') && (! stristr($url,'/rss'))) {
$poll = $url . '/rss';
$check_feed = true;
// Will leave it to others to figure out how to grab the avatar, which is on the $url page in the open graph meta links
}
if($appnet || ! $poll)
$check_feed = true;
if((! isset($vcard)) || (! x($vcard,'fn')) || (! $profile))
$check_feed = true;
if(($at_addr) && (! count($links)))
$check_feed = false;
if ($connectornetworks)
$check_feed = false;
if($check_feed) {
$feedret = scrape_feed(($poll) ? $poll : $url);
logger('probe_url: scrape_feed ' . (($poll)? $poll : $url) . ' returns: ' . print_r($feedret,true), LOGGER_DATA);
if(count($feedret) && ($feedret['feed_atom'] || $feedret['feed_rss'])) {
$poll = ((x($feedret,'feed_atom')) ? unamp($feedret['feed_atom']) : unamp($feedret['feed_rss']));
if(! x($vcard))
$vcard = array();
}
if(x($feedret,'photo') && (! x($vcard,'photo')))
$vcard['photo'] = $feedret['photo'];
$cookiejar = tempnam(get_temppath(), 'cookiejar-scrape-feed-');
$xml = fetch_url($poll, false, $redirects, 0, Null, $cookiejar);
unlink($cookiejar);
logger('probe_url: fetch feed: ' . $poll . ' returns: ' . $xml, LOGGER_DATA);
if ($xml == "") {
logger("scrape_feed: XML is empty for feed ".$poll);
$network = NETWORK_PHANTOM;
} else {
$data = feed_import($xml,$dummy1,$dummy2, $dummy3, true);
if (!is_array($data)) {
logger("scrape_feed: This doesn't seem to be a feed: ".$poll);
$network = NETWORK_PHANTOM;
} else {
if (($vcard["photo"] == "") AND ($data["header"]["author-avatar"] != ""))
$vcard["photo"] = $data["header"]["author-avatar"];
if (($vcard["fn"] == "") AND ($data["header"]["author-name"] != ""))
$vcard["fn"] = $data["header"]["author-name"];
if (($vcard["nick"] == "") AND ($data["header"]["author-nick"] != ""))
$vcard["nick"] = $data["header"]["author-nick"];
if ($network == NETWORK_OSTATUS) {
if ($data["header"]["author-id"] != "")
$alias = $data["header"]["author-id"];
if ($data["header"]["author-link"] != "")
$profile = $data["header"]["author-link"];
} elseif(!$profile AND ($data["header"]["author-link"] != "") AND !in_array($network, array("", NETWORK_FEED)))
$profile = $data["header"]["author-link"];
}
}
// Workaround for misconfigured Friendica servers
if (($network == "") AND (strstr($url, "/profile/"))) {
$noscrape = str_replace("/profile/", "/noscrape/", $url);
$noscrapejson = fetch_url($noscrape);
if ($noscrapejson) {
$network = NETWORK_DFRN;
$poco = str_replace("/profile/", "/poco/", $url);
$noscrapedata = json_decode($noscrapejson, true);
if (isset($noscrapedata["addr"]))
$addr = $noscrapedata["addr"];
if (isset($noscrapedata["fn"]))
$vcard["fn"] = $noscrapedata["fn"];
if (isset($noscrapedata["key"]))
$pubkey = $noscrapedata["key"];
if (isset($noscrapedata["photo"]))
$vcard["photo"] = $noscrapedata["photo"];
if (isset($noscrapedata["dfrn-request"]))
$request = $noscrapedata["dfrn-request"];
if (isset($noscrapedata["dfrn-confirm"]))
$confirm = $noscrapedata["dfrn-confirm"];
if (isset($noscrapedata["dfrn-notify"]))
$notify = $noscrapedata["dfrn-notify"];
if (isset($noscrapedata["dfrn-poll"]))
$poll = $noscrapedata["dfrn-poll"];
}
}
if(! $network)
$network = NETWORK_FEED;
if(! x($vcard,'nick')) {
$vcard['nick'] = strtolower(notags(unxmlify($vcard['fn'])));
if(strpos($vcard['nick'],' '))
$vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
}
if(! $priority)
$priority = 2;
}
}
if(! x($vcard,'photo')) {
$a = get_app();
$vcard['photo'] = App::get_baseurl() . '/images/person-175.jpg' ;
}
if(! $profile)
$profile = $url;
// No human could be associated with this link, use the URL as the contact name
if(($network === NETWORK_FEED) && ($poll) && (! x($vcard,'fn')))
$vcard['fn'] = $url;
if (($notify != "") AND ($poll != "")) {
$baseurl = matching_url(normalise_link($notify), normalise_link($poll));
$baseurl2 = matching_url($baseurl, normalise_link($profile));
if ($baseurl2 != "")
$baseurl = $baseurl2;
}
if (($baseurl == "") AND ($notify != ""))
$baseurl = matching_url(normalise_link($profile), normalise_link($notify));
if (($baseurl == "") AND ($poll != ""))
$baseurl = matching_url(normalise_link($profile), normalise_link($poll));
if (substr($baseurl, -10) == "/index.php")
$baseurl = str_replace("/index.php", "", $baseurl);
if ($network == "")
$network = NETWORK_PHANTOM;
$baseurl = rtrim($baseurl, "/");
if(strpos($url,'@') AND ($addr == "") AND ($network == NETWORK_DFRN))
$addr = str_replace('acct:', '', $url);
$vcard['fn'] = notags($vcard['fn']);
$vcard['nick'] = str_replace(' ','',notags($vcard['nick']));
$result['name'] = $vcard['fn'];
$result['nick'] = $vcard['nick'];
$result['url'] = $profile;
$result['addr'] = $addr;
$result['batch'] = $batch;
$result['notify'] = $notify;
$result['poll'] = $poll;
$result['request'] = $request;
$result['confirm'] = $confirm;
$result['poco'] = $poco;
$result['photo'] = $vcard['photo'];
$result['priority'] = $priority;
$result['network'] = $network;
$result['alias'] = $alias;
$result['pubkey'] = $pubkey;
$result['baseurl'] = $baseurl;
logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG);
if ($level == 1) {
// Trying if it maybe a diaspora account
if (($result['network'] == NETWORK_FEED) OR ($result['addr'] == "")) {
require_once('include/bbcode.php');
$address = GetProfileUsername($url, "", true);
$result2 = probe_url($address, $mode, ++$level);
if (!in_array($result2['network'], array("", NETWORK_PHANTOM, NETWORK_FEED)))
$result = $result2;
}
// Maybe it's some non standard GNU Social installation (Single user, subfolder or no uri rewrite)
if (($result['network'] == NETWORK_FEED) AND ($result['baseurl'] != "") AND ($result['nick'] != "")) {
$addr = $result['nick'].'@'.str_replace("http://", "", $result['baseurl']);
$result2 = probe_url($addr, $mode, ++$level);
if (!in_array($result2['network'], array("", NETWORK_PHANTOM, NETWORK_FEED)))
$result = $result2;
}
// Quickfix for Hubzilla systems with enabled OStatus plugin
if (($result['network'] == NETWORK_DIASPORA) AND ($result["batch"] == "")) {
$result2 = probe_url($url, PROBE_DIASPORA, ++$level);
if ($result2['network'] == NETWORK_DIASPORA) {
$addr = $result["addr"];
$result = $result2;
if (($result["addr"] == "") AND ($addr != ""))
$result["addr"] = $addr;
}
}
}
// Only store into the cache if the value seems to be valid
if ($result['network'] != NETWORK_PHANTOM) {
Cache::set("probe_url:".$mode.":".$original_url,serialize($result), CACHE_DAY);
/// @todo temporary fix - we need a real contact update function that updates only changing fields
/// The biggest problem is the avatar picture that could have a reduced image size.
/// It should only be updated if the existing picture isn't existing anymore.
if (($result['network'] != NETWORK_FEED) AND ($mode == PROBE_NORMAL) AND
$result["name"] AND $result["nick"] AND $result["url"] AND $result["addr"] AND $result["poll"])
q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `url` = '%s', `addr` = '%s',
`notify` = '%s', `poll` = '%s', `alias` = '%s', `success_update` = '%s'
WHERE `nurl` = '%s' AND NOT `self` AND `uid` = 0",
dbesc($result["name"]),
dbesc($result["nick"]),
dbesc($result["url"]),
dbesc($result["addr"]),
dbesc($result["notify"]),
dbesc($result["poll"]),
dbesc($result["alias"]),
dbesc(datetime_convert()),
dbesc(normalise_link($result['url']))
);
}
return $result;
}
/**
* @brief Find the matching part between two url
*
* @param string $url1
* @param string $url2
* @return string The matching part
*/
function matching_url($url1, $url2) {
if (($url1 == "") OR ($url2 == ""))
return "";
$url1 = normalise_link($url1);
$url2 = normalise_link($url2);
$parts1 = parse_url($url1);
$parts2 = parse_url($url2);
if (!isset($parts1["host"]) OR !isset($parts2["host"]))
return "";
if ($parts1["scheme"] != $parts2["scheme"])
return "";
if ($parts1["host"] != $parts2["host"])
return "";
if ($parts1["port"] != $parts2["port"])
return "";
$match = $parts1["scheme"]."://".$parts1["host"];
if ($parts1["port"])
$match .= ":".$parts1["port"];
$pathparts1 = explode("/", $parts1["path"]);
$pathparts2 = explode("/", $parts2["path"]);
$i = 0;
$path = "";
do {
$path1 = $pathparts1[$i];
$path2 = $pathparts2[$i];
if ($path1 == $path2)
$path .= $path1."/";
} while (($path1 == $path2) AND ($i++ <= count($pathparts1)));
$match .= $path;
return normalise_link($match);
return $data;
}

View file

@ -399,7 +399,7 @@ function acl_lookup(&$a, $out_type = 'json') {
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
$search = (x($_REQUEST,'search') ? $_REQUEST['search'] : "");
$type = (x($_REQUEST,'type') ? $_REQUEST['type'] : "");
$mode = (x($_REQUEST,'mode') ? $_REQUEST['mode'] : "");
$mode = (x($_REQUEST,'smode') ? $_REQUEST['smode'] : "");
$conv_id = (x($_REQUEST,'conversation') ? $_REQUEST['conversation'] : null);
// For use with jquery.textcomplete for private mail completion
@ -481,11 +481,11 @@ function acl_lookup(&$a, $out_type = 'json') {
if ($type=='' || $type=='g'){
$r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
FROM `group`,`group_member`
WHERE `group`.`deleted` = 0 AND `group`.`uid` = %d
AND `group_member`.`gid`=`group`.`id`
FROM `group`
INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id` AND `group_member`.`uid` = `group`.`uid`
WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
$sql_extra
GROUP BY `group`.`id`
GROUP BY `group`.`name`
ORDER BY `group`.`name`
LIMIT %d,%d",
intval(local_user()),
@ -690,7 +690,7 @@ function navbar_complete(&$a) {
$localsearch = get_config('system','poco_local_search');
$search = $prefix.notags(trim($_REQUEST['search']));
$mode = $_REQUEST['mode'];
$mode = $_REQUEST['smode'];
// don't search if search term has less than 2 characters
if(! $search || mb_strlen($search) < 2)

File diff suppressed because it is too large Load diff

View file

@ -47,11 +47,10 @@ require_once("boot.php");
global $a, $db;
if(is_null($a)) {
if (is_null($a))
$a = new App;
}
if(is_null($db)) {
if (is_null($db)) {
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
@ -66,162 +65,261 @@ $bDebug = get_config('jabber','debug');
$oAuth = new exAuth($sLogFile, $bDebug);
class exAuth
{
class exAuth {
private $sLogFile;
private $bDebug;
private $rLogFile;
public function __construct($sLogFile, $bDebug)
{
/**
* @brief Create the class and do the authentification studd
*
* @param string $sLogFile The logfile name
* @param boolean $bDebug Debug mode
*/
public function __construct($sLogFile, $bDebug) {
global $db;
// setter
$this->sLogFile = $sLogFile;
$this->bDebug = $bDebug;
// ovo ne provjeravamo jer ako ne mozes kreirati log file, onda si u kvascu :)
// Open the logfile if the logfile name is defined
if ($this->sLogFile != '')
$this->rLogFile = fopen($this->sLogFile, "a") or die("Error opening log file: ". $this->sLogFile);
$this->writeLog("[exAuth] start");
// ovdje bi trebali biti spojeni na MySQL, imati otvoren log i zavrtit cekalicu
// We are connected to the SQL server and are having a log file.
do {
$iHeader = fgets(STDIN, 3);
$aLength = unpack("n", $iHeader);
$iLength = $aLength["1"];
if($iLength > 0) {
// ovo znaci da smo nesto dobili
$sData = fgets(STDIN, $iLength + 1);
$this->writeDebugLog("[debug] received data: ". $sData);
$aCommand = explode(":", $sData);
if (is_array($aCommand)){
switch ($aCommand[0]){
case "isuser":
// provjeravamo je li korisnik dobar
if (!isset($aCommand[1])){
$this->writeLog("[exAuth] invalid isuser command, no username given");
fwrite(STDOUT, pack("nn", 2, 0));
} else {
// ovdje provjeri je li korisnik OK
$sUser = str_replace(array("%20", "(a)"), array(" ", "@"), $aCommand[1]);
$this->writeDebugLog("[debug] checking isuser for ". $sUser);
$sQuery = "SELECT `uid` FROM `user` WHERE `nickname`='". $db->escape($sUser) ."'";
$this->writeDebugLog("[debug] using query ". $sQuery);
if ($oResult = q($sQuery)){
if ($oResult) {
// korisnik OK
$this->writeLog("[exAuth] valid user: ". $sUser);
fwrite(STDOUT, pack("nn", 2, 1));
} else {
// korisnik nije OK
$this->writeLog("[exAuth] invalid user: ". $sUser);
fwrite(STDOUT, pack("nn", 2, 0));
}
//$oResult->close();
} else {
$this->writeLog("[MySQL] invalid query: ". $sQuery);
fwrite(STDOUT, pack("nn", 2, 0));
}
}
break;
case "auth":
// provjeravamo autentifikaciju korisnika
if (sizeof($aCommand) != 4){
$this->writeLog("[exAuth] invalid auth command, data missing");
fwrite(STDOUT, pack("nn", 2, 0));
} else {
// ovdje provjeri prijavu
$sUser = str_replace(array("%20", "(a)"), array(" ", "@"), $aCommand[1]);
$this->writeDebugLog("[debug] doing auth for ". $sUser);
//$sQuery = "SELECT `uid`, `password` FROM `user` WHERE `password`='".hash('whirlpool',$aCommand[3])."' AND `nickname`='". $db->escape($sUser) ."'";
$sQuery = "SELECT `uid`, `password` FROM `user` WHERE `nickname`='". $db->escape($sUser) ."'";
$this->writeDebugLog("[debug] using query ". $sQuery);
if ($oResult = q($sQuery)){
$uid = $oResult[0]["uid"];
$Error = ($oResult[0]["password"] != hash('whirlpool',$aCommand[3]));
/*
if ($oResult[0]["password"] == hash('whirlpool',$aCommand[3])) {
// korisnik OK
$this->writeLog("[exAuth] authentificated user ". $sUser ."@". $aCommand[2]);
fwrite(STDOUT, pack("nn", 2, 1));
} else {
// korisnik nije OK
$this->writeLog("[exAuth] authentification failed for user ". $sUser ."@". $aCommand[2]);
fwrite(STDOUT, pack("nn", 2, 0));
}
$oResult->close();
*/
} else {
$this->writeLog("[MySQL] invalid query: ". $sQuery);
$Error = true;
$uid = -1;
}
if ($Error) {
$oConfig = q("SELECT `v` FROM `pconfig` WHERE `uid`=%d AND `cat` = 'xmpp' AND `k`='password' LIMIT 1;", intval($uid));
$this->writeLog("[exAuth] got password ".$oConfig[0]["v"]);
$Error = ($aCommand[3] != $oConfig[0]["v"]);
}
if ($Error) {
$this->writeLog("[exAuth] authentification failed for user ". $sUser ."@". $aCommand[2]);
fwrite(STDOUT, pack("nn", 2, 0));
} else {
$this->writeLog("[exAuth] authentificated user ". $sUser ."@". $aCommand[2]);
fwrite(STDOUT, pack("nn", 2, 1));
}
}
break;
case "setpass":
// postavljanje zaporke, onemoguceno
$this->writeLog("[exAuth] setpass command disabled");
fwrite(STDOUT, pack("nn", 2, 0));
break;
default:
// ako je uhvaceno ista drugo
$this->writeLog("[exAuth] unknown command ". $aCommand[0]);
fwrite(STDOUT, pack("nn", 2, 0));
break;
}
} else {
$this->writeDebugLog("[debug] invalid command string");
fwrite(STDOUT, pack("nn", 2, 0));
}
// Quit if the database connection went down
if (!$db->connected()) {
$this->writeDebugLog("[debug] the database connection went down");
return;
}
$iHeader = fgets(STDIN, 3);
$aLength = unpack("n", $iHeader);
$iLength = $aLength["1"];
// No data? Then quit
if ($iLength == 0) {
$this->writeDebugLog("[debug] we got no data");
return;
}
// Fetching the data
$sData = fgets(STDIN, $iLength + 1);
$this->writeDebugLog("[debug] received data: ". $sData);
$aCommand = explode(":", $sData);
if (is_array($aCommand)) {
switch ($aCommand[0]) {
case "isuser":
// Check the existance of a given username
$this->isuser($aCommand);
break;
case "auth":
// Check if the givven password is correct
$this->auth($aCommand);
break;
case "setpass":
// We don't accept the setting of passwords here
$this->writeLog("[exAuth] setpass command disabled");
fwrite(STDOUT, pack("nn", 2, 0));
break;
default:
// We don't know the given command
$this->writeLog("[exAuth] unknown command ". $aCommand[0]);
fwrite(STDOUT, pack("nn", 2, 0));
break;
}
} else {
$this->writeDebugLog("[debug] invalid command string");
fwrite(STDOUT, pack("nn", 2, 0));
}
unset ($iHeader);
unset ($aLength);
unset ($iLength);
unset($aCommand);
} while (true);
}
public function __destruct()
{
// zatvori log file
/**
* @brief Check if the given username exists
*
* @param array $aCommand The command array
*/
private function isuser($aCommand) {
global $a;
// Check if there is a username
if (!isset($aCommand[1])) {
$this->writeLog("[exAuth] invalid isuser command, no username given");
fwrite(STDOUT, pack("nn", 2, 0));
return;
}
// Now we check if the given user is valid
$sUser = str_replace(array("%20", "(a)"), array(" ", "@"), $aCommand[1]);
$this->writeDebugLog("[debug] checking isuser for ". $sUser."@".$aCommand[2]);
// If the hostnames doesn't match, we try to check remotely
if ($a->get_hostname() != $aCommand[2])
$found = $this->check_user($aCommand[2], $aCommand[1], true);
else {
$sQuery = "SELECT `uid` FROM `user` WHERE `nickname`='".dbesc($sUser)."'";
$this->writeDebugLog("[debug] using query ". $sQuery);
$r = q($sQuery);
$found = dbm::is_result($r);
}
if ($found) {
// The user is okay
$this->writeLog("[exAuth] valid user: ". $sUser);
fwrite(STDOUT, pack("nn", 2, 1));
} else {
// The user isn't okay
$this->writeLog("[exAuth] invalid user: ". $sUser);
fwrite(STDOUT, pack("nn", 2, 0));
}
}
/**
* @brief Check remote user existance via HTTP(S)
*
* @param string $host The hostname
* @param string $user Username
* @param boolean $ssl Should the check be done via SSL?
*
* @return boolean Was the user found?
*/
private function check_user($host, $user, $ssl) {
$url = ($ssl ? "https":"http")."://".$host."/noscrape/".$user;
$data = z_fetch_url($url);
if (!is_array($data))
return(false);
if ($data["return_code"] != "200")
return(false);
$json = @json_decode($data["body"]);
if (!is_object($json))
return(false);
return($json->nick == $user);
}
/**
* @brief Authenticate the givven user and password
*
* @param array $aCommand The command array
*/
private function auth($aCommand) {
global $a;
// check user authentication
if (sizeof($aCommand) != 4) {
$this->writeLog("[exAuth] invalid auth command, data missing");
fwrite(STDOUT, pack("nn", 2, 0));
return;
}
// We now check if the password match
$sUser = str_replace(array("%20", "(a)"), array(" ", "@"), $aCommand[1]);
$this->writeDebugLog("[debug] doing auth for ".$sUser."@".$aCommand[2]);
// If the hostnames doesn't match, we try to authenticate remotely
if ($a->get_hostname() != $aCommand[2])
$Error = !$this->check_credentials($aCommand[2], $aCommand[1], $aCommand[3], true);
else {
$sQuery = "SELECT `uid`, `password` FROM `user` WHERE `nickname`='".dbesc($sUser)."'";
$this->writeDebugLog("[debug] using query ". $sQuery);
if ($oResult = q($sQuery)) {
$uid = $oResult[0]["uid"];
$Error = ($oResult[0]["password"] != hash('whirlpool',$aCommand[3]));
} else {
$this->writeLog("[MySQL] invalid query: ". $sQuery);
$Error = true;
$uid = -1;
}
if ($Error) {
$oConfig = q("SELECT `v` FROM `pconfig` WHERE `uid` = %d AND `cat` = 'xmpp' AND `k`='password' LIMIT 1;", intval($uid));
$this->writeLog("[exAuth] got password ".$oConfig[0]["v"]);
$Error = ($aCommand[3] != $oConfig[0]["v"]);
}
}
if ($Error) {
$this->writeLog("[exAuth] authentification failed for user ".$sUser."@". $aCommand[2]);
fwrite(STDOUT, pack("nn", 2, 0));
} else {
$this->writeLog("[exAuth] authentificated user ".$sUser."@".$aCommand[2]);
fwrite(STDOUT, pack("nn", 2, 1));
}
}
/**
* @brief Check remote credentials via HTTP(S)
*
* @param string $host The hostname
* @param string $user Username
* @param string $password Password
* @param boolean $ssl Should the check be done via SSL?
*
* @return boolean Are the credentials okay?
*/
private function check_credentials($host, $user, $password, $ssl) {
$this->writeDebugLog("[debug] check credentials for user ".$user." on ".$host);
$url = ($ssl ? "https":"http")."://".$host."/api/account/verify_credentials.json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$password);
$header = curl_exec($ch);
$curl_info = @curl_getinfo($ch);
$http_code = $curl_info["http_code"];
curl_close($ch);
$this->writeDebugLog("[debug] got HTTP code ".$http_code);
return ($http_code == 200);
}
/**
* @brief write data to the logfile
*
* @param string $sMessage The logfile message
*/
private function writeLog($sMessage) {
if (is_resource($this->rLogFile))
fwrite($this->rLogFile, date("r")." ".$sMessage."\n");
}
/**
* @brief write debug data to the logfile
*
* @param string $sMessage The logfile message
*/
private function writeDebugLog($sMessage) {
if ($this->bDebug)
$this->writeLog($sMessage);
}
/**
* @brief destroy the class
*/
public function __destruct() {
// close the log file
$this->writeLog("[exAuth] stop");
if (is_resource($this->rLogFile)){
if (is_resource($this->rLogFile))
fclose($this->rLogFile);
}
}
private function writeLog($sMessage)
{
if (is_resource($this->rLogFile)) {
fwrite($this->rLogFile, date("r") ." ". $sMessage ."\n");
}
}
private function writeDebugLog($sMessage)
{
if ($this->bDebug){
$this->writeLog($sMessage);
}
}
}
?>

View file

@ -34,7 +34,6 @@ function bb_map_location($match) {
function bb_attachment($Text, $simplehtml = false, $tryoembed = true) {
$data = get_attachment_data($Text);
if (!$data)
return $Text;
@ -85,7 +84,7 @@ function bb_attachment($Text, $simplehtml = false, $tryoembed = true) {
$text .= $oembed;
if (trim($data["description"]) != "")
$text .= sprintf('<blockquote>%s</blockquote></span>', trim($data["description"]));
$text .= sprintf('<blockquote>%s</blockquote></span>', trim(bbcode($data["description"])));
}
}
return $data["text"].$text.$data["after"];
@ -147,7 +146,7 @@ function cleancss($input) {
if (($char >= "a") and ($char <= "z"))
$cleaned .= $char;
if (!(strpos(" #;:0123456789-_", $char) === false))
if (!(strpos(" #;:0123456789-_.%", $char) === false))
$cleaned .= $char;
}
@ -408,23 +407,28 @@ function bb_ShareAttributes($share, $simplehtml) {
if ($itemcache == "")
$reldate = (($posted) ? " " . relative_date($posted) : '');
// We only call this so that a previously unknown contact can be added.
// This is important for the function "get_contact_details_by_url".
// This function then can fetch an entry from the contact table.
get_contact($profile, 0);
$data = get_contact_details_by_url($profile);
if (isset($data["name"]) AND isset($data["addr"]))
if (isset($data["name"]) AND ($data["name"] != "") AND isset($data["addr"]) AND ($data["addr"] != ""))
$userid_compact = $data["name"]." (".$data["addr"].")";
else
$userid_compact = GetProfileUsername($profile,$author, true);
if (isset($data["addr"]))
if (isset($data["addr"]) AND ($data["addr"] != ""))
$userid = $data["addr"];
else
$userid = GetProfileUsername($profile,$author, false);
if (isset($data["name"]))
if (isset($data["name"]) AND ($data["name"] != ""))
$author = $data["name"];
if (isset($data["photo"]))
$avatar = $data["photo"];
if (isset($data["micro"]) AND ($data["micro"] != ""))
$avatar = $data["micro"];
$preshare = trim($share[1]);
@ -490,6 +494,8 @@ function bb_ShareAttributes($share, $simplehtml) {
default:
$text = trim($share[1])."\n";
$avatar = proxy_url($avatar, false, PROXY_SIZE_THUMB);
$tpl = get_markup_template('shared_content.tpl');
$text .= replace_macros($tpl,
array(
@ -717,6 +723,13 @@ function bb_CleanPictureLinks($text) {
return ($text);
}
function bb_highlight($match) {
if(in_array(strtolower($match[1]),['php','css','mysql','sql','abap','diff','html','perl','ruby',
'vbscript','avrc','dtd','java','xml','cpp','python','javascript','js','sh']))
return text_highlight($match[2],strtolower($match[1]));
return $match[0];
}
// BBcode 2 HTML was written by WAY2WEB.net
// extended to work with Mistpark/Friendica - Mike Macgirvin
@ -769,6 +782,11 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
if (!$tryoembed)
$Text = preg_replace("/\[share(.*?)avatar\s?=\s?'.*?'\s?(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","\n[share$1$2]$3[/share]",$Text);
// Check for [code] text here, before the linefeeds are messed with.
// The highlighter will unescape and re-escape the content.
if (strpos($Text,'[code=') !== false) {
$Text = preg_replace_callback("/\[code=(.*?)\](.*?)\[\/code\]/ism", 'bb_highlight', $Text);
}
// Convert new line chars to html <br /> tags
// nlbr seems to be hopelessly messed up
@ -874,8 +892,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// we may need to restrict this further if it picks up too many strays
// link acct:user@host to a webfinger profile redirector
$Text = preg_replace('/acct:(.*?)@(.*?)([ ,])/', '<a href="' . $a->get_baseurl() . '/acctlink?addr=' . "$1@$2"
. '" target="extlink" >acct:' . "$1@$2$3" . '</a>',$Text);
$Text = preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', '<a href="' . $a->get_baseurl() . '/acctlink?addr=$1@$2" target="extlink">acct:$1@$2</a>',$Text);
// Perform MAIL Search
$Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1">$1</a>', $Text);
@ -902,6 +919,9 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'<h5>$1</h5>',$Text);
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text);
// Check for paragraph
$Text = preg_replace("(\[p\](.*?)\[\/p\])ism",'<p>$1</p>',$Text);
// Check for bold text
$Text = preg_replace("(\[b\](.*?)\[\/b\])ism",'<strong>$1</strong>',$Text);
@ -1121,6 +1141,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
$Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text);
}

View file

@ -1,72 +1,197 @@
<?php
/**
* @file include/cache.php
*
* @brief Class for storing data for a short time
*/
use \Friendica\Core\Config;
use \Friendica\Core\PConfig;
class Cache {
/**
* cache api
* @brief Check for memcache and open a connection if configured
*
* @return object|boolean The memcache object - or "false" if not successful
*/
public static function memcache() {
if (!function_exists('memcache_connect')) {
return false;
}
class Cache {
public static function get($key) {
if (!Config::get('system', 'memcache')) {
return false;
}
$r = q("SELECT `v` FROM `cache` WHERE `k`='%s' limit 1",
dbesc($key)
);
$memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
$memcache_port = Config::get('system', 'memcache_port', 11211);
if (count($r))
return $r[0]['v'];
$memcache = new Memcache;
if (!$memcache->connect($memcache_host, $memcache_port)) {
return false;
}
return $memcache;
}
/**
* @brief Return the duration for a given cache level
*
* @param integer $level Cache level
*
* @return integer The cache duration in seconds
*/
private function duration($level) {
switch($level) {
case CACHE_MONTH;
$seconds = 2592000;
break;
case CACHE_WEEK;
$seconds = 604800;
break;
case CACHE_DAY;
$seconds = 86400;
break;
case CACHE_HOUR;
$seconds = 3600;
break;
case CACHE_HALF_HOUR;
$seconds = 1800;
break;
case CACHE_QUARTER_HOUR;
$seconds = 900;
break;
case CACHE_FIVE_MINUTES;
$seconds = 300;
break;
case CACHE_MINUTE;
$seconds = 60;
break;
}
return $seconds;
}
/**
* @brief Fetch cached data according to the key
*
* @param string $key The key to the cached data
*
* @return mixed Cached $value or "null" if not found
*/
public static function get($key) {
$memcache = self::memcache();
if (is_object($memcache)) {
// We fetch with the hostname as key to avoid problems with other applications
$value = $memcache->get(get_app()->get_hostname().":".$key);
if (!is_bool($value)) {
return unserialize($value);
}
return null;
}
public static function set($key,$value, $duration = CACHE_MONTH) {
// Frequently clear cache
self::clear($duration);
q("REPLACE INTO `cache` (`k`,`v`,`expire_mode`,`updated`) VALUES ('%s','%s',%d,'%s')",
dbesc($key),
dbesc($value),
intval($duration),
dbesc(datetime_convert()));
$r = q("SELECT `v` FROM `cache` WHERE `k`='%s' LIMIT 1",
dbesc($key)
);
if (dbm::is_result($r)) {
return unserialize($r[0]['v']);
}
/*
*
* Leaving this legacy code temporaily to see how REPLACE fares
* as opposed to non-atomic checks when faced with fast moving key duplication.
* As a MySQL extension it isn't portable, but we're not yet very portable.
*/
/*
* $r = q("SELECT * FROM `cache` WHERE `k`='%s' limit 1",
* dbesc($key)
* );
* if(count($r)) {
* q("UPDATE `cache` SET `v` = '%s', `updated = '%s' WHERE `k` = '%s'",
* dbesc($value),
* dbesc(datetime_convert()),
* dbesc($key));
* }
* else {
* q("INSERT INTO `cache` (`k`,`v`,`updated`) VALUES ('%s','%s','%s')",
* dbesc($key),
* dbesc($value),
* dbesc(datetime_convert()));
* }
* }
*/
public static function clear(){
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")), intval(CACHE_MONTH));
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 7 days")), intval(CACHE_WEEK));
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 1 days")), intval(CACHE_DAY));
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 1 hours")), intval(CACHE_HOUR));
}
return null;
}
/**
* @brief Put data in the cache according to the key
*
* The input $value can have multiple formats.
*
* @param string $key The key to the cached data
* @param mixed $valie The value that is about to be stored
* @param integer $duration The cache lifespan
*/
public static function set($key, $value, $duration = CACHE_MONTH) {
// Do we have an installed memcache? Use it instead.
$memcache = self::memcache();
if (is_object($memcache)) {
// We store with the hostname as key to avoid problems with other applications
$memcache->set(get_app()->get_hostname().":".$key, serialize($value), MEMCACHE_COMPRESSED, self::duration($duration));
return;
}
/// @todo store the cache data in the same way like the config data
q("REPLACE INTO `cache` (`k`,`v`,`expire_mode`,`updated`) VALUES ('%s','%s',%d,'%s')",
dbesc($key),
dbesc(serialize($value)),
intval($duration),
dbesc(datetime_convert()));
}
/**
* @brief Remove outdated data from the cache
*
* @param integer $maxlevel The maximum cache level that is to be cleared
*/
public static function clear($max_level = CACHE_MONTH) {
// Clear long lasting cache entries only once a day
if (get_config("system", "cache_cleared_day") < time() - self::duration(CACHE_DAY)) {
if ($max_level == CACHE_MONTH) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")), intval(CACHE_MONTH));
}
if ($max_level <= CACHE_WEEK) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 7 days")), intval(CACHE_WEEK));
}
if ($max_level <= CACHE_DAY) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 1 days")), intval(CACHE_DAY));
}
set_config("system", "cache_cleared_day", time());
}
if (($max_level <= CACHE_HOUR) AND (get_config("system", "cache_cleared_hour")) < time() - self::duration(CACHE_HOUR)) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 1 hours")), intval(CACHE_HOUR));
set_config("system", "cache_cleared_hour", time());
}
if (($max_level <= CACHE_HALF_HOUR) AND (get_config("system", "cache_cleared_half_hour")) < time() - self::duration(CACHE_HALF_HOUR)) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 30 minutes")), intval(CACHE_HALF_HOUR));
set_config("system", "cache_cleared_half_hour", time());
}
if (($max_level <= CACHE_QUARTER_HOUR) AND (get_config("system", "cache_cleared_hour")) < time() - self::duration(CACHE_QUARTER_HOUR)) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 15 minutes")), intval(CACHE_QUARTER_HOUR));
set_config("system", "cache_cleared_quarter_hour", time());
}
if (($max_level <= CACHE_FIVE_MINUTES) AND (get_config("system", "cache_cleared_five_minute")) < time() - self::duration(CACHE_FIVE_MINUTES)) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 5 minutes")), intval(CACHE_FIVE_MINUTES));
set_config("system", "cache_cleared_five_minute", time());
}
if (($max_level <= CACHE_MINUTE) AND (get_config("system", "cache_cleared_minute")) < time() - self::duration(CACHE_MINUTE)) {
q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
dbesc(datetime_convert('UTC','UTC',"now - 1 minutes")), intval(CACHE_MINUTE));
set_config("system", "cache_cleared_minute", time());
}
}
}

View file

@ -11,7 +11,7 @@ function cli_startup() {
if(is_null($a)) {
$a = new App;
}
if(is_null($db)) {
@include(".htconfig.php");
require_once("dba.php");

View file

@ -7,10 +7,10 @@ function contact_profile_assign($current,$foreign_net) {
$disabled = (($foreign_net) ? ' disabled="true" ' : '');
$o .= "<select id=\"contact-profile-selector\" $disabled name=\"profile-assign\" />\r\n";
$o .= "<select id=\"contact-profile-selector\" class=\"form-control\" $disabled name=\"profile-assign\" />\r\n";
$r = q("SELECT `id`, `profile-name` FROM `profile` WHERE `uid` = %d",
intval($_SESSION['uid']));
intval($_SESSION['uid']));
if(count($r)) {
foreach($r as $rr) {

View file

@ -374,30 +374,18 @@ function visible_activity($item) {
}
/**
* @brief List of all contact fields that are needed for the conversation function
* @brief SQL query for items
*/
function contact_fieldlist() {
function item_query() {
$fieldlist = "`contact`.`network`, `contact`.`url`, `contact`.`name`, `contact`.`writable`,
`contact`.`self`, `contact`.`id` AS `cid`, `contact`.`alias`";
return $fieldlist;
return "SELECT ".item_fieldlists()." FROM `item` ".
item_joins()." WHERE ".item_condition();
}
/**
* @brief SQL condition for contacts
* @brief List of all data fields that are needed for displaying items
*/
function contact_condition() {
$condition = "NOT `contact`.`blocked` AND NOT `contact`.`pending`";
return $condition;
}
/**
* @brief List of all item fields that are needed for the conversation function
*/
function item_fieldlist() {
function item_fieldlists() {
/*
These Fields are not added below (yet). They are here to for bug search.
@ -405,19 +393,15 @@ These Fields are not added below (yet). They are here to for bug search.
`item`.`extid`,
`item`.`received`,
`item`.`changed`,
`item`.`author-avatar`,
`item`.`object`,
`item`.`moderated`,
`item`.`target-type`,
`item`.`target`,
`item`.`resource-id`,
`item`.`tag`,
`item`.`attach`,
`item`.`inform`,
`item`.`pubmail`,
`item`.`moderated`,
`item`.`visible`,
`item`.`spam`,
`item`.`starred`,
`item`.`bookmark`,
`item`.`unseen`,
`item`.`deleted`,
@ -430,28 +414,42 @@ These Fields are not added below (yet). They are here to for bug search.
`item`.`shadow`,
*/
$fieldlist = "`item`.`author-link`, `item`.`verb`, `item`.`id`, `item`.`parent`, `item`.`file`,
`item`.`uid`, `item`.`author-name`, `item`.`location`, `item`.`coord`,
`item`.`title`, `item`.`uri`, `item`.`created`, `item`.`app`, `item`.`guid`,
`item`.`contact-id`, `item`.`thr-parent`, `item`.`parent-uri`, `item`.`rendered-hash`,
`item`.`body`, `item`.`rendered-html`, `item`.`private`, `item`.`edited`,
`item`.`allow_cid`, `item`.`allow_gid`, `item`.`deny_cid`, `item`.`deny_gid`,
`item`.`event-id`, `item`.`object-type`, `item`.`starred`, `item`.`created`,
`item`.`postopts`, `item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`,
`item`.`plink`, `item`.`wall`, `item`.`commented`,
`item`.`id` AS `item_id`, `item`.`network` AS `item_network`";
return "`item`.`author-link`, `item`.`author-name`, `item`.`author-avatar`,
`item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`,
`item`.`contact-id`, `item`.`uid`, `item`.`id`, `item`.`parent`,
`item`.`uri`, `item`.`thr-parent`, `item`.`parent-uri`,
`item`.`commented`, `item`.`created`, `item`.`edited`,
`item`.`verb`, `item`.`object-type`, `item`.`postopts`, `item`.`plink`,
`item`.`guid`, `item`.`wall`, `item`.`private`, `item`.`starred`,
`item`.`title`, `item`.`body`, `item`.`file`, `item`.`event-id`,
`item`.`location`, `item`.`coord`, `item`.`app`, `item`.`attach`,
`item`.`rendered-hash`, `item`.`rendered-html`, `item`.`object`,
`item`.`allow_cid`, `item`.`allow_gid`, `item`.`deny_cid`, `item`.`deny_gid`,
`item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
return $fieldlist;
`author`.`thumb` AS `author-thumb`, `owner`.`thumb` AS `owner-thumb`,
`contact`.`network`, `contact`.`url`, `contact`.`name`, `contact`.`writable`,
`contact`.`self`, `contact`.`id` AS `cid`, `contact`.`alias`";
}
/**
* @brief SQL condition for items
* @brief SQL join for contacts that are needed for displaying items
*/
function item_joins() {
return "STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND
NOT `contact`.`blocked` AND NOT `contact`.`pending`
LEFT JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id`
LEFT JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id`";
}
/**
* @brief SQL condition for items that are needed for displaying items
*/
function item_condition() {
$condition = "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`";
return $condition;
return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`";
}
/**
@ -623,7 +621,6 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
$comment = '';
$owner_url = '';
$owner_photo = '';
$owner_name = '';
$sparkle = '';
@ -668,18 +665,6 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
$tags[] = $prefix."<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
}
/*foreach(explode(',',$item['tag']) as $tag){
$tag = trim($tag);
if ($tag!="") {
$t = bbcode($tag);
$tags[] = $t;
if($t[0] == '#')
$hashtags[] = $t;
elseif($t[0] == '@')
$mentions[] = $t;
}
}*/
$sp = false;
$profile_link = best_link_url($item,$sp);
if($profile_link === 'mailbox')
@ -689,12 +674,21 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
else
$profile_link = zrl($profile_link);
// Don't rely on the author-avatar. It is better to use the data from the contact table
$author_contact = get_contact_details_by_url($item['author-link'], $profile_owner);
if ($author_contact["thumb"])
$profile_avatar = $author_contact["thumb"];
else
$profile_avatar = $item['author-avatar'];
if (!isset($item['author-thumb']) OR ($item['author-thumb'] == "")) {
$author_contact = get_contact_details_by_url($item['author-link'], $profile_owner);
if ($author_contact["thumb"])
$item['author-thumb'] = $author_contact["thumb"];
else
$item['author-thumb'] = $item['author-avatar'];
}
if (!isset($item['owner-thumb']) OR ($item['owner-thumb'] == "")) {
$owner_contact = get_contact_details_by_url($item['owner-link'], $profile_owner);
if ($owner_contact["thumb"])
$item['owner-thumb'] = $owner_contact["thumb"];
else
$item['owner-thumb'] = $item['owner-avatar'];
}
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
call_hooks('render_location',$locate);
@ -762,7 +756,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
'name' => $profile_name_e,
'sparkle' => $sparkle,
'lock' => $lock,
'thumb' => App::remove_baseurl(proxy_url($profile_avatar, false, PROXY_SIZE_THUMB)),
'thumb' => App::remove_baseurl(proxy_url($item['author-thumb'], false, PROXY_SIZE_THUMB)),
'title' => $item['title_e'],
'body' => $body_e,
'tags' => $tags_e,
@ -781,7 +775,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
'indent' => '',
'owner_name' => $owner_name_e,
'owner_url' => $owner_url,
'owner_photo' => proxy_url($owner_photo, false, PROXY_SIZE_THUMB),
'owner_photo' => App::remove_baseurl(proxy_url($item['owner-thumb'], false, PROXY_SIZE_THUMB)),
'plink' => get_plink($item),
'edpost' => false,
'isstarred' => $isstarred,
@ -885,15 +879,13 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
function best_link_url($item,&$sparkle,$ssl_state = false) {
$a = get_app();
$best_url = '';
$sparkle = false;
$clean_url = normalise_link($item['author-link']);
if (local_user()) {
$r = q("SELECT `id` FROM `contact` WHERE `network` = '%s' AND `uid` = %d AND `nurl` = '%s' LIMIT 1",
$r = q("SELECT `id` FROM `contact` WHERE `network` = '%s' AND `uid` = %d AND `nurl` = '%s' AND NOT `pending` LIMIT 1",
dbesc(NETWORK_DFRN), intval(local_user()), dbesc(normalise_link($clean_url)));
if ($r) {
$best_url = 'redir/'.$r[0]['id'];
@ -911,80 +903,86 @@ function best_link_url($item,&$sparkle,$ssl_state = false) {
}
if(! function_exists('item_photo_menu')){
function item_photo_menu($item){
$a = get_app();
if (! function_exists('item_photo_menu')) {
function item_photo_menu($item)
{
$ssl_state = false;
if(local_user())
if(local_user()) {
$ssl_state = true;
}
$sub_link="";
$poke_link="";
$contact_url="";
$pm_url="";
$status_link="";
$photos_link="";
$posts_link="";
$network = "";
$sub_link = '';
$poke_link = '';
$contact_url = '';
$pm_url = '';
$status_link = '';
$photos_link = '';
$posts_link = '';
$network = '';
if((local_user()) && local_user() == $item['uid'] && $item['parent'] == $item['id'] && (! $item['self'])) {
if ((local_user()) && local_user() == $item['uid'] && $item['parent'] == $item['id'] && (! $item['self'])) {
$sub_link = 'javascript:dosubthread(' . $item['id'] . '); return false;';
}
$sparkle = false;
$profile_link = best_link_url($item,$sparkle,$ssl_state);
if($profile_link === 'mailbox')
$profile_link = best_link_url($item, $sparkle, $ssl_state);
if ($profile_link === 'mailbox') {
$profile_link = '';
}
$cid = 0;
$network = "";
$network = '';
$rel = 0;
$r = q("SELECT `id`, `network`, `rel` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' LIMIT 1",
intval(local_user()), dbesc(normalise_link($item['author-link'])));
if ($r) {
$cid = $r[0]["id"];
$network = $r[0]["network"];
$rel = $r[0]["rel"];
$cid = $r[0]['id'];
$network = $r[0]['network'];
$rel = $r[0]['rel'];
}
if($sparkle) {
$status_link = $profile_link."?url=status";
$photos_link = $profile_link."?url=photos";
$profile_link = $profile_link."?url=profile";
$status_link = $profile_link . '?url=status';
$photos_link = $profile_link . '?url=photos';
$profile_link = $profile_link . '?url=profile';
$zurl = '';
} else
} else {
$profile_link = zrl($profile_link);
}
if($cid && !$item['self']) {
$poke_link = 'poke/?f=&c='.$cid;
$contact_url = 'contacts/'.$cid;
$posts_link = 'contacts/'.$cid.'/posts';
if ($cid && !$item['self']) {
$poke_link = 'poke/?f=&c=' . $cid;
$contact_url = 'contacts/' . $cid;
$posts_link = 'contacts/' . $cid . '/posts';
if (in_array($network, array(NETWORK_DFRN, NETWORK_DIASPORA)))
$pm_url = 'message/new/'.$cid;
if (in_array($network, array(NETWORK_DFRN, NETWORK_DIASPORA))) {
$pm_url = 'message/new/' . $cid;
}
}
if (local_user()) {
$menu = Array(
t("Follow Thread") => $sub_link,
t("View Status") => $status_link,
t("View Profile") => $profile_link,
t("View Photos") => $photos_link,
t("Network Posts") => $posts_link,
t("Edit Contact") => $contact_url,
t("Send PM") => $pm_url
t('Follow Thread') => $sub_link,
t('View Status') => $status_link,
t('View Profile') => $profile_link,
t('View Photos') => $photos_link,
t('Network Posts') => $posts_link,
t('View Contact') => $contact_url,
t('Send PM') => $pm_url
);
if ($network == NETWORK_DFRN)
if ($network == NETWORK_DFRN) {
$menu[t("Poke")] = $poke_link;
}
if ((($cid == 0) OR ($rel == CONTACT_IS_FOLLOWER)) AND
in_array($item['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA)))
$menu[t("Connect/Follow")] = "follow?url=".urlencode($item['author-link']);
} else
$menu = array(t("View Profile") => $item['author-link']);
in_array($item['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA))) {
$menu[t('Connect/Follow')] = 'follow?url=' . urlencode($item['author-link']);
}
} else {
$menu = array(t('View Profile') => $item['author-link']);
}
$args = array('item' => $item, 'menu' => $menu);
@ -992,13 +990,14 @@ function item_photo_menu($item){
$menu = $args['menu'];
$o = "";
foreach($menu as $k=>$v){
if(strpos($v,'javascript:') === 0) {
$v = substr($v,11);
$o .= "<li role=\"menuitem\"><a onclick=\"$v\">$k</a></li>\n";
$o = '';
foreach ($menu as $k => $v) {
if (strpos($v, 'javascript:') === 0) {
$v = substr($v, 11);
$o .= '<li role="menuitem"><a onclick="' . $v . '">' . $k . '</a></li>' . PHP_EOL;
} elseif ($v!='') {
$o .= '<li role="menuitem"><a href="' . $v . '">' . $k . '</a></li>' . PHP_EOL;
}
elseif ($v!="") $o .= "<li role=\"menuitem\"><a href=\"$v\">$k</a></li>\n";
}
return $o;
}}
@ -1145,7 +1144,7 @@ function format_like($cnt,$arr,$type,$id) {
$explikers = sprintf( t('%s don\'t attend.'), $likers);
break;
case 'attendmaybe':
$phrase = sprintf( t('<span %1$s>%2$d people</span> anttend maybe'), $spanatts, $cnt);
$phrase = sprintf( t('<span %1$s>%2$d people</span> attend maybe'), $spanatts, $cnt);
$explikers = sprintf( t('%s anttend maybe.'), $likers);
break;
}
@ -1289,6 +1288,10 @@ function status_editor($a,$x, $notes_cid = 0, $popup=false) {
'$private' => t('Private post'),
'$is_private' => $private_post,
'$public_link' => $public_post_link,
//jot nav tab (used in some themes)
'$message' => t('Message'),
'$browser' => t('Browser'),
));

View file

@ -11,6 +11,7 @@ if (!file_exists("boot.php") AND (sizeof($_SERVER["argv"]) != 0)) {
}
require_once("boot.php");
require_once("include/photos.php");
function cron_run(&$argv, &$argc){
@ -27,7 +28,6 @@ function cron_run(&$argv, &$argc){
unset($db_host, $db_user, $db_pass, $db_data);
};
require_once('include/session.php');
require_once('include/datetime.php');
require_once('include/items.php');
@ -70,53 +70,48 @@ function cron_run(&$argv, &$argc){
// run queue delivery process in the background
proc_run('php',"include/queue.php");
proc_run(PRIORITY_NEGLIGIBLE, "include/queue.php");
// run the process to discover global contacts in the background
proc_run('php',"include/discover_poco.php");
proc_run(PRIORITY_LOW, "include/discover_poco.php");
// run the process to update locally stored global contacts in the background
proc_run('php',"include/discover_poco.php", "checkcontact");
proc_run(PRIORITY_LOW, "include/discover_poco.php", "checkcontact");
// expire any expired accounts
// Expire and remove user entries
cron_expire_and_remove_users();
q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0
AND `account_expires_on` != '0000-00-00 00:00:00'
AND `account_expires_on` < UTC_TIMESTAMP() ");
// If the worker is active, split the jobs in several sub processes
if (get_config("system", "worker")) {
// Check OStatus conversations
proc_run(PRIORITY_MEDIUM, "include/cronjobs.php", "ostatus_mentions");
// delete user and contact records for recently removed accounts
// Check every conversation
proc_run(PRIORITY_MEDIUM, "include/cronjobs.php", "ostatus_conversations");
$r = q("SELECT * FROM `user` WHERE `account_removed` = 1 AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
if ($r) {
foreach($r as $user) {
q("DELETE FROM `contact` WHERE `uid` = %d", intval($user['uid']));
q("DELETE FROM `user` WHERE `uid` = %d", intval($user['uid']));
}
// Call possible post update functions
proc_run(PRIORITY_LOW, "include/cronjobs.php", "post_update");
// update nodeinfo data
proc_run(PRIORITY_LOW, "include/cronjobs.php", "nodeinfo");
} else {
// Check OStatus conversations
// Check only conversations with mentions (for a longer time)
ostatus::check_conversations(true);
// Check every conversation
ostatus::check_conversations(false);
// Call possible post update functions
// see include/post_update.php for more details
post_update();
// update nodeinfo data
nodeinfo_cron();
}
$abandon_days = intval(get_config('system','account_abandon_days'));
if($abandon_days < 1)
$abandon_days = 0;
// Check OStatus conversations
// Check only conversations with mentions (for a longer time)
ostatus::check_conversations(true);
// Check every conversation
ostatus::check_conversations(false);
// Call possible post update functions
// see include/post_update.php for more details
post_update();
// update nodeinfo data
nodeinfo_cron();
/// @TODO Regenerate usage statistics
// q("ANALYZE TABLE `item`");
// once daily run birthday_updates and then expire in background
$d1 = get_config('system','last_expire_day');
@ -126,11 +121,15 @@ function cron_run(&$argv, &$argc){
update_contact_birthdays();
proc_run('php',"include/discover_poco.php", "suggestions");
proc_run(PRIORITY_LOW, "include/discover_poco.php", "suggestions");
set_config('system','last_expire_day',$d2);
proc_run('php','include/expire.php');
proc_run(PRIORITY_LOW, 'include/expire.php');
proc_run(PRIORITY_LOW, 'include/dbclean.php');
cron_update_photo_albums();
}
// Clear cache entries
@ -142,28 +141,78 @@ function cron_run(&$argv, &$argc){
// Repair entries in the database
cron_repair_database();
// Poll contacts
cron_poll_contacts($argc, $argv);
logger('cron: end');
set_config('system','last_cron', time());
return;
}
/**
* @brief Update the cached values for the number of photo albums per user
*/
function cron_update_photo_albums() {
$r = q("SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`");
if (!dbm::is_result($r)) {
return;
}
foreach ($r AS $user) {
photo_albums($user['uid'], true);
}
}
/**
* @brief Expire and remove user entries
*/
function cron_expire_and_remove_users() {
// expire any expired accounts
q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0
AND `account_expires_on` != '0000-00-00 00:00:00'
AND `account_expires_on` < UTC_TIMESTAMP() ");
// delete user and contact records for recently removed accounts
$r = q("SELECT * FROM `user` WHERE `account_removed` AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
if ($r) {
foreach($r as $user) {
q("DELETE FROM `contact` WHERE `uid` = %d", intval($user['uid']));
q("DELETE FROM `user` WHERE `uid` = %d", intval($user['uid']));
}
}
}
/**
* @brief Poll contacts for unreceived messages
*
* @param Integer $argc Number of command line arguments
* @param Array $argv Array of command line arguments
*/
function cron_poll_contacts($argc, $argv) {
$manual_id = 0;
$generation = 0;
$force = false;
$restart = false;
if(($argc > 1) && ($argv[1] == 'force'))
if (($argc > 1) && ($argv[1] == 'force'))
$force = true;
if(($argc > 1) && ($argv[1] == 'restart')) {
if (($argc > 1) && ($argv[1] == 'restart')) {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
if (!$generation)
killme();
}
if(($argc > 1) && intval($argv[1])) {
if (($argc > 1) && intval($argv[1])) {
$manual_id = intval($argv[1]);
$force = true;
}
$interval = intval(get_config('system','poll_interval'));
if(! $interval)
if (!$interval)
$interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval')));
// If we are using the worker we don't need a delivery interval
@ -180,6 +229,10 @@ function cron_run(&$argv, &$argc){
// and which have a polling address and ignore Diaspora since
// we are unable to match those posts with a Diaspora GUID and prevent duplicates.
$abandon_days = intval(get_config('system','account_abandon_days'));
if($abandon_days < 1)
$abandon_days = 0;
$abandon_sql = (($abandon_days)
? sprintf(" AND `user`.`login_date` > UTC_TIMESTAMP() - INTERVAL %d DAY ", intval($abandon_days))
: ''
@ -200,11 +253,11 @@ function cron_run(&$argv, &$argc){
dbesc(NETWORK_MAIL2)
);
if(! count($contacts)) {
if (!count($contacts)) {
return;
}
foreach($contacts as $c) {
foreach ($contacts as $c) {
$res = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
intval($c['id'])
@ -266,24 +319,22 @@ function cron_run(&$argv, &$argc){
$update = true;
break;
}
if(!$update)
if (!$update)
continue;
}
logger("Polling ".$contact["network"]." ".$contact["id"]." ".$contact["nick"]." ".$contact["name"]);
proc_run('php','include/onepoll.php',$contact['id']);
if ($contact["remote_self"]) {
proc_run(PRIORITY_MEDIUM, 'include/onepoll.php', $contact['id']);
} else {
proc_run(PRIORITY_LOW, 'include/onepoll.php', $contact['id']);
}
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
}
}
logger('cron: end');
set_config('system','last_cron', time());
return;
}
/**
@ -327,10 +378,10 @@ function cron_clear_cache(&$a) {
}
// Delete the cached OEmbed entries that are older than one year
q("DELETE FROM `oembed` WHERE `created` < NOW() - INTERVAL 1 YEAR");
q("DELETE FROM `oembed` WHERE `created` < NOW() - INTERVAL 3 MONTH");
// Delete the cached "parse_url" entries that are older than one year
q("DELETE FROM `parsed_url` WHERE `created` < NOW() - INTERVAL 1 YEAR");
q("DELETE FROM `parsed_url` WHERE `created` < NOW() - INTERVAL 3 MONTH");
// Maximum table size in megabyte
$max_tablesize = intval(get_config('system','optimize_max_tablesize')) * 1000000;

View file

@ -31,6 +31,17 @@ function cronhooks_run(&$argv, &$argc){
return;
}
load_hooks();
if (($argc == 2) AND is_array($a->hooks) AND array_key_exists("cron", $a->hooks)) {
foreach ($a->hooks["cron"] as $hook)
if ($hook[1] == $argv[1]) {
logger("Calling cron hook '".$hook[1]."'", LOGGER_DEBUG);
call_single_hook($a, $name, $hook, $data);
}
return;
}
$last = get_config('system','last_cronhook');
$poll_interval = intval(get_config('system','cronhook_interval'));
@ -47,13 +58,17 @@ function cronhooks_run(&$argv, &$argc){
$a->set_baseurl(get_config('system','url'));
load_hooks();
logger('cronhooks: start');
$d = datetime_convert();
call_hooks('cron', $d);
if (get_config("system", "worker") AND is_array($a->hooks) AND array_key_exists("cron", $a->hooks)) {
foreach ($a->hooks["cron"] as $hook) {
logger("Calling cronhooks for '".$hook[1]."'", LOGGER_DEBUG);
proc_run(PRIORITY_MEDIUM, "include/cronhooks.php", $hook[1]);
}
} else
call_hooks('cron', $d);
logger('cronhooks: end');

77
include/cronjobs.php Normal file
View file

@ -0,0 +1,77 @@
<?php
if (!file_exists("boot.php") AND (sizeof($_SERVER["argv"]) != 0)) {
$directory = dirname($_SERVER["argv"][0]);
if (substr($directory, 0, 1) != "/")
$directory = $_SERVER["PWD"]."/".$directory;
$directory = realpath($directory."/..");
chdir($directory);
}
require_once("boot.php");
function cronjobs_run(&$argv, &$argc){
global $a, $db;
if(is_null($a)) {
$a = new App;
}
if(is_null($db)) {
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
};
require_once('include/session.php');
require_once('include/datetime.php');
require_once('include/ostatus.php');
require_once('include/post_update.php');
require_once('mod/nodeinfo.php');
load_config('config');
load_config('system');
$a->set_baseurl(get_config('system','url'));
// No parameter set? So return
if ($argc <= 1)
return;
// Check OStatus conversations
// Check only conversations with mentions (for a longer time)
if ($argv[1] == 'ostatus_mentions') {
ostatus::check_conversations(true);
return;
}
// Check every conversation
if ($argv[1] == 'ostatus_conversations') {
ostatus::check_conversations(false);
return;
}
// Call possible post update functions
// see include/post_update.php for more details
if ($argv[1] == 'post_update') {
post_update();
return;
}
// update nodeinfo data
if ($argv[1] == 'nodeinfo') {
nodeinfo_cron();
return;
}
return;
}
if (array_search(__file__,get_included_files())===0){
cronjobs_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -213,7 +213,7 @@ function dob($dob) {
* @return string Parsed HTML output.
*/
function datesel($format, $min, $max, $default, $id = 'datepicker') {
return datetimesel($format,$min,$max,$default,$id,true,false, '','');
return datetimesel($format,$min,$max,$default,'',$id,true,false, '','');
}
/**
@ -231,7 +231,7 @@ function datesel($format, $min, $max, $default, $id = 'datepicker') {
* @return string Parsed HTML output.
*/
function timesel($format, $h, $m, $id='timepicker') {
return datetimesel($format,new DateTime(),new DateTime(),new DateTime("$h:$m"),$id,false,true);
return datetimesel($format,new DateTime(),new DateTime(),new DateTime("$h:$m"),'',$id,false,true);
}
/**
@ -262,7 +262,7 @@ function timesel($format, $h, $m, $id='timepicker') {
* @todo Once browser support is better this could probably be replaced with
* native HTML5 date picker.
*/
function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pickdate = true, $picktime = true, $minfrom = '', $maxfrom = '', $required = false) {
function datetimesel($format, $min, $max, $default, $label, $id = 'datetimepicker', $pickdate = true, $picktime = true, $minfrom = '', $maxfrom = '', $required = false) {
// First day of the week (0 = Sunday)
$firstDay = get_pconfig(local_user(),'system','first_day_of_week');
@ -284,7 +284,7 @@ function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pic
$minjs = $min ? ",minDate: new Date({$min->getTimestamp()}*1000), yearStart: " . $min->format('Y') : '';
$maxjs = $max ? ",maxDate: new Date({$max->getTimestamp()}*1000), yearEnd: " . $max->format('Y') : '';
$input_text = $default ? 'value="' . date($dateformat, $default->getTimestamp()) . '"' : '';
$input_text = $default ? date($dateformat, $default->getTimestamp()) : '';
$defaultdatejs = $default ? ",defaultDate: new Date({$default->getTimestamp()}*1000)" : '';
$pickers = '';
@ -294,9 +294,9 @@ function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pic
$extra_js = '';
$pickers .= ",dayOfWeekStart: ".$firstDay.",lang:'".$lang."'";
if($minfrom != '')
$extra_js .= "\$('#$minfrom').data('xdsoft_datetimepicker').setOptions({onChangeDateTime: function (currentDateTime) { \$('#$id').data('xdsoft_datetimepicker').setOptions({minDate: currentDateTime})}})";
$extra_js .= "\$('#id_$minfrom').data('xdsoft_datetimepicker').setOptions({onChangeDateTime: function (currentDateTime) { \$('#id_$id').data('xdsoft_datetimepicker').setOptions({minDate: currentDateTime})}})";
if($maxfrom != '')
$extra_js .= "\$('#$maxfrom').data('xdsoft_datetimepicker').setOptions({onChangeDateTime: function (currentDateTime) { \$('#$id').data('xdsoft_datetimepicker').setOptions({maxDate: currentDateTime})}})";
$extra_js .= "\$('#id_$maxfrom').data('xdsoft_datetimepicker').setOptions({onChangeDateTime: function (currentDateTime) { \$('#id_$id').data('xdsoft_datetimepicker').setOptions({maxDate: currentDateTime})}})";
$readable_format = $dateformat;
$readable_format = str_replace('Y','yyyy',$readable_format);
@ -305,10 +305,13 @@ function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pic
$readable_format = str_replace('H','HH',$readable_format);
$readable_format = str_replace('i','MM',$readable_format);
$o .= "<div class='date'><input type='text' placeholder='$readable_format' name='$id' id='$id' $input_text />";
$o .= '</div>';
$tpl = get_markup_template('field_input.tpl');
$o .= replace_macros($tpl,array(
'$field' => array($id, $label, $input_text, '', (($required) ? '*' : ''), 'placeholder="' . $readable_format . '"'),
));
$o .= "<script type='text/javascript'>";
$o .= "\$(function () {var picker = \$('#$id').datetimepicker({step:5,format:'$dateformat' $minjs $maxjs $pickers $defaultdatejs}); $extra_js})";
$o .= "\$(function () {var picker = \$('#id_$id').datetimepicker({step:5,format:'$dateformat' $minjs $maxjs $pickers $defaultdatejs}); $extra_js})";
$o .= "</script>";
return $o;
@ -322,15 +325,15 @@ function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pic
* Results relative to current timezone.
* Limited to range of timestamps.
*
* @param string $posted_date
* @param string $posted_date MySQL-formatted date string (YYYY-MM-DD HH:MM:SS)
* @param string $format (optional) Parsed with sprintf()
* <tt>%1$d %2$s ago</tt>, e.g. 22 hours ago, 1 minute ago
*
*
* @return string with relative date
*/
function relative_date($posted_date,$format = null) {
function relative_date($posted_date, $format = null) {
$localtime = datetime_convert('UTC',date_default_timezone_get(),$posted_date);
$localtime = $posted_date . ' UTC';
$abs = strtotime($localtime);
@ -344,13 +347,6 @@ function relative_date($posted_date,$format = null) {
return t('less than a second ago');
}
/*
$time_append = '';
if ($etime >= 86400) {
$time_append = ' ('.$localtime.')';
}
*/
$a = array( 12 * 30 * 24 * 60 * 60 => array( t('year'), t('years')),
30 * 24 * 60 * 60 => array( t('month'), t('months')),
7 * 24 * 60 * 60 => array( t('week'), t('weeks')),
@ -365,10 +361,11 @@ function relative_date($posted_date,$format = null) {
if ($d >= 1) {
$r = round($d);
// translators - e.g. 22 hours ago, 1 minute ago
if(! $format)
if (!$format) {
$format = t('%1$d %2$s ago');
}
return sprintf( $format,$r, (($r == 1) ? $str[0] : $str[1]));
return sprintf($format, $r, (($r == 1) ? $str[0] : $str[1]));
}
}
}

View file

@ -1,10 +1,11 @@
<?php
require_once("dbm.php");
# if PDO is avaible for mysql, use the new database abstraction
# TODO: PDO is disabled for release 3.3. We need to investigate why
# the update from 3.2 fails with pdo
/*
if(class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
if (class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
require_once("library/dddbl2/dddbl.php");
require_once("include/dba_pdo.php");
}
@ -23,7 +24,7 @@ require_once('include/datetime.php');
*
*/
if(! class_exists('dba')) {
if (! class_exists('dba')) {
class dba {
private $debug = 0;
@ -33,7 +34,7 @@ class dba {
public $connected = false;
public $error = false;
function __construct($server,$user,$pass,$db,$install = false) {
function __construct($server, $user, $pass, $db, $install = false) {
global $a;
$stamp1 = microtime(true);
@ -43,15 +44,15 @@ class dba {
$pass = trim($pass);
$db = trim($db);
if (!(strlen($server) && strlen($user))){
if (!(strlen($server) && strlen($user))) {
$this->connected = false;
$this->db = null;
return;
}
if($install) {
if(strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1')) {
if(! dns_get_record($server, DNS_A + DNS_CNAME + DNS_PTR)) {
if ($install) {
if (strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1')) {
if (! dns_get_record($server, DNS_A + DNS_CNAME + DNS_PTR)) {
$this->error = sprintf( t('Cannot locate DNS info for database server \'%s\''), $server);
$this->connected = false;
$this->db = null;
@ -60,23 +61,28 @@ class dba {
}
}
if(class_exists('mysqli')) {
if (class_exists('mysqli')) {
$this->db = @new mysqli($server,$user,$pass,$db);
if(! mysqli_connect_errno()) {
if (! mysqli_connect_errno()) {
$this->connected = true;
}
}
else {
if (isset($a->config["system"]["db_charset"])) {
$this->db->set_charset($a->config["system"]["db_charset"]);
}
} else {
$this->mysqli = false;
$this->db = mysql_connect($server,$user,$pass);
if($this->db && mysql_select_db($db,$this->db)) {
if ($this->db && mysql_select_db($db,$this->db)) {
$this->connected = true;
}
if (isset($a->config["system"]["db_charset"]))
mysql_set_charset($a->config["system"]["db_charset"], $this->db);
}
if(! $this->connected) {
if (!$this->connected) {
$this->db = null;
if(! $install)
if (!$install) {
system_unavailable();
}
}
$a->save_timestamp($stamp1, "network");
@ -86,27 +92,80 @@ class dba {
return $this->db;
}
/**
* @brief Returns the MySQL server version string
*
* This function discriminate between the deprecated mysql API and the current
* object-oriented mysqli API. Example of returned string: 5.5.46-0+deb8u1
*
* @return string
*/
public function server_info() {
if ($this->mysqli) {
$return = $this->db->server_info;
} else {
$return = mysql_get_server_info($this->db);
}
return $return;
}
/**
* @brief Returns the number of rows
*
* @return integer
*/
public function num_rows() {
if (!$this->result) {
return 0;
}
if ($this->mysqli) {
$return = $this->result->num_rows;
} else {
$return = mysql_num_rows($this->result);
}
return $return;
}
public function q($sql, $onlyquery = false) {
global $a;
if((! $this->db) || (! $this->connected))
if (!$this->db || !$this->connected) {
return false;
}
$this->error = '';
// Check the connection (This can reconnect the connection - if configured)
if ($this->mysqli) {
$connected = $this->db->ping();
} else {
$connected = mysql_ping($this->db);
}
$connstr = ($connected ? "Connected" : "Disonnected");
$stamp1 = microtime(true);
if($this->mysqli)
$result = @$this->db->query($sql);
else
$result = @mysql_query($sql,$this->db);
$orig_sql = $sql;
if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) {
$sql = "/*".$a->callstack()." */ ".$sql;
}
if ($this->mysqli) {
$result = @$this->db->query($sql);
} else {
$result = @mysql_query($sql,$this->db);
}
$stamp2 = microtime(true);
$duration = (float)($stamp2-$stamp1);
$a->save_timestamp($stamp1, "database");
if(x($a->config,'system') && x($a->config['system'],'db_log')) {
if (strtolower(substr($orig_sql, 0, 6)) != "select") {
$a->save_timestamp($stamp1, "database_write");
}
if (x($a->config,'system') && x($a->config['system'],'db_log')) {
if (($duration > $a->config["system"]["db_loglimit"])) {
$duration = round($duration, 3);
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
@ -117,30 +176,34 @@ class dba {
}
}
if($this->mysqli) {
if($this->db->errno)
if ($this->mysqli) {
if ($this->db->errno) {
$this->error = $this->db->error;
}
elseif(mysql_errno($this->db))
$this->error = mysql_error($this->db);
if(strlen($this->error)) {
logger('dba: ' . $this->error);
$this->errorno = $this->db->errno;
}
} elseif (mysql_errno($this->db)) {
$this->error = mysql_error($this->db);
$this->errorno = mysql_errno($this->db);
}
if($this->debug) {
if (strlen($this->error)) {
logger('DB Error ('.$connstr.') '.$this->errorno.': '.$this->error);
}
if ($this->debug) {
$mesg = '';
if($result === false)
if ($result === false) {
$mesg = 'false';
elseif($result === true)
} elseif ($result === true) {
$mesg = 'true';
else {
if($this->mysqli)
} else {
if ($this->mysqli) {
$mesg = $result->num_rows . ' results' . EOL;
else
} else {
$mesg = mysql_num_rows($result) . ' results' . EOL;
}
}
$str = 'SQL = ' . printable($sql) . EOL . 'SQL returned ' . $mesg
@ -156,30 +219,30 @@ class dba {
* These usually indicate SQL syntax errors that need to be resolved.
*/
if($result === false) {
if ($result === false) {
logger('dba: ' . printable($sql) . ' returned false.' . "\n" . $this->error);
if(file_exists('dbfail.out'))
if (file_exists('dbfail.out')) {
file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . ' returned false' . "\n" . $this->error . "\n", FILE_APPEND);
}
}
if(($result === true) || ($result === false))
if (($result === true) || ($result === false)) {
return $result;
}
if ($onlyquery) {
$this->result = $result;
return true;
}
$r = array();
if($this->mysqli) {
if($result->num_rows) {
if ($this->mysqli) {
if ($result->num_rows) {
while($x = $result->fetch_array(MYSQLI_ASSOC))
$r[] = $x;
$result->free_result();
}
}
else {
if(mysql_num_rows($result)) {
} else {
if (mysql_num_rows($result)) {
while($x = mysql_fetch_array($result, MYSQL_ASSOC))
$r[] = $x;
mysql_free_result($result);
@ -188,33 +251,35 @@ class dba {
//$a->save_timestamp($stamp1, "database");
if($this->debug)
if ($this->debug) {
logger('dba: ' . printable(print_r($r, true)));
}
return($r);
}
public function qfetch() {
$x = false;
if ($this->result)
if($this->mysqli) {
if($this->result->num_rows)
if ($this->result) {
if ($this->mysqli) {
if ($this->result->num_rows)
$x = $this->result->fetch_array(MYSQLI_ASSOC);
} else {
if(mysql_num_rows($this->result))
if (mysql_num_rows($this->result))
$x = mysql_fetch_array($this->result, MYSQL_ASSOC);
}
}
return($x);
}
public function qclose() {
if ($this->result)
if($this->mysqli) {
if ($this->result) {
if ($this->mysqli) {
$this->result->free_result();
} else {
mysql_free_result($this->result);
}
}
}
public function dbg($dbg) {
@ -222,47 +287,62 @@ class dba {
}
public function escape($str) {
if($this->db && $this->connected) {
if($this->mysqli)
if ($this->db && $this->connected) {
if ($this->mysqli) {
return @$this->db->real_escape_string($str);
else
} else {
return @mysql_real_escape_string($str,$this->db);
}
}
}
function connected() {
if ($this->mysqli) {
$connected = $this->db->ping();
} else {
$connected = mysql_ping($this->db);
}
return $connected;
}
function __destruct() {
if ($this->db)
if($this->mysqli)
if ($this->db) {
if ($this->mysqli) {
$this->db->close();
else
} else {
mysql_close($this->db);
}
}
}
}}
if(! function_exists('printable')) {
if (! function_exists('printable')) {
function printable($s) {
$s = preg_replace("~([\x01-\x08\x0E-\x0F\x10-\x1F\x7F-\xFF])~",".", $s);
$s = str_replace("\x00",'.',$s);
if(x($_SERVER,'SERVER_NAME'))
if (x($_SERVER,'SERVER_NAME')) {
$s = escape_tags($s);
}
return $s;
}}
// Procedural functions
if(! function_exists('dbg')) {
if (! function_exists('dbg')) {
function dbg($state) {
global $db;
if($db)
$db->dbg($state);
if ($db) {
$db->dbg($state);
}
}}
if(! function_exists('dbesc')) {
if (! function_exists('dbesc')) {
function dbesc($str) {
global $db;
if($db && $db->connected)
if ($db && $db->connected) {
return($db->escape($str));
else
} else {
return(str_replace("'","\\'",$str));
}
}}
@ -272,17 +352,17 @@ function dbesc($str) {
// Example: $r = q("SELECT * FROM `%s` WHERE `uid` = %d",
// 'user', 1);
if(! function_exists('q')) {
if (! function_exists('q')) {
function q($sql) {
global $db;
$args = func_get_args();
unset($args[0]);
if($db && $db->connected) {
if ($db && $db->connected) {
$stmt = @vsprintf($sql,$args); // Disabled warnings
//logger("dba: q: $stmt", LOGGER_ALL);
if($stmt === false)
if ($stmt === false)
logger('dba: vsprintf error: ' . print_r(debug_backtrace(),true), LOGGER_DEBUG);
return $db->q($stmt);
}
@ -298,20 +378,57 @@ function q($sql) {
}}
/**
* @brief Performs a query with "dirty reads"
*
* By doing dirty reads (reading uncommitted data) no locks are performed
* This function can be used to fetch data that doesn't need to be reliable.
*
* @param $args Query parameters (1 to N parameters of different types)
* @return array Query array
*/
function qu($sql) {
global $db;
$args = func_get_args();
unset($args[0]);
if ($db && $db->connected) {
$stmt = @vsprintf($sql,$args); // Disabled warnings
if ($stmt === false)
logger('dba: vsprintf error: ' . print_r(debug_backtrace(),true), LOGGER_DEBUG);
$db->q("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
$retval = $db->q($stmt);
$db->q("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;");
return $retval;
}
/**
*
* This will happen occasionally trying to store the
* session data after abnormal program termination
*
*/
logger('dba: no database: ' . print_r($args,true));
return false;
}
/**
*
* Raw db query, no arguments
*
*/
if(! function_exists('dbq')) {
if (! function_exists('dbq')) {
function dbq($sql) {
global $db;
if($db && $db->connected)
if ($db && $db->connected) {
$ret = $db->q($sql);
else
} else {
$ret = false;
}
return $ret;
}}
@ -322,16 +439,16 @@ function dbq($sql) {
// cast to int to avoid trouble.
if(! function_exists('dbesc_array_cb')) {
if (! function_exists('dbesc_array_cb')) {
function dbesc_array_cb(&$item, $key) {
if(is_string($item))
if (is_string($item))
$item = dbesc($item);
}}
if(! function_exists('dbesc_array')) {
if (! function_exists('dbesc_array')) {
function dbesc_array(&$arr) {
if(is_array($arr) && count($arr)) {
if (is_array($arr) && count($arr)) {
array_walk($arr,'dbesc_array_cb');
}
}}
@ -340,4 +457,3 @@ function dbesc_array(&$arr) {
function dba_timer() {
return microtime(true);
}

157
include/dbclean.php Normal file
View file

@ -0,0 +1,157 @@
<?php
/**
* @file include/dbclean.php
* @brief The script is called from time to time to clean the database entries and remove orphaned data.
*/
require_once("boot.php");
function dbclean_run(&$argv, &$argc) {
global $a, $db;
if (is_null($a))
$a = new App;
if (is_null($db)) {
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
}
load_config('config');
load_config('system');
if ($argc == 2) {
$stage = intval($argv[1]);
} else {
$stage = 0;
}
if (get_config("system", "worker") AND ($stage == 0)) {
proc_run(PRIORITY_LOW, 'include/dbclean.php', 1);
proc_run(PRIORITY_LOW, 'include/dbclean.php', 2);
proc_run(PRIORITY_LOW, 'include/dbclean.php', 3);
proc_run(PRIORITY_LOW, 'include/dbclean.php', 4);
proc_run(PRIORITY_LOW, 'include/dbclean.php', 5);
proc_run(PRIORITY_LOW, 'include/dbclean.php', 6);
proc_run(PRIORITY_LOW, 'include/dbclean.php', 7);
} else {
remove_orphans($stage);
}
}
/**
* @brief Remove orphaned database entries
*/
function remove_orphans($stage = 0) {
global $db;
$count = 0;
if (($stage == 1) OR ($stage == 0)) {
logger("Deleting old global item entries from item table without user copy");
if ($db->q("SELECT `id` FROM `item` WHERE `uid` = 0
AND NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0)
AND `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY LIMIT 10000", true)) {
$count = $db->num_rows();
logger("found global item orphans: ".$count);
while ($orphan = $db->qfetch()) {
q("DELETE FROM `item` WHERE `id` = %d", intval($orphan["id"]));
}
}
$db->qclose();
logger("Done deleting old global item entries from item table without user copy");
}
if (($stage == 2) OR ($stage == 0)) {
logger("Deleting items without parents");
if ($db->q("SELECT `id` FROM `item` WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) LIMIT 10000", true)) {
$count = $db->num_rows();
logger("found item orphans without parents: ".$count);
while ($orphan = $db->qfetch()) {
q("DELETE FROM `item` WHERE `id` = %d", intval($orphan["id"]));
}
}
$db->qclose();
logger("Done deleting items without parents");
}
if (($stage == 3) OR ($stage == 0)) {
logger("Deleting orphaned data from thread table");
if ($db->q("SELECT `iid` FROM `thread` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`)", true)) {
$count = $db->num_rows();
logger("found thread orphans: ".$count);
while ($orphan = $db->qfetch()) {
q("DELETE FROM `thread` WHERE `iid` = %d", intval($orphan["iid"]));
}
}
$db->qclose();
logger("Done deleting orphaned data from thread table");
}
if (($stage == 4) OR ($stage == 0)) {
logger("Deleting orphaned data from notify table");
if ($db->q("SELECT `iid` FROM `notify` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`)", true)) {
$count = $db->num_rows();
logger("found notify orphans: ".$count);
while ($orphan = $db->qfetch()) {
q("DELETE FROM `notify` WHERE `iid` = %d", intval($orphan["iid"]));
}
}
$db->qclose();
logger("Done deleting orphaned data from notify table");
}
if (($stage == 5) OR ($stage == 0)) {
logger("Deleting orphaned data from notify-threads table");
if ($db->q("SELECT `id` FROM `notify-threads` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`)", true)) {
$count = $db->num_rows();
logger("found notify-threads orphans: ".$count);
while ($orphan = $db->qfetch()) {
q("DELETE FROM `notify-threads` WHERE `id` = %d", intval($orphan["id"]));
}
}
$db->qclose();
logger("Done deleting orphaned data from notify-threads table");
}
if (($stage == 6) OR ($stage == 0)) {
logger("Deleting orphaned data from sign table");
if ($db->q("SELECT `iid` FROM `sign` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`)", true)) {
$count = $db->num_rows();
logger("found sign orphans: ".$count);
while ($orphan = $db->qfetch()) {
q("DELETE FROM `sign` WHERE `iid` = %d", intval($orphan["iid"]));
}
}
$db->qclose();
logger("Done deleting orphaned data from sign table");
}
if (($stage == 7) OR ($stage == 0)) {
logger("Deleting orphaned data from term table");
if ($db->q("SELECT `oid` FROM `term` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`)", true)) {
$count = $db->num_rows();
logger("found term orphans: ".$count);
while ($orphan = $db->qfetch()) {
q("DELETE FROM `term` WHERE `oid` = %d", intval($orphan["oid"]));
}
}
$db->qclose();
logger("Done deleting orphaned data from term table");
}
// Call it again if not all entries were purged
if (($stage != 0) AND ($count > 0) AND get_config("system", "worker")) {
proc_run(PRIORITY_LOW, 'include/dbclean.php');
}
}
if (array_search(__file__,get_included_files())===0){
dbclean_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}
?>

View file

@ -20,8 +20,8 @@ class dbm {
foreach ($r AS $process) {
$state = trim($process["State"]);
// Filter out all idle processes
if (!in_array($state, array("", "init", "statistics"))) {
// Filter out all non blocking processes
if (!in_array($state, array("", "init", "statistics", "updating"))) {
++$states[$state];
++$processes;
}
@ -35,5 +35,19 @@ class dbm {
}
return(array("list" => $statelist, "amount" => $processes));
}
/**
* Checks if $array is a filled array with at least one entry.
*
* @param $array mixed A filled array with at least one entry
* @return Whether $array is a filled array
*/
public static function is_result($array) {
// It could be a return value from an update statement
if (is_bool($array)) {
return $array;
}
return (is_array($array) && count($array) > 0);
}
}
?>

View file

@ -78,8 +78,16 @@ function table_structure($table) {
if ($index["Index_type"] == "FULLTEXT")
continue;
if ($index['Key_name'] != 'PRIMARY' && $index['Non_unique'] == '0' && !isset($indexdata[$index["Key_name"]])) {
$indexdata[$index["Key_name"]] = array('UNIQUE');
}
$column = $index["Column_name"];
if ($index["Sub_part"] != "")
// On utf8mb4 a varchar index can only have a length of 191
// To avoid the need to add this to every index definition we just ignore it here.
// Exception are primary indexes
// Since there are some combindex primary indexes we use the limit of 180 here.
if (($index["Sub_part"] != "") AND (($index["Sub_part"] < 180) OR ($index["Key_name"] == "PRIMARY")))
$column .= "(".$index["Sub_part"].")";
$indexdata[$index["Key_name"]][] = $column;
@ -104,7 +112,7 @@ function table_structure($table) {
return(array("fields"=>$fielddata, "indexes"=>$indexdata));
}
function print_structure($database) {
function print_structure($database, $charset) {
echo "-- ------------------------------------------\n";
echo "-- ".FRIENDICA_PLATFORM." ".FRIENDICA_VERSION." (".FRIENDICA_CODENAME,")\n";
echo "-- DB_UPDATE_VERSION ".DB_UPDATE_VERSION."\n";
@ -113,7 +121,7 @@ function print_structure($database) {
echo "--\n";
echo "-- TABLE $name\n";
echo "--\n";
db_create_table($name, $structure['fields'], true, false, $structure["indexes"]);
db_create_table($name, $structure['fields'], $charset, true, false, $structure["indexes"]);
echo "\n";
}
@ -122,6 +130,14 @@ function print_structure($database) {
function update_structure($verbose, $action, $tables=null, $definition=null) {
global $a, $db;
if ($action)
set_config('system', 'maintenance', 1);
if (isset($a->config["system"]["db_charset"]))
$charset = $a->config["system"]["db_charset"];
else
$charset = "utf8";
$errors = false;
logger('updating structure', LOGGER_DEBUG);
@ -140,15 +156,29 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
// Get the definition
if (is_null($definition))
$definition = db_definition();
$definition = db_definition($charset);
// Ensure index conversion to unique removes duplicates
$sql_config = "SET session old_alter_table=1;";
if ($verbose)
echo $sql_config."\n";
if ($action)
@$db->q($sql_config);
// MySQL >= 5.7.4 doesn't support the IGNORE keyword in ALTER TABLE statements
if ((version_compare($db->server_info(), '5.7.4') >= 0) AND
!(strpos($db->server_info(), 'MariaDB') !== false)) {
$ignore = '';
}else {
$ignore = ' IGNORE';
}
// Compare it
foreach ($definition AS $name => $structure) {
$is_new_table = False;
$sql3="";
if (!isset($database[$name])) {
$r = db_create_table($name, $structure["fields"], $verbose, $action, $structure['indexes']);
$r = db_create_table($name, $structure["fields"], $charset, $verbose, $action, $structure['indexes']);
if(false === $r) {
$errors .= t('Errors encountered creating database tables.').$name.EOL;
}
@ -167,7 +197,7 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
if ($current_index_definition != $new_index_definition && substr($indexname, 0, 6) != 'local_') {
$sql2=db_drop_index($indexname);
if ($sql3 == "")
$sql3 = "ALTER TABLE `".$name."` ".$sql2;
$sql3 = "ALTER".$ignore." TABLE `".$name."` ".$sql2;
else
$sql3 .= ", ".$sql2;
}
@ -211,7 +241,7 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
$sql2=db_create_index($indexname, $fieldnames);
if ($sql2 != "") {
if ($sql3 == "")
$sql3 = "ALTER TABLE `".$name."` ".$sql2;
$sql3 = "ALTER" . $ignore . " TABLE `".$name."` ".$sql2;
else
$sql3 .= ", ".$sql2;
}
@ -232,6 +262,9 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
}
}
if ($action)
set_config('system', 'maintenance', 0);
return $errors;
}
@ -257,7 +290,7 @@ function db_field_command($parameters, $create = true) {
return($fieldstruct);
}
function db_create_table($name, $fields, $verbose, $action, $indexes=null) {
function db_create_table($name, $fields, $charset, $verbose, $action, $indexes=null) {
global $a, $db;
$r = true;
@ -282,7 +315,7 @@ function db_create_table($name, $fields, $verbose, $action, $indexes=null) {
$sql = implode(",\n\t", $sql_rows);
$sql = sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n\t", dbesc($name)).$sql."\n) DEFAULT CHARSET=utf8";
$sql = sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n\t", dbesc($name)).$sql."\n) DEFAULT CHARSET=".$charset;
if ($verbose)
echo $sql.";\n";
@ -315,9 +348,9 @@ function db_create_index($indexname, $fieldnames, $method="ADD") {
killme();
}
if ($indexname == "PRIMARY") {
return sprintf("%s PRIMARY KEY(`%s`)", $method, implode("`,`", $fieldnames));
if ($fieldnames[0] == "UNIQUE") {
array_shift($fieldnames);
$method .= ' UNIQUE';
}
$names = "";
@ -331,12 +364,26 @@ function db_create_index($indexname, $fieldnames, $method="ADD") {
$names .= "`".dbesc($fieldname)."`";
}
if ($indexname == "PRIMARY") {
return sprintf("%s PRIMARY KEY(%s)", $method, $names);
}
$sql = sprintf("%s INDEX `%s` (%s)", $method, dbesc($indexname), $names);
return($sql);
}
function db_definition() {
function db_index_suffix($charset, $reduce = 0) {
if ($charset != "utf8mb4")
return "";
// On utf8mb4 indexes can only have a length of 191
$indexlength = 191 - $reduce;
return "(".$indexlength.")";
}
function db_definition($charset) {
$database = array();
@ -365,10 +412,10 @@ function db_definition() {
"data" => array("type" => "longblob", "not null" => "1"),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"edited" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"allow_cid" => array("type" => "mediumtext", "not null" => "1"),
"allow_gid" => array("type" => "mediumtext", "not null" => "1"),
"deny_cid" => array("type" => "mediumtext", "not null" => "1"),
"deny_gid" => array("type" => "mediumtext", "not null" => "1"),
"allow_cid" => array("type" => "mediumtext"),
"allow_gid" => array("type" => "mediumtext"),
"deny_cid" => array("type" => "mediumtext"),
"deny_gid" => array("type" => "mediumtext"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -389,13 +436,14 @@ function db_definition() {
$database["cache"] = array(
"fields" => array(
"k" => array("type" => "varchar(255)", "not null" => "1", "primary" => "1"),
"v" => array("type" => "text", "not null" => "1"),
"v" => array("type" => "text"),
"expire_mode" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"updated" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
),
"indexes" => array(
"PRIMARY" => array("k"),
"PRIMARY" => array("k".db_index_suffix($charset)),
"updated" => array("updated"),
"expire_mode_updated" => array("expire_mode", "updated"),
)
);
$database["challenge"] = array(
@ -429,11 +477,11 @@ function db_definition() {
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"cat" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"k" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"v" => array("type" => "text", "not null" => "1"),
"v" => array("type" => "text"),
),
"indexes" => array(
"PRIMARY" => array("id"),
"cat_k" => array("cat(30)","k(30)"),
"cat_k" => array("UNIQUE", "cat(30)","k(30)"),
)
);
$database["contact"] = array(
@ -449,29 +497,30 @@ function db_definition() {
"name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"nick" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"location" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"about" => array("type" => "text", "not null" => "1"),
"keywords" => array("type" => "text", "not null" => "1"),
"about" => array("type" => "text"),
"keywords" => array("type" => "text"),
"gender" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"xmpp" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"attag" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"avatar" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"photo" => array("type" => "text", "not null" => "1"),
"thumb" => array("type" => "text", "not null" => "1"),
"micro" => array("type" => "text", "not null" => "1"),
"site-pubkey" => array("type" => "text", "not null" => "1"),
"photo" => array("type" => "text"),
"thumb" => array("type" => "text"),
"micro" => array("type" => "text"),
"site-pubkey" => array("type" => "text"),
"issued-id" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"dfrn-id" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"nurl" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"addr" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"alias" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"pubkey" => array("type" => "text", "not null" => "1"),
"prvkey" => array("type" => "text", "not null" => "1"),
"pubkey" => array("type" => "text"),
"prvkey" => array("type" => "text"),
"batch" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"request" => array("type" => "text", "not null" => "1"),
"notify" => array("type" => "text", "not null" => "1"),
"poll" => array("type" => "text", "not null" => "1"),
"confirm" => array("type" => "text", "not null" => "1"),
"poco" => array("type" => "text", "not null" => "1"),
"request" => array("type" => "text"),
"notify" => array("type" => "text"),
"poll" => array("type" => "text"),
"confirm" => array("type" => "text"),
"poco" => array("type" => "text"),
"aes_allow" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"ret-aes" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"usehub" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
@ -491,23 +540,25 @@ function db_definition() {
"writable" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"forum" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"prv" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"contact-type" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"hidden" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"archive" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"pending" => array("type" => "tinyint(1)", "not null" => "1", "default" => "1"),
"rating" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"reason" => array("type" => "text", "not null" => "1"),
"reason" => array("type" => "text"),
"closeness" => array("type" => "tinyint(2)", "not null" => "1", "default" => "99"),
"info" => array("type" => "mediumtext", "not null" => "1"),
"info" => array("type" => "mediumtext"),
"profile-id" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"bdyear" => array("type" => "varchar(4)", "not null" => "1", "default" => ""),
"bd" => array("type" => "date", "not null" => "1", "default" => "0000-00-00"),
"notify_new_posts" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"fetch_further_information" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"ffi_keyword_blacklist" => array("type" => "mediumtext", "not null" => "1"),
"ffi_keyword_blacklist" => array("type" => "mediumtext"),
),
"indexes" => array(
"PRIMARY" => array("id"),
"uid" => array("uid"),
"addr_uid" => array("addr", "uid"),
"nurl" => array("nurl"),
)
);
@ -515,12 +566,12 @@ function db_definition() {
"fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"guid" => array("type" => "varchar(64)", "not null" => "1", "default" => ""),
"recips" => array("type" => "mediumtext", "not null" => "1"),
"recips" => array("type" => "mediumtext"),
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"creator" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"updated" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"subject" => array("type" => "mediumtext", "not null" => "1"),
"subject" => array("type" => "mediumtext"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -536,6 +587,7 @@ function db_definition() {
),
"indexes" => array(
"PRIMARY" => array("id"),
"cmd_item_contact" => array("UNIQUE", "cmd", "item", "contact"),
)
);
$database["event"] = array(
@ -548,17 +600,17 @@ function db_definition() {
"edited" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"start" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"finish" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"summary" => array("type" => "text", "not null" => "1"),
"desc" => array("type" => "text", "not null" => "1"),
"location" => array("type" => "text", "not null" => "1"),
"summary" => array("type" => "text"),
"desc" => array("type" => "text"),
"location" => array("type" => "text"),
"type" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"nofinish" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"adjust" => array("type" => "tinyint(1)", "not null" => "1", "default" => "1"),
"ignore" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "0"),
"allow_cid" => array("type" => "mediumtext", "not null" => "1"),
"allow_gid" => array("type" => "mediumtext", "not null" => "1"),
"deny_cid" => array("type" => "mediumtext", "not null" => "1"),
"deny_gid" => array("type" => "mediumtext", "not null" => "1"),
"allow_cid" => array("type" => "mediumtext"),
"allow_gid" => array("type" => "mediumtext"),
"deny_cid" => array("type" => "mediumtext"),
"deny_gid" => array("type" => "mediumtext"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -568,6 +620,7 @@ function db_definition() {
$database["fcontact"] = array(
"fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"guid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"photo" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@ -581,7 +634,7 @@ function db_definition() {
"priority" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"network" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"alias" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"pubkey" => array("type" => "text", "not null" => "1"),
"pubkey" => array("type" => "text"),
"updated" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
),
"indexes" => array(
@ -605,7 +658,7 @@ function db_definition() {
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"server" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"posturl" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"key" => array("type" => "text", "not null" => "1"),
"key" => array("type" => "text"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -621,7 +674,7 @@ function db_definition() {
"url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"request" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"photo" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"note" => array("type" => "text", "not null" => "1"),
"note" => array("type" => "text"),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
),
"indexes" => array(
@ -654,16 +707,17 @@ function db_definition() {
"last_contact" => array("type" => "datetime", "default" => "0000-00-00 00:00:00"),
"last_failure" => array("type" => "datetime", "default" => "0000-00-00 00:00:00"),
"location" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"about" => array("type" => "text", "not null" => "1"),
"keywords" => array("type" => "text", "not null" => "1"),
"about" => array("type" => "text"),
"keywords" => array("type" => "text"),
"gender" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"birthday" => array("type" => "varchar(32)", "not null" => "1", "default" => "0000-00-00"),
"community" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"contact-type" => array("type" => "tinyint(1)", "not null" => "1", "default" => "-1"),
"hide" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"nsfw" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"network" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"addr" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"notify" => array("type" => "text", "not null" => "1"),
"notify" => array("type" => "text"),
"alias" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"generation" => array("type" => "tinyint(3)", "not null" => "1", "default" => "0"),
"server_url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@ -725,7 +779,7 @@ function db_definition() {
"nurl" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"version" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"site_name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"info" => array("type" => "text", "not null" => "1"),
"info" => array("type" => "text"),
"register_policy" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"poco" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"noscrape" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@ -762,7 +816,7 @@ function db_definition() {
"contact-id" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"knowyou" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"duplex" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"note" => array("type" => "text", "not null" => "1"),
"note" => array("type" => "text"),
"hash" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"datetime" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"blocked" => array("type" => "tinyint(1)", "not null" => "1", "default" => "1"),
@ -792,34 +846,36 @@ function db_definition() {
"commented" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"received" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"changed" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"owner-id" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"owner-name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"owner-link" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"owner-avatar" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"author-id" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"author-name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"author-link" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"author-avatar" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"title" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"body" => array("type" => "mediumtext", "not null" => "1"),
"body" => array("type" => "mediumtext"),
"app" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"verb" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"object-type" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"object" => array("type" => "text", "not null" => "1"),
"object" => array("type" => "text"),
"target-type" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"target" => array("type" => "text", "not null" => "1"),
"postopts" => array("type" => "text", "not null" => "1"),
"target" => array("type" => "text"),
"postopts" => array("type" => "text"),
"plink" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"resource-id" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"event-id" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"tag" => array("type" => "mediumtext", "not null" => "1"),
"attach" => array("type" => "mediumtext", "not null" => "1"),
"inform" => array("type" => "mediumtext", "not null" => "1"),
"file" => array("type" => "mediumtext", "not null" => "1"),
"tag" => array("type" => "mediumtext"),
"attach" => array("type" => "mediumtext"),
"inform" => array("type" => "mediumtext"),
"file" => array("type" => "mediumtext"),
"location" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"coord" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"allow_cid" => array("type" => "mediumtext", "not null" => "1"),
"allow_gid" => array("type" => "mediumtext", "not null" => "1"),
"deny_cid" => array("type" => "mediumtext", "not null" => "1"),
"deny_gid" => array("type" => "mediumtext", "not null" => "1"),
"allow_cid" => array("type" => "mediumtext"),
"allow_gid" => array("type" => "mediumtext"),
"deny_cid" => array("type" => "mediumtext"),
"deny_gid" => array("type" => "mediumtext"),
"private" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"pubmail" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"moderated" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
@ -835,7 +891,7 @@ function db_definition() {
"mention" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"network" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"rendered-hash" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"rendered-html" => array("type" => "mediumtext", "not null" => "1"),
"rendered-html" => array("type" => "mediumtext"),
"global" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
),
"indexes" => array(
@ -855,15 +911,18 @@ function db_definition() {
"uid_title" => array("uid","title"),
"uid_thrparent" => array("uid","thr-parent"),
"uid_parenturi" => array("uid","parent-uri"),
"uid_contactid_id" => array("uid","contact-id","id"),
"uid_contactid_created" => array("uid","contact-id","created"),
"gcontactid_uid_created" => array("gcontact-id","uid","created"),
"authorid_created" => array("author-id","created"),
"ownerid_created" => array("owner-id","created"),
"wall_body" => array("wall","body(6)"),
"uid_visible_moderated_created" => array("uid","visible","moderated","created"),
"uid_uri" => array("uid","uri"),
"uid_uri" => array("uid", "uri"),
"uid_wall_created" => array("uid","wall","created"),
"resource-id" => array("resource-id"),
"uid_type" => array("uid","type"),
"uid_starred" => array("uid","starred"),
"uid_starred_id" => array("uid","starred", "id"),
"contactid_allowcid_allowpid_denycid_denygid" => array("contact-id","allow_cid(10)","allow_gid(10)","deny_cid(10)","deny_gid(10)"),
"uid_wall_parent_created" => array("uid","wall","parent","created"),
"uid_type_changed" => array("uid","type","changed"),
@ -913,7 +972,7 @@ function db_definition() {
"contact-id" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"convid" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"title" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"body" => array("type" => "mediumtext", "not null" => "1"),
"body" => array("type" => "mediumtext"),
"seen" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"reply" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"replied" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
@ -941,7 +1000,7 @@ function db_definition() {
"ssltype" => array("type" => "varchar(16)", "not null" => "1", "default" => ""),
"mailbox" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"user" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"pass" => array("type" => "text", "not null" => "1"),
"pass" => array("type" => "text"),
"reply_to" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"action" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"movetofolder" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@ -972,7 +1031,7 @@ function db_definition() {
"url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"photo" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"date" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"msg" => array("type" => "mediumtext", "not null" => "1"),
"msg" => array("type" => "mediumtext"),
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"link" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"iid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
@ -980,6 +1039,8 @@ function db_definition() {
"seen" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"verb" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"otype" => array("type" => "varchar(16)", "not null" => "1", "default" => ""),
"name_cache" => array("type" => "tinytext"),
"msg_cache" => array("type" => "mediumtext")
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -1003,11 +1064,11 @@ function db_definition() {
$database["oembed"] = array(
"fields" => array(
"url" => array("type" => "varchar(255)", "not null" => "1", "primary" => "1"),
"content" => array("type" => "text", "not null" => "1"),
"content" => array("type" => "text"),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
),
"indexes" => array(
"PRIMARY" => array("url"),
"PRIMARY" => array("url".db_index_suffix($charset)),
"created" => array("created"),
)
);
@ -1016,11 +1077,11 @@ function db_definition() {
"url" => array("type" => "varchar(255)", "not null" => "1", "primary" => "1"),
"guessing" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0", "primary" => "1"),
"oembed" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0", "primary" => "1"),
"content" => array("type" => "text", "not null" => "1"),
"content" => array("type" => "text"),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
),
"indexes" => array(
"PRIMARY" => array("url", "guessing", "oembed"),
"PRIMARY" => array("url".db_index_suffix($charset), "guessing", "oembed"),
"created" => array("created"),
)
);
@ -1030,11 +1091,11 @@ function db_definition() {
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"cat" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"k" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"v" => array("type" => "mediumtext", "not null" => "1"),
"v" => array("type" => "mediumtext"),
),
"indexes" => array(
"PRIMARY" => array("id"),
"uid_cat_k" => array("uid","cat(30)","k(30)"),
"uid_cat_k" => array("UNIQUE", "uid","cat(30)","k(30)"),
)
);
$database["photo"] = array(
@ -1047,7 +1108,7 @@ function db_definition() {
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"edited" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"title" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"desc" => array("type" => "text", "not null" => "1"),
"desc" => array("type" => "text"),
"album" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"filename" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"type" => array("type" => "varchar(128)", "not null" => "1", "default" => "image/jpeg"),
@ -1057,14 +1118,16 @@ function db_definition() {
"data" => array("type" => "mediumblob", "not null" => "1"),
"scale" => array("type" => "tinyint(3)", "not null" => "1", "default" => "0"),
"profile" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"allow_cid" => array("type" => "mediumtext", "not null" => "1"),
"allow_gid" => array("type" => "mediumtext", "not null" => "1"),
"deny_cid" => array("type" => "mediumtext", "not null" => "1"),
"deny_gid" => array("type" => "mediumtext", "not null" => "1"),
"allow_cid" => array("type" => "mediumtext"),
"allow_gid" => array("type" => "mediumtext"),
"deny_cid" => array("type" => "mediumtext"),
"deny_gid" => array("type" => "mediumtext"),
),
"indexes" => array(
"PRIMARY" => array("id"),
"uid" => array("uid"),
"uid_contactid" => array("uid", "contact-id"),
"uid_profile" => array("uid", "profile"),
"uid_album_created" => array("uid", "album", "created"),
"resource-id" => array("resource-id"),
"guid" => array("guid"),
)
@ -1073,16 +1136,16 @@ function db_definition() {
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"q0" => array("type" => "mediumtext", "not null" => "1"),
"q1" => array("type" => "mediumtext", "not null" => "1"),
"q2" => array("type" => "mediumtext", "not null" => "1"),
"q3" => array("type" => "mediumtext", "not null" => "1"),
"q4" => array("type" => "mediumtext", "not null" => "1"),
"q5" => array("type" => "mediumtext", "not null" => "1"),
"q6" => array("type" => "mediumtext", "not null" => "1"),
"q7" => array("type" => "mediumtext", "not null" => "1"),
"q8" => array("type" => "mediumtext", "not null" => "1"),
"q9" => array("type" => "mediumtext", "not null" => "1"),
"q0" => array("type" => "mediumtext"),
"q1" => array("type" => "mediumtext"),
"q2" => array("type" => "mediumtext"),
"q3" => array("type" => "mediumtext"),
"q4" => array("type" => "mediumtext"),
"q5" => array("type" => "mediumtext"),
"q6" => array("type" => "mediumtext"),
"q7" => array("type" => "mediumtext"),
"q8" => array("type" => "mediumtext"),
"q9" => array("type" => "mediumtext"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -1101,6 +1164,17 @@ function db_definition() {
"choice" => array("choice"),
)
);
$database["process"] = array(
"fields" => array(
"pid" => array("type" => "int(10) unsigned", "not null" => "1", "primary" => "1"),
"command" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
),
"indexes" => array(
"PRIMARY" => array("pid"),
"command" => array("command"),
)
);
$database["profile"] = array(
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
@ -1119,27 +1193,28 @@ function db_definition() {
"hometown" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"gender" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"marital" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"with" => array("type" => "text", "not null" => "1"),
"with" => array("type" => "text"),
"howlong" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"sexual" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"politic" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"religion" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"pub_keywords" => array("type" => "text", "not null" => "1"),
"prv_keywords" => array("type" => "text", "not null" => "1"),
"likes" => array("type" => "text", "not null" => "1"),
"dislikes" => array("type" => "text", "not null" => "1"),
"about" => array("type" => "text", "not null" => "1"),
"pub_keywords" => array("type" => "text"),
"prv_keywords" => array("type" => "text"),
"likes" => array("type" => "text"),
"dislikes" => array("type" => "text"),
"about" => array("type" => "text"),
"summary" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"music" => array("type" => "text", "not null" => "1"),
"book" => array("type" => "text", "not null" => "1"),
"tv" => array("type" => "text", "not null" => "1"),
"film" => array("type" => "text", "not null" => "1"),
"interest" => array("type" => "text", "not null" => "1"),
"romance" => array("type" => "text", "not null" => "1"),
"work" => array("type" => "text", "not null" => "1"),
"education" => array("type" => "text", "not null" => "1"),
"contact" => array("type" => "text", "not null" => "1"),
"music" => array("type" => "text"),
"book" => array("type" => "text"),
"tv" => array("type" => "text"),
"film" => array("type" => "text"),
"interest" => array("type" => "text"),
"romance" => array("type" => "text"),
"work" => array("type" => "text"),
"education" => array("type" => "text"),
"contact" => array("type" => "text"),
"homepage" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"xmpp" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"photo" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"thumb" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"publish" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
@ -1185,7 +1260,7 @@ function db_definition() {
"network" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"last" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"content" => array("type" => "mediumtext", "not null" => "1"),
"content" => array("type" => "mediumtext"),
"batch" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
),
"indexes" => array(
@ -1226,7 +1301,7 @@ function db_definition() {
"fields" => array(
"id" => array("type" => "bigint(20) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"sid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"data" => array("type" => "text", "not null" => "1"),
"data" => array("type" => "text"),
"expire" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
),
"indexes" => array(
@ -1239,8 +1314,8 @@ function db_definition() {
"fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"iid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
"signed_text" => array("type" => "mediumtext", "not null" => "1"),
"signature" => array("type" => "text", "not null" => "1"),
"signed_text" => array("type" => "mediumtext"),
"signature" => array("type" => "text"),
"signer" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
),
"indexes" => array(
@ -1287,6 +1362,7 @@ function db_definition() {
"type_term" => array("type","term"),
"uid_otype_type_term_global_created" => array("uid","otype","type","term","global","created"),
"otype_type_term_tid" => array("otype","type","term","tid"),
"uid_otype_type_url" => array("uid","otype","type","url"),
"guid" => array("guid"),
)
);
@ -1296,6 +1372,8 @@ function db_definition() {
"uid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
"contact-id" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"gcontact-id" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"owner-id" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"author-id" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"edited" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"commented" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
@ -1335,7 +1413,7 @@ function db_definition() {
$database["tokens"] = array(
"fields" => array(
"id" => array("type" => "varchar(40)", "not null" => "1", "primary" => "1"),
"secret" => array("type" => "text", "not null" => "1"),
"secret" => array("type" => "text"),
"client_id" => array("type" => "varchar(20)", "not null" => "1", "default" => ""),
"expires" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"scope" => array("type" => "varchar(200)", "not null" => "1", "default" => ""),
@ -1361,10 +1439,10 @@ function db_definition() {
"default-location" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"allow_location" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"theme" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"pubkey" => array("type" => "text", "not null" => "1"),
"prvkey" => array("type" => "text", "not null" => "1"),
"spubkey" => array("type" => "text", "not null" => "1"),
"sprvkey" => array("type" => "text", "not null" => "1"),
"pubkey" => array("type" => "text"),
"prvkey" => array("type" => "text"),
"spubkey" => array("type" => "text"),
"sprvkey" => array("type" => "text"),
"verified" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "0"),
"blocked" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "0"),
"blockwall" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "0"),
@ -1374,6 +1452,7 @@ function db_definition() {
"cntunkmail" => array("type" => "int(11)", "not null" => "1", "default" => "10"),
"notify-flags" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "65535"),
"page-flags" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"account-type" => array("type" => "int(11) unsigned", "not null" => "1", "default" => "0"),
"prvnets" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"pwdreset" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"maxreq" => array("type" => "int(11)", "not null" => "1", "default" => "10"),
@ -1384,11 +1463,11 @@ function db_definition() {
"expire_notification_sent" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"service_class" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"def_gid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"allow_cid" => array("type" => "mediumtext", "not null" => "1"),
"allow_gid" => array("type" => "mediumtext", "not null" => "1"),
"deny_cid" => array("type" => "mediumtext", "not null" => "1"),
"deny_gid" => array("type" => "mediumtext", "not null" => "1"),
"openidserver" => array("type" => "text", "not null" => "1"),
"allow_cid" => array("type" => "mediumtext"),
"allow_gid" => array("type" => "mediumtext"),
"deny_cid" => array("type" => "mediumtext"),
"deny_gid" => array("type" => "mediumtext"),
"openidserver" => array("type" => "text"),
),
"indexes" => array(
"PRIMARY" => array("uid"),
@ -1408,7 +1487,7 @@ function db_definition() {
$database["workerqueue"] = array(
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"parameter" => array("type" => "text", "not null" => "1"),
"parameter" => array("type" => "text"),
"priority" => array("type" => "tinyint(3) unsigned", "not null" => "1", "default" => "0"),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"pid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
@ -1443,11 +1522,33 @@ function dbstructure_run(&$argv, &$argc) {
if ($argc==2) {
switch ($argv[1]) {
case "dryrun":
update_structure(true, false);
return;
case "update":
update_structure(true, true);
$build = get_config('system','build');
if (!x($build)) {
set_config('system','build',DB_UPDATE_VERSION);
$build = DB_UPDATE_VERSION;
}
$stored = intval($build);
$current = intval(DB_UPDATE_VERSION);
// run any left update_nnnn functions in update.php
for($x = $stored; $x < $current; $x ++) {
$r = run_update_function($x);
if (!$r) break;
}
set_config('system','build',DB_UPDATE_VERSION);
return;
case "dumpsql":
print_structure(db_definition());
// For the dump that is used to create the database.sql we always assume utfmb4
$charset = "utf8mb4";
print_structure(db_definition($charset), $charset);
return;
}
}
@ -1456,7 +1557,8 @@ function dbstructure_run(&$argv, &$argc) {
// print help
echo $argv[0]." <command>\n";
echo "\n";
echo "commands:\n";
echo "Commands:\n";
echo "dryrun show database update schema queries without running them\n";
echo "update update database schema\n";
echo "dumpsql dump database schema\n";
return;

View file

@ -178,7 +178,7 @@ function delivery_run(&$argv, &$argc){
$r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
`user`.`page-flags`, `user`.`prvnets`
`user`.`page-flags`, `user`.`account-type`, `user`.`prvnets`
FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
intval($uid)

View file

@ -98,9 +98,9 @@ class dfrn {
$sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' ";
$r = q("SELECT `contact`.*, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`
$r = q("SELECT `contact`.*, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`, `user`.`account-type`
FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1",
WHERE `contact`.`self` AND `user`.`nickname` = '%s' LIMIT 1",
dbesc($owner_nick)
);
@ -112,7 +112,6 @@ class dfrn {
$owner_nick = $owner['nickname'];
$sql_post_table = "";
$visibility = "";
if(! $public_feed) {
@ -171,9 +170,6 @@ class dfrn {
else
$sort = 'ASC';
$date_field = "`changed`";
$sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC";
if(! strlen($last_update))
$last_update = 'now -30 days';
@ -190,22 +186,19 @@ class dfrn {
$check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
// AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' )
// dbesc($check_date),
$r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`,
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
`contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`,
`contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`,
`contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
`sign`.`signed_text`, `sign`.`signature`, `sign`.`signer`
FROM `item` $sql_post_table
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
FROM `item` USE INDEX (`uid_wall_changed`, `uid_type_changed`) $sql_post_table
STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
AND NOT `contact`.`blocked`
LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0
AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s'
WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`moderated` AND `item`.`parent` != 0
AND `item`.`wall` AND `item`.`changed` > '%s'
$sql_extra
ORDER BY $sql_order LIMIT 0, 300",
ORDER BY `item`.`parent` ".$sort.", `item`.`created` ASC LIMIT 0, 300",
intval($owner_id),
dbesc($check_date),
dbesc($sort)
@ -369,6 +362,7 @@ class dfrn {
xml::add_element($doc, $relocate, "dfrn:url", $owner['url']);
xml::add_element($doc, $relocate, "dfrn:name", $owner['name']);
xml::add_element($doc, $relocate, "dfrn:addr", $owner['addr']);
xml::add_element($doc, $relocate, "dfrn:avatar", $owner['avatar']);
xml::add_element($doc, $relocate, "dfrn:photo", $photos[4]);
xml::add_element($doc, $relocate, "dfrn:thumb", $photos[5]);
xml::add_element($doc, $relocate, "dfrn:micro", $photos[6]);
@ -439,9 +433,13 @@ class dfrn {
xml::add_element($doc, $root, "link", "", $attributes);
}
// For backward compatibility we keep this element
if ($owner['page-flags'] == PAGE_COMMUNITY)
xml::add_element($doc, $root, "dfrn:community", 1);
// The former element is replaced by this one
xml::add_element($doc, $root, "dfrn:account_type", $owner["account-type"]);
/// @todo We need a way to transmit the different page flags like "PAGE_PRVGROUP"
xml::add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME));
@ -511,14 +509,16 @@ class dfrn {
xml::add_element($doc, $author, "dfrn:birthday", $birthday);
// Only show contact details when we are allowed to
$r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `user`.`nickname`, `user`.`timezone`,
`profile`.`locality`, `profile`.`region`, `profile`.`country-name`, `profile`.`pub_keywords`, `profile`.`dob`
$r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `user`.`nickname`,
`user`.`timezone`, `profile`.`locality`, `profile`.`region`, `profile`.`country-name`,
`profile`.`pub_keywords`, `profile`.`xmpp`, `profile`.`dob`
FROM `profile`
INNER JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `profile`.`is-default` AND NOT `user`.`hidewall` AND `user`.`uid` = %d",
intval($owner['uid']));
if ($r) {
$profile = $r[0];
xml::add_element($doc, $author, "poco:displayName", $profile["name"]);
xml::add_element($doc, $author, "poco:updated", $namdate);
@ -549,12 +549,10 @@ class dfrn {
}
/// @todo When we are having the XMPP address in the profile we should propagate it here
$xmpp = "";
if (trim($xmpp) != "") {
if (trim($profile["xmpp"]) != "") {
$ims = $doc->createElement("poco:ims");
xml::add_element($doc, $ims, "poco:type", "xmpp");
xml::add_element($doc, $ims, "poco:value", $xmpp);
xml::add_element($doc, $ims, "poco:value", $profile["xmpp"]);
xml::add_element($doc, $ims, "poco:primary", "true");
$author->appendChild($ims);
}
@ -1142,7 +1140,7 @@ class dfrn {
$author["link"] = $xpath->evaluate($element."/atom:uri/text()", $context)->item(0)->nodeValue;
$r = q("SELECT `id`, `uid`, `url`, `network`, `avatar-date`, `name-date`, `uri-date`, `addr`,
`name`, `nick`, `about`, `location`, `keywords`, `bdyear`, `bd`, `hidden`
`name`, `nick`, `about`, `location`, `keywords`, `xmpp`, `bdyear`, `bd`, `hidden`, `contact-type`
FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
intval($importer["uid"]), dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET));
if ($r) {
@ -1218,9 +1216,13 @@ class dfrn {
if ($value != "")
$poco["location"] = $value;
/// @todo Only search for elements with "poco:type" = "xmpp"
$value = $xpath->evaluate($element."/poco:ims/poco:value/text()", $context)->item(0)->nodeValue;
if ($value != "")
$poco["xmpp"] = $value;
/// @todo Add support for the following fields that we don't support by now in the contact table:
/// - poco:utcOffset
/// - poco:ims
/// - poco:urls
/// - poco:locality
/// - poco:region
@ -1307,12 +1309,13 @@ class dfrn {
q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s',
`addr` = '%s', `keywords` = '%s', `bdyear` = '%s', `bd` = '%s', `hidden` = %d,
`name-date` = '%s', `uri-date` = '%s'
`xmpp` = '%s', `name-date` = '%s', `uri-date` = '%s'
WHERE `id` = %d AND `network` = '%s'",
dbesc($contact["name"]), dbesc($contact["nick"]), dbesc($contact["about"]), dbesc($contact["location"]),
dbesc($contact["addr"]), dbesc($contact["keywords"]), dbesc($contact["bdyear"]),
dbesc($contact["bd"]), intval($contact["hidden"]), dbesc($contact["name-date"]),
dbesc($contact["uri-date"]), intval($contact["id"]), dbesc($contact["network"]));
dbesc($contact["bd"]), intval($contact["hidden"]), dbesc($contact["xmpp"]),
dbesc($contact["name-date"]), dbesc($contact["uri-date"]),
intval($contact["id"]), dbesc($contact["network"]));
}
update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"],
@ -1326,6 +1329,7 @@ class dfrn {
$poco["generation"] = 2;
$poco["photo"] = $author["avatar"];
$poco["hide"] = $hide;
$poco["contact-type"] = $contact["contact-type"];
update_gcontact($poco);
}
@ -1548,6 +1552,7 @@ class dfrn {
$relocate["url"] = $xpath->query("dfrn:url/text()", $relocation)->item(0)->nodeValue;
$relocate["addr"] = $xpath->query("dfrn:addr/text()", $relocation)->item(0)->nodeValue;
$relocate["name"] = $xpath->query("dfrn:name/text()", $relocation)->item(0)->nodeValue;
$relocate["avatar"] = $xpath->query("dfrn:avatar/text()", $relocation)->item(0)->nodeValue;
$relocate["photo"] = $xpath->query("dfrn:photo/text()", $relocation)->item(0)->nodeValue;
$relocate["thumb"] = $xpath->query("dfrn:thumb/text()", $relocation)->item(0)->nodeValue;
$relocate["micro"] = $xpath->query("dfrn:micro/text()", $relocation)->item(0)->nodeValue;
@ -1557,6 +1562,9 @@ class dfrn {
$relocate["poll"] = $xpath->query("dfrn:poll/text()", $relocation)->item(0)->nodeValue;
$relocate["sitepubkey"] = $xpath->query("dfrn:sitepubkey/text()", $relocation)->item(0)->nodeValue;
if (($relocate["avatar"] == "") AND ($relocate["photo"] != ""))
$relocate["avatar"] = $relocate["photo"];
if ($relocate["addr"] == "")
$relocate["addr"] = preg_replace("=(https?://)(.*)/profile/(.*)=ism", "$3@$2", $relocate["url"]);
@ -1583,7 +1591,7 @@ class dfrn {
`server_url` = '%s'
WHERE `nurl` = '%s';",
dbesc($relocate["name"]),
dbesc($relocate["photo"]),
dbesc($relocate["avatar"]),
dbesc($relocate["url"]),
dbesc(normalise_link($relocate["url"])),
dbesc($relocate["addr"]),
@ -1595,9 +1603,7 @@ class dfrn {
// Update the contact table. We try to find every entry.
$x = q("UPDATE `contact` SET
`name` = '%s',
`photo` = '%s',
`thumb` = '%s',
`micro` = '%s',
`avatar` = '%s',
`url` = '%s',
`nurl` = '%s',
`addr` = '%s',
@ -1608,9 +1614,7 @@ class dfrn {
`site-pubkey` = '%s'
WHERE (`id` = %d AND `uid` = %d) OR (`nurl` = '%s');",
dbesc($relocate["name"]),
dbesc($relocate["photo"]),
dbesc($relocate["thumb"]),
dbesc($relocate["micro"]),
dbesc($relocate["avatar"]),
dbesc($relocate["url"]),
dbesc(normalise_link($relocate["url"])),
dbesc($relocate["addr"]),
@ -1623,6 +1627,8 @@ class dfrn {
intval($importer["importer_uid"]),
dbesc(normalise_link($old["url"])));
update_contact_avatar($relocate["avatar"], $importer["importer_uid"], $importer["id"], true);
if ($x === false)
return false;
@ -1631,17 +1637,23 @@ class dfrn {
$fields = array(
'owner-link' => array($old["url"], $relocate["url"]),
'author-link' => array($old["url"], $relocate["url"]),
'owner-avatar' => array($old["photo"], $relocate["photo"]),
'author-avatar' => array($old["photo"], $relocate["photo"]),
//'owner-avatar' => array($old["photo"], $relocate["photo"]),
//'author-avatar' => array($old["photo"], $relocate["photo"]),
);
foreach ($fields as $n=>$f){
$x = q("UPDATE `item` SET `%s` = '%s' WHERE `%s` = '%s' AND `uid` = %d",
$n, dbesc($f[1]),
foreach ($fields as $n=>$f) {
$r = q("SELECT `id` FROM `item` WHERE `%s` = '%s' AND `uid` = %d LIMIT 1",
$n, dbesc($f[0]),
intval($importer["importer_uid"]));
if ($x === false)
return false;
if ($r) {
$x = q("UPDATE `item` SET `%s` = '%s' WHERE `%s` = '%s' AND `uid` = %d",
$n, dbesc($f[1]),
$n, dbesc($f[0]),
intval($importer["importer_uid"]));
if ($x === false)
return false;
}
}
/// @TODO
/// merge with current record, current contents have priority
@ -1683,7 +1695,7 @@ class dfrn {
$changed = true;
if ($entrytype == DFRN_REPLY_RC)
proc_run("php", "include/notifier.php","comment-import", $current["id"]);
proc_run(PRIORITY_HIGH, "include/notifier.php","comment-import", $current["id"]);
}
// update last-child if it changes
@ -2243,7 +2255,7 @@ class dfrn {
if($posted_id AND $parent AND ($entrytype == DFRN_REPLY_RC)) {
logger("Notifying followers about comment ".$posted_id, LOGGER_DEBUG);
proc_run("php", "include/notifier.php", "comment-import", $posted_id);
proc_run(PRIORITY_HIGH, "include/notifier.php", "comment-import", $posted_id);
}
return true;
@ -2414,7 +2426,7 @@ class dfrn {
if($entrytype == DFRN_REPLY_RC) {
logger("Notifying followers about deletion of post ".$item["id"], LOGGER_DEBUG);
proc_run("php", "include/notifier.php","drop", $item["id"]);
proc_run(PRIORITY_HIGH, "include/notifier.php","drop", $item["id"]);
}
}
}
@ -2474,7 +2486,19 @@ class dfrn {
logger("Import DFRN message for user ".$importer["uid"]." from contact ".$importer["id"], LOGGER_DEBUG);
// is it a public forum? Private forums aren't supported by now with this method
// The account type is new since 3.5.1
if ($xpath->query("/atom:feed/dfrn:account_type")->length > 0) {
$accounttype = intval($xpath->evaluate("/atom:feed/dfrn:account_type/text()", $context)->item(0)->nodeValue);
if ($accounttype != $importer["contact-type"])
q("UPDATE `contact` SET `contact-type` = %d WHERE `id` = %d",
intval($accounttype),
intval($importer["id"])
);
}
// is it a public forum? Private forums aren't supported with this method
// This is deprecated since 3.5.1
$forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue);
if ($forum != $importer["forum"])

View file

@ -2,6 +2,10 @@
/**
* @file include/diaspora.php
* @brief The implementation of the diaspora protocol
*
* The new protocol is described here: http://diaspora.github.io/diaspora_federation/index.html
* Currently this implementation here interprets the old and the new protocol and sends the old one.
* This will change in the future.
*/
require_once("include/items.php");
@ -100,6 +104,59 @@ class diaspora {
return($signature);
}
/**
* @brief verify the envelope and return the verified data
*
* @param string $envelope The magic envelope
*
* @return string verified data
*/
private function verify_magic_envelope($envelope) {
$basedom = parse_xml_string($envelope, false);
if (!is_object($basedom)) {
logger("Envelope is no XML file");
return false;
}
$children = $basedom->children('http://salmon-protocol.org/ns/magic-env');
if (sizeof($children) == 0) {
logger("XML has no children");
return false;
}
$handle = "";
$data = base64url_decode($children->data);
$type = $children->data->attributes()->type[0];
$encoding = $children->encoding;
$alg = $children->alg;
$sig = base64url_decode($children->sig);
$key_id = $children->sig->attributes()->key_id[0];
if ($key_id != "")
$handle = base64url_decode($key_id);
$b64url_data = base64url_encode($data);
$msg = str_replace(array("\n", "\r", " ", "\t"), array("", "", "", ""), $b64url_data);
$signable_data = $msg.".".base64url_encode($type).".".base64url_encode($encoding).".".base64url_encode($alg);
$key = self::key($handle);
$verify = rsa_verify($signable_data, $sig, $key);
if (!$verify) {
logger('Message did not verify. Discarding.');
return false;
}
return $data;
}
/**
* @brief: Decodes incoming Diaspora message
*
@ -233,7 +290,6 @@ class diaspora {
return array('message' => (string)$inner_decrypted,
'author' => unxmlify($author_link),
'key' => (string)$key);
}
@ -360,8 +416,10 @@ class diaspora {
$data = parse_xml_string($msg["message"], false);
if (!is_object($data))
if (!is_object($data)) {
logger("No valid XML ".$msg["message"], LOGGER_DEBUG);
return false;
}
$first_child = $data->getName();
@ -378,6 +436,8 @@ class diaspora {
$type = $element->getName();
$orig_type = $type;
logger("Got message type ".$type.": ".$msg["message"], LOGGER_DATA);
// All retractions are handled identically from now on.
// In the new version there will only be "retraction".
if (in_array($type, array("signed_retraction", "relayable_retraction")))
@ -422,11 +482,11 @@ class diaspora {
}
}
if ($fieldname == "author_signature")
if (($fieldname == "author_signature") AND ($entry != ""))
$author_signature = base64_decode($entry);
elseif ($fieldname == "parent_author_signature")
elseif (($fieldname == "parent_author_signature") AND ($entry != ""))
$parent_author_signature = base64_decode($entry);
elseif ($fieldname != "target_author_signature") {
elseif (!in_array($fieldname, array("author_signature", "parent_author_signature", "target_author_signature"))) {
if ($signed_data != "") {
$signed_data .= ";";
$signed_data_parent .= ";";
@ -451,19 +511,27 @@ class diaspora {
return true;
// No author_signature? This is a must, so we quit.
if (!isset($author_signature))
if (!isset($author_signature)) {
logger("No author signature for type ".$type." - Message: ".$msg["message"], LOGGER_DEBUG);
return false;
}
if (isset($parent_author_signature)) {
$key = self::key($msg["author"]);
if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256"))
if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256")) {
logger("No valid parent author signature for author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG);
return false;
}
}
$key = self::key($fields->author);
return rsa_verify($signed_data, $author_signature, $key, "sha256");
if (!rsa_verify($signed_data, $author_signature, $key, "sha256")) {
logger("No valid author signature for author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG);
return false;
} else
return true;
}
/**
@ -506,6 +574,9 @@ class diaspora {
$d = strtotime($person["updated"]." +00:00");
if ($d < strtotime("now - 14 days"))
$update = true;
if ($person["guid"] == "")
$update = true;
}
if (!$person OR $update) {
@ -539,6 +610,7 @@ class diaspora {
`request` = '%s',
`nick` = '%s',
`addr` = '%s',
`guid` = '%s',
`batch` = '%s',
`notify` = '%s',
`poll` = '%s',
@ -551,7 +623,8 @@ class diaspora {
dbesc($arr["photo"]),
dbesc($arr["request"]),
dbesc($arr["nick"]),
dbesc($arr["addr"]),
dbesc(strtolower($arr["addr"])),
dbesc($arr["guid"]),
dbesc($arr["batch"]),
dbesc($arr["notify"]),
dbesc($arr["poll"]),
@ -563,15 +636,16 @@ class diaspora {
dbesc($arr["network"])
);
} else {
$r = q("INSERT INTO `fcontact` (`url`,`name`,`photo`,`request`,`nick`,`addr`,
$r = q("INSERT INTO `fcontact` (`url`,`name`,`photo`,`request`,`nick`,`addr`, `guid`,
`batch`, `notify`,`poll`,`confirm`,`network`,`alias`,`pubkey`,`updated`)
VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')",
VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')",
dbesc($arr["url"]),
dbesc($arr["name"]),
dbesc($arr["photo"]),
dbesc($arr["request"]),
dbesc($arr["nick"]),
dbesc($arr["addr"]),
dbesc($arr["guid"]),
dbesc($arr["batch"]),
dbesc($arr["notify"]),
dbesc($arr["poll"]),
@ -603,7 +677,7 @@ class diaspora {
$r = q("SELECT `addr` FROM `gcontact` WHERE `id` = %d AND `addr` != ''",
intval($gcontact_id));
if ($r)
return $r[0]["addr"];
return strtolower($r[0]["addr"]);
}
$r = q("SELECT `network`, `addr`, `self`, `url`, `nick` FROM `contact` WHERE `id` = %d",
@ -623,7 +697,7 @@ class diaspora {
}
}
return $handle;
return strtolower($handle);
}
/**
@ -806,11 +880,30 @@ class diaspora {
if ($level > 5)
return false;
// This will work for Diaspora and newer Friendica servers
$source_url = $server."/p/".$guid.".xml";
$x = fetch_url($source_url);
if(!$x)
return false;
// This will work for new Diaspora servers and Friendica servers from 3.5
$source_url = $server."/fetch/post/".$guid;
logger("Fetch post from ".$source_url, LOGGER_DEBUG);
$envelope = fetch_url($source_url);
if($envelope) {
logger("Envelope was fetched.", LOGGER_DEBUG);
$x = self::verify_magic_envelope($envelope);
if (!$x)
logger("Envelope could not be verified.", LOGGER_DEBUG);
else
logger("Envelope was verified.", LOGGER_DEBUG);
} else
$x = false;
// This will work for older Diaspora and Friendica servers
if (!$x) {
$source_url = $server."/p/".$guid.".xml";
logger("Fetch post from ".$source_url, LOGGER_DEBUG);
$x = fetch_url($source_url);
if(!$x)
return false;
}
$source_xml = parse_xml_string($x, false);
@ -819,9 +912,11 @@ class diaspora {
if ($source_xml->post->reshare) {
// Reshare of a reshare - old Diaspora version
logger("Message is a reshare", LOGGER_DEBUG);
return self::message($source_xml->post->reshare->root_guid, $server, ++$level);
} elseif ($source_xml->getName() == "reshare") {
// Reshare of a reshare - new Diaspora version
logger("Message is a new reshare", LOGGER_DEBUG);
return self::message($source_xml->root_guid, $server, ++$level);
}
@ -834,8 +929,10 @@ class diaspora {
$author = (string)$source_xml->author;
// If this isn't a "status_message" then quit
if (!$author)
if (!$author) {
logger("Message doesn't seem to be a status message", LOGGER_DEBUG);
return false;
}
$msg = array("message" => $x, "author" => $author);
@ -981,6 +1078,23 @@ class diaspora {
return true;
}
/**
* @brief Fetch the uri from our database if we already have this item (maybe from ourselves)
*
* @param string $author Author handle
* @param string $guid Message guid
*
* @return string The constructed uri or the one from our database
*/
private function get_uri_from_guid($author, $guid) {
$r = q("SELECT `uri` FROM `item` WHERE `guid` = '%s' LIMIT 1", dbesc($guid));
if ($r)
return $r[0]["uri"];
else
return $author.":".$guid;
}
/**
* @brief Processes an incoming comment
*
@ -997,6 +1111,11 @@ class diaspora {
$text = unxmlify($data->text);
$author = notags(unxmlify($data->author));
if (isset($data->created_at))
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
else
$created_at = datetime_convert();
$contact = self::allowed_contact_by_handle($importer, $sender, true);
if (!$contact)
return false;
@ -1033,7 +1152,7 @@ class diaspora {
$datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
$datarray["guid"] = $guid;
$datarray["uri"] = $author.":".$guid;
$datarray["uri"] = self::get_uri_from_guid($author, $guid);
$datarray["type"] = "remote-comment";
$datarray["verb"] = ACTIVITY_POST;
@ -1043,6 +1162,8 @@ class diaspora {
$datarray["object-type"] = ACTIVITY_OBJ_COMMENT;
$datarray["object"] = $xml;
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at;
$datarray["body"] = diaspora2bb($text);
self::fetch_guid($datarray);
@ -1063,7 +1184,7 @@ class diaspora {
);
// notify others
proc_run("php", "include/notifier.php", "comment-import", $message_id);
proc_run(PRIORITY_HIGH, "include/notifier.php", "comment-import", $message_id);
}
return $message_id;
@ -1239,7 +1360,7 @@ class diaspora {
intval($importer["uid"]),
dbesc($guid),
dbesc($author),
dbesc(datetime_convert("UTC", "UTC", $created_at)),
dbesc($created_at),
dbesc(datetime_convert()),
dbesc($subject),
dbesc($participants)
@ -1370,7 +1491,7 @@ class diaspora {
$datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
$datarray["guid"] = $guid;
$datarray["uri"] = $author.":".$guid;
$datarray["uri"] = self::get_uri_from_guid($author, $guid);
$datarray["type"] = "activity";
$datarray["verb"] = $verb;
@ -1398,7 +1519,7 @@ class diaspora {
);
// notify others
proc_run("php", "include/notifier.php", "comment-import", $message_id);
proc_run(PRIORITY_HIGH, "include/notifier.php", "comment-import", $message_id);
}
return $message_id;
@ -1531,7 +1652,7 @@ class diaspora {
* @return bool Success
*/
private function receive_profile($importer, $data) {
$author = notags(unxmlify($data->author));
$author = strtolower(notags(unxmlify($data->author)));
$contact = self::contact_by_handle($importer["uid"], $author);
if (!$contact)
@ -1678,7 +1799,7 @@ class diaspora {
$i = item_store($arr);
if($i)
proc_run("php", "include/notifier.php", "activity", $i);
proc_run(PRIORITY_HIGH, "include/notifier.php", "activity", $i);
}
}
}
@ -1736,10 +1857,26 @@ class diaspora {
// That makes us friends.
if ($contact) {
if ($following AND $sharing) {
logger("Author ".$author." (Contact ".$contact["id"].") wants to have a bidirectional conection.", LOGGER_DEBUG);
self::receive_request_make_friend($importer, $contact);
// refetch the contact array
$contact = self::contact_by_handle($importer["uid"],$author);
// If we are now friends, we are sending a share message.
// Normally we needn't to do so, but the first message could have been vanished.
if (in_array($contact["rel"], array(CONTACT_IS_FRIEND, CONTACT_IS_FOLLOWER))) {
$u = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($importer["uid"]));
if($u) {
logger("Sending share message to author ".$author." - Contact: ".$contact["id"]." - User: ".$importer["uid"], LOGGER_DEBUG);
$ret = self::send_share($u[0], $contact);
}
}
return true;
} else /// @todo Handle all possible variations of adding and retracting of permissions
} else { /// @todo Handle all possible variations of adding and retracting of permissions
logger("Author ".$author." (Contact ".$contact["id"].") wants to change the relationship: Following: ".$following." - sharing: ".$sharing. "(By now unsupported)", LOGGER_DEBUG);
return false;
}
}
if (!$following AND $sharing AND in_array($importer["page-flags"], array(PAGE_SOAPBOX, PAGE_NORMAL))) {
@ -1748,6 +1885,12 @@ class diaspora {
} elseif (!$following AND !$sharing) {
logger("Author ".$author." doesn't want anything - and we don't know the author. Request is ignored.", LOGGER_DEBUG);
return false;
} elseif (!$following AND $sharing) {
logger("Author ".$author." wants to share with us.", LOGGER_DEBUG);
} elseif ($following AND $sharing) {
logger("Author ".$author." wants to have a bidirectional conection.", LOGGER_DEBUG);
} elseif ($following AND !$sharing) {
logger("Author ".$author." wants to listen to us.", LOGGER_DEBUG);
}
$ret = self::person_by_handle($author);
@ -1787,13 +1930,19 @@ class diaspora {
return;
}
logger("Author ".$author." was added as contact number ".$contact_record["id"].".", LOGGER_DEBUG);
$def_gid = get_default_group($importer['uid'], $ret["network"]);
if(intval($def_gid))
group_add_member($importer["uid"], "", $contact_record["id"], $def_gid);
update_contact_avatar($ret["photo"], $importer['uid'], $contact_record["id"], true);
if($importer["page-flags"] == PAGE_NORMAL) {
logger("Sending intra message for author ".$author.".", LOGGER_DEBUG);
$hash = random_string().(string)time(); // Generate a confirm_key
$ret = q("INSERT INTO `intro` (`uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`)
@ -1810,6 +1959,8 @@ class diaspora {
// automatic friend approval
logger("Does an automatic friend approval for author ".$author.".", LOGGER_DEBUG);
update_contact_avatar($contact_record["photo"],$importer["uid"],$contact_record["id"]);
// technically they are sharing with us (CONTACT_IS_SHARING),
@ -1838,8 +1989,13 @@ class diaspora {
);
$u = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($importer["uid"]));
if($u)
if($u) {
logger("Sending share message (Relation: ".$new_relation.") to author ".$author." - Contact: ".$contact_record["id"]." - User: ".$importer["uid"], LOGGER_DEBUG);
$ret = self::send_share($u[0], $contact_record);
// Send the profile data, maybe it weren't transmitted before
self::send_profile($importer["uid"], array($contact_record));
}
}
return true;
@ -1883,27 +2039,15 @@ class diaspora {
if (!$r) {
$server = "https://".substr($orig_author, strpos($orig_author, "@") + 1);
logger("1st try: reshared message ".$guid." will be fetched from original server: ".$server);
logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server);
$item_id = self::store_by_guid($guid, $server);
if (!$item_id) {
$server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
logger("2nd try: reshared message ".$guid." will be fetched from original server: ".$server);
logger("2nd try: reshared message ".$guid." will be fetched without SLL from the server ".$server);
$item_id = self::store_by_guid($guid, $server);
}
// Deactivated by now since there is a risk that someone could manipulate postings through this method
/* if (!$item_id) {
$server = "https://".substr($author, strpos($author, "@") + 1);
logger("3rd try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
$item_id = self::store_by_guid($guid, $server);
}
if (!$item_id) {
$server = "http://".substr($author, strpos($author, "@") + 1);
logger("4th try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
$item_id = self::store_by_guid($guid, $server);
}
*/
if ($item_id) {
$r = q("SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`,
`author-name`, `author-link`, `author-avatar`
@ -1938,7 +2082,7 @@ class diaspora {
$guid = notags(unxmlify($data->guid));
$author = notags(unxmlify($data->author));
$public = notags(unxmlify($data->public));
$created_at = notags(unxmlify($data->created_at));
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
$contact = self::allowed_contact_by_handle($importer, $author, false);
if (!$contact)
@ -1969,7 +2113,7 @@ class diaspora {
$datarray["owner-avatar"] = $datarray["author-avatar"];
$datarray["guid"] = $guid;
$datarray["uri"] = $datarray["parent-uri"] = $author.":".$guid;
$datarray["uri"] = $datarray["parent-uri"] = self::get_uri_from_guid($author, $guid);
$datarray["verb"] = ACTIVITY_POST;
$datarray["gravity"] = GRAVITY_PARENT;
@ -1985,7 +2129,7 @@ class diaspora {
$datarray["plink"] = self::plink($author, $guid);
$datarray["private"] = (($public == "false") ? 1 : 0);
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert("UTC", "UTC", $created_at);
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at;
$datarray["object-type"] = $original_item["object-type"];
@ -2025,12 +2169,6 @@ class diaspora {
if (!$r)
return false;
// Only delete it if the author really fits
if (!link_compare($r[0]["author-link"], $person["url"])) {
logger("Item author ".$r[0]["author-link"]." doesn't fit to expected contact ".$person["url"], LOGGER_DEBUG);
return false;
}
// Check if the sender is the thread owner
$p = q("SELECT `id`, `author-link`, `origin` FROM `item` WHERE `id` = %d",
intval($r[0]["parent"]));
@ -2054,7 +2192,7 @@ class diaspora {
// Now check if the retraction needs to be relayed by us
if($p[0]["origin"]) {
// notify others
proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
proc_run(PRIORITY_HIGH, "include/notifier.php", "drop", $r[0]["id"]);
}
return true;
@ -2112,12 +2250,11 @@ class diaspora {
* @return int The message id of the newly created item
*/
private function receive_status_message($importer, $data, $xml) {
$raw_message = unxmlify($data->raw_message);
$guid = notags(unxmlify($data->guid));
$author = notags(unxmlify($data->author));
$public = notags(unxmlify($data->public));
$created_at = notags(unxmlify($data->created_at));
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
$provider_display_name = notags(unxmlify($data->provider_display_name));
/// @todo enable support for polls
@ -2171,7 +2308,7 @@ class diaspora {
$datarray["owner-avatar"] = $datarray["author-avatar"];
$datarray["guid"] = $guid;
$datarray["uri"] = $datarray["parent-uri"] = $author.":".$guid;
$datarray["uri"] = $datarray["parent-uri"] = self::get_uri_from_guid($author, $guid);
$datarray["verb"] = ACTIVITY_POST;
$datarray["gravity"] = GRAVITY_PARENT;
@ -2185,7 +2322,7 @@ class diaspora {
$datarray["plink"] = self::plink($author, $guid);
$datarray["private"] = (($public == "false") ? 1 : 0);
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert("UTC", "UTC", $created_at);
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at;
if (isset($address["address"]))
$datarray["location"] = $address["address"];
@ -2227,6 +2364,40 @@ class diaspora {
return $nick."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
}
/**
* @brief Creates the envelope for the "fetch" endpoint
*
* @param string $msg The message that is to be transmitted
* @param array $user The record of the sender
*
* @return string The envelope
*/
public static function build_magic_envelope($msg, $user) {
$b64url_data = base64url_encode($msg);
$data = str_replace(array("\n", "\r", " ", "\t"), array("", "", "", ""), $b64url_data);
$key_id = base64url_encode(diaspora::my_handle($user));
$type = "application/xml";
$encoding = "base64url";
$alg = "RSA-SHA256";
$signable_data = $data.".".base64url_encode($type).".".base64url_encode($encoding).".".base64url_encode($alg);
$signature = rsa_sign($signable_data, $user["prvkey"]);
$sig = base64url_encode($signature);
$xmldata = array("me:env" => array("me:data" => $data,
"@attributes" => array("type" => $type),
"me:encoding" => $encoding,
"me:alg" => $alg,
"me:sig" => $sig,
"@attributes2" => array("key_id" => $key_id)));
$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
return xml::from_array($xmldata, $xml, false, $namespaces);
}
/**
* @brief Creates the envelope for a public message
*
@ -2258,11 +2429,11 @@ class diaspora {
$sig = base64url_encode($signature);
$xmldata = array("diaspora" => array("header" => array("author_id" => $handle),
"me:env" => array("me:encoding" => "base64url",
"me:alg" => "RSA-SHA256",
"me:data" => $data,
"@attributes" => array("type" => "application/xml"),
"me:sig" => $sig)));
"me:env" => array("me:encoding" => $encoding,
"me:alg" => $alg,
"me:data" => $data,
"@attributes" => array("type" => $type),
"me:sig" => $sig)));
$namespaces = array("" => "https://joindiaspora.com/protocol",
"me" => "http://salmon-protocol.org/ns/magic-env");
@ -2348,10 +2519,10 @@ class diaspora {
$cipher_json = base64_encode($encrypted_header_json_object);
$xmldata = array("diaspora" => array("encrypted_header" => $cipher_json,
"me:env" => array("me:encoding" => "base64url",
"me:alg" => "RSA-SHA256",
"me:env" => array("me:encoding" => $encoding,
"me:alg" => $alg,
"me:data" => $data,
"@attributes" => array("type" => "application/xml"),
"@attributes" => array("type" => $type),
"me:sig" => $sig)));
$namespaces = array("" => "https://joindiaspora.com/protocol",
@ -2469,6 +2640,20 @@ class diaspora {
}
/**
* @brief Build the post xml
*
* @param string $type The message type
* @param array $message The message data
*
* @return string The post XML
*/
public static function build_post_xml($type, $message) {
$data = array("XML" => array("post" => array($type => $message)));
return xml::from_array($data, $xml);
}
/**
* @brief Builds and transmit messages
*
@ -2484,13 +2669,15 @@ class diaspora {
*/
private function build_and_transmit($owner, $contact, $type, $message, $public_batch = false, $guid = "", $spool = false) {
$data = array("XML" => array("post" => array($type => $message)));
$msg = xml::from_array($data, $xml);
$msg = self::build_post_xml($type, $message);
logger('message: '.$msg, LOGGER_DATA);
logger('send guid '.$guid, LOGGER_DEBUG);
// Fallback if the private key wasn't transmitted in the expected field
if ($owner['uprvkey'] == "")
$owner['uprvkey'] = $owner['prvkey'];
$slap = self::build_message($msg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch);
if ($spool) {
@ -2517,6 +2704,8 @@ class diaspora {
$message = array("sender_handle" => self::my_handle($owner),
"recipient_handle" => $contact["addr"]);
logger("Send share ".print_r($message, true), LOGGER_DEBUG);
return self::build_and_transmit($owner, $contact, "request", $message);
}
@ -2534,6 +2723,8 @@ class diaspora {
"diaspora_handle" => self::my_handle($owner),
"type" => "Person");
logger("Send unshare ".print_r($message, true), LOGGER_DEBUG);
return self::build_and_transmit($owner, $contact, "retraction", $message);
}
@ -2618,16 +2809,16 @@ class diaspora {
}
/**
* @brief Sends a post
* @brief Create a post (status message or reshare)
*
* @param array $item The item that will be exported
* @param array $owner the array of the item owner
* @param array $contact Target of the communication
* @param bool $public_batch Is it a public post?
*
* @return int The result of the transmission
* @return array
* 'type' -> Message type ("status_message" or "reshare")
* 'message' -> Array of XML elements of the status
*/
public static function send_status($item, $owner, $contact, $public_batch = false) {
public static function build_status($item, $owner) {
$myaddr = self::my_handle($owner);
@ -2690,8 +2881,24 @@ class diaspora {
$type = "status_message";
}
return array("type" => $type, "message" => $message);
}
return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
/**
* @brief Sends a post
*
* @param array $item The item that will be exported
* @param array $owner the array of the item owner
* @param array $contact Target of the communication
* @param bool $public_batch Is it a public post?
*
* @return int The result of the transmission
*/
public static function send_status($item, $owner, $contact, $public_batch = false) {
$status = diaspora::build_status($item, $owner);
return self::build_and_transmit($owner, $contact, $status["type"], $status["message"], $public_batch, $item["guid"]);
}
/**
@ -3004,17 +3211,18 @@ class diaspora {
*
* @param int $uid The user id
*/
public static function send_profile($uid) {
public static function send_profile($uid, $recips = false) {
if (!$uid)
return;
$recips = q("SELECT `id`,`name`,`network`,`pubkey`,`notify` FROM `contact` WHERE `network` = '%s'
AND `uid` = %d AND `rel` != %d",
dbesc(NETWORK_DIASPORA),
intval($uid),
intval(CONTACT_IS_SHARING)
);
if (!$recips)
$recips = q("SELECT `id`,`name`,`network`,`pubkey`,`notify` FROM `contact` WHERE `network` = '%s'
AND `uid` = %d AND `rel` != %d",
dbesc(NETWORK_DIASPORA),
intval($uid),
intval(CONTACT_IS_SHARING)
);
if (!$recips)
return;
@ -3078,8 +3286,10 @@ class diaspora {
"searchable" => $searchable,
"tag_string" => $tags);
foreach($recips as $recip)
foreach($recips as $recip) {
logger("Send updated profile data for user ".$uid." to contact ".$recip["id"], LOGGER_DEBUG);
self::build_and_transmit($profile, $recip, "profile", $message, false, "", true);
}
}
/**

View file

@ -49,7 +49,7 @@ function notification($params) {
// with $params['show_in_notification_page'] == false, the notification isn't inserted into
// the database, and an email is sent if applicable.
// default, if not specified: true
$show_in_notification_page = ((x($params, 'show_in_notification_page')) ? $params['show_in_notification_page']:True);
$show_in_notification_page = ((x($params, 'show_in_notification_page')) ? $params['show_in_notification_page']:true);
$additional_mail_header = "";
$additional_mail_header .= "Precedence: list\n";
@ -418,6 +418,7 @@ function notification($params) {
$datarray = array();
$datarray['hash'] = $hash;
$datarray['name'] = $params['source_name'];
$datarray['name_cache'] = strip_tags(bbcode($params['source_name']));
$datarray['url'] = $params['source_link'];
$datarray['photo'] = $params['source_photo'];
$datarray['date'] = datetime_convert();
@ -439,8 +440,8 @@ function notification($params) {
// create notification entry in DB
$r = q("INSERT INTO `notify` (`hash`, `name`, `url`, `photo`, `date`, `uid`, `link`, `iid`, `parent`, `type`, `verb`, `otype`)
values('%s', '%s', '%s', '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s')",
$r = q("INSERT INTO `notify` (`hash`, `name`, `url`, `photo`, `date`, `uid`, `link`, `iid`, `parent`, `type`, `verb`, `otype`, `name_cache`)
values('%s', '%s', '%s', '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s')",
dbesc($datarray['hash']),
dbesc($datarray['name']),
dbesc($datarray['url']),
@ -452,7 +453,8 @@ function notification($params) {
intval($datarray['parent']),
intval($datarray['type']),
dbesc($datarray['verb']),
dbesc($datarray['otype'])
dbesc($datarray['otype']),
dbesc($datarray["name_cache"])
);
$r = q("SELECT `id` FROM `notify` WHERE `hash` = '%s' AND `uid` = %d LIMIT 1",
@ -494,8 +496,10 @@ function notification($params) {
$itemlink = $a->get_baseurl().'/notify/view/'.$notify_id;
$msg = replace_macros($epreamble, array('$itemlink' => $itemlink));
$r = q("UPDATE `notify` SET `msg` = '%s' WHERE `id` = %d AND `uid` = %d",
$msg_cache = format_notification_message($datarray['name_cache'], strip_tags(bbcode($msg)));
$r = q("UPDATE `notify` SET `msg` = '%s', `msg_cache` = '%s' WHERE `id` = %d AND `uid` = %d",
dbesc($msg),
dbesc($msg_cache),
intval($notify_id),
intval($params['uid'])
);
@ -778,4 +782,27 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
if (isset($params["type"]))
notification($params);
}
?>
/**
* @brief Formats a notification message with the notification author
*
* Replace the name with {0} but ensure to make that only once. The {0} is used
* later and prints the name in bold.
*
* @param string $name
* @param string $message
* @return string Formatted message
*/
function format_notification_message($name, $message) {
if ($name != '') {
$pos = strpos($message, $name);
} else {
$pos = false;
}
if ($pos !== false) {
$message = substr_replace($message, '{0}', $pos, strlen($name));
}
return $message;
}

View file

@ -1,12 +1,15 @@
<?php
/**
* @file include/event.php
* @brief functions specific to event handling
*/
require_once('include/bbcode.php');
require_once('include/map.php');
require_once('include/datetime.php');
function format_event_html($ev, $simple = false) {
if(! ((is_array($ev)) && count($ev)))
return '';
@ -290,7 +293,7 @@ function event_store($arr) {
`location` = '%s',
`type` = '%s',
`adjust` = %d,
`nofinish` = %d,
`nofinish` = %d
WHERE `id` = %d AND `uid` = %d",
dbesc($arr['edited']),
@ -427,3 +430,427 @@ function event_store($arr) {
return $item_id;
}
}
function get_event_strings() {
// First day of the week (0 = Sunday)
$firstDay = get_pconfig(local_user(),'system','first_day_of_week');
if ($firstDay === false) $firstDay=0;
$i18n = array(
"firstDay" => $firstDay,
"Sun" => t("Sun"),
"Mon" => t("Mon"),
"Tue" => t("Tue"),
"Wed" => t("Wed"),
"Thu" => t("Thu"),
"Fri" => t("Fri"),
"Sat" => t("Sat"),
"Sunday" => t("Sunday"),
"Monday" => t("Monday"),
"Tuesday" => t("Tuesday"),
"Wednesday" => t("Wednesday"),
"Thursday" => t("Thursday"),
"Friday" => t("Friday"),
"Saturday" => t("Saturday"),
"Jan" => t("Jan"),
"Feb" => t("Feb"),
"Mar" => t("Mar"),
"Apr" => t("Apr"),
"May" => t("May"),
"Jun" => t("Jun"),
"Jul" => t("Jul"),
"Aug" => t("Aug"),
"Sep" => t("Sept"),
"Oct" => t("Oct"),
"Nov" => t("Nov"),
"Dec" => t("Dec"),
"January" => t("January"),
"February" => t("February"),
"March" => t("March"),
"April" => t("April"),
"May" => t("May"),
"June" => t("June"),
"July" => t("July"),
"August" => t("August"),
"September" => t("September"),
"October" => t("October"),
"November" => t("November"),
"December" => t("December"),
"today" => t("today"),
"month" => t("month"),
"week" => t("week"),
"day" => t("day"),
"allday" => t("all-day"),
"noevent" => t("No events to display"),
"dtstart_label" => t("Starts:"),
"dtend_label" => t("Finishes:"),
"location_label" => t("Location:")
);
return $i18n;
}
/**
* @brief Get an event by its event ID
*
* @param type $owner_uid The User ID of the owner of the event
* @param type $event_params An assoziative array with
* int 'event_id' => The ID of the event in the event table
* @param type $sql_extra
* @return array Query result
*/
function event_by_id($owner_uid = 0, $event_params, $sql_extra = '') {
// ownly allow events if there is a valid owner_id
if($owner_uid == 0)
return;
// query for the event by event id
$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
STRAIGHT_JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
WHERE `event`.`uid` = %d AND `event`.`id` = %d $sql_extra",
intval($owner_uid),
intval($event_params["event_id"])
);
if(count($r))
return $r;
}
/**
* @brief Get all events in a specific timeframe
*
* @param int $owner_uid The User ID of the owner of the events
* @param array $event_params An assoziative array with
* int 'ignored' =>
* string 'start' => Start time of the timeframe
* string 'finish' => Finish time of the timeframe
* string 'adjust_start' =>
* string 'adjust_start' =>
*
* @param string $sql_extra Additional sql conditions (e.g. permission request)
* @return array Query results
*/
function events_by_date($owner_uid = 0, $event_params, $sql_extra = '') {
// ownly allow events if there is a valid owner_id
if($owner_uid == 0)
return;
// query for the event by date
$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
STRAIGHT_JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
WHERE `event`.`uid` = %d AND event.ignore = %d
AND ((`adjust` = 0 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s')
OR (`adjust` = 1 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s'))
$sql_extra ",
intval($owner_uid),
intval($event_params["ignored"]),
dbesc($event_params["start"]),
dbesc($event_params["start"]),
dbesc($event_params["finish"]),
dbesc($event_params["adjust_start"]),
dbesc($event_params["adjust_start"]),
dbesc($event_params["adjust_finish"])
);
if(count($r))
return $r;
}
/**
* @brief Convert an array query results in an arry which could be used by the events template
*
* @param array $arr Event query array
* @return array Event array for the template
*/
function process_events ($arr) {
$events=array();
$last_date = '';
$fmt = t('l, F j');
if (count($arr)) {
foreach($arr as $rr) {
$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
$d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], $fmt) : datetime_convert('UTC','UTC',$rr['start'],$fmt));
$d = day_translate($d);
$start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'c') : datetime_convert('UTC','UTC',$rr['start'],'c'));
if ($rr['nofinish']){
$end = null;
} else {
$end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['finish'], 'c') : datetime_convert('UTC','UTC',$rr['finish'],'c'));
}
$is_first = ($d !== $last_date);
$last_date = $d;
$edit = ((! $rr['cid']) ? array(App::get_baseurl().'/events/event/'.$rr['id'],t('Edit event'),'','') : null);
$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
if(! $title) {
list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
$title = strip_tags(html_entity_decode($title,ENT_QUOTES,'UTF-8'));
}
$html = format_event_html($rr);
$rr['desc'] = bbcode($rr['desc']);
$rr['location'] = bbcode($rr['location']);
$events[] = array(
'id'=>$rr['id'],
'start'=> $start,
'end' => $end,
'allDay' => false,
'title' => $title,
'j' => $j,
'd' => $d,
'is_first'=>$is_first,
'item'=>$rr,
'html'=>$html,
'plink' => array($rr['plink'],t('link to source'),'',''),
);
}
}
return $events;
}
/**
* @brief Format event to export format (ical/csv)
*
* @param array $events Query result for events
* @param string $format The output format (ical/csv)
* @param string $timezone The timezone of the user (not implemented yet)
*
* @return string Content according to selected export format
*/
function event_format_export ($events, $format = 'ical', $timezone) {
if(! ((is_array($events)) && count($events)))
return;
switch ($format) {
// format the exported data as a CSV file
case "csv":
header("Content-type: text/csv");
$o = '"Subject", "Start Date", "Start Time", "Description", "End Date", "End Time", "Location"' . PHP_EOL;
foreach ($events as $event) {
/// @todo the time / date entries don't include any information about the
// timezone the event is scheduled in :-/
$tmp1 = strtotime($event['start']);
$tmp2 = strtotime($event['finish']);
$time_format = "%H:%M:%S";
$date_format = "%Y-%m-%d";
$o .= '"'.$event['summary'].'", "'.strftime($date_format, $tmp1) .
'", "'.strftime($time_format, $tmp1).'", "'.$event['desc'] .
'", "'.strftime($date_format, $tmp2) .
'", "'.strftime($time_format, $tmp2) .
'", "'.$event['location'].'"' . PHP_EOL;
}
break;
// format the exported data as a ics file
case "ical":
header("Content-type: text/ics");
$o = 'BEGIN:VCALENDAR'. PHP_EOL
. 'VERSION:2.0' . PHP_EOL
. 'PRODID:-//friendica calendar export//0.1//EN' . PHP_EOL;
/// @todo include timezone informations in cases were the time is not in UTC
// see http://tools.ietf.org/html/rfc2445#section-4.8.3
// . 'BEGIN:VTIMEZONE' . PHP_EOL
// . 'TZID:' . $timezone . PHP_EOL
// . 'END:VTIMEZONE' . PHP_EOL;
// TODO instead of PHP_EOL CRLF should be used for long entries
// but test your solution against http://icalvalid.cloudapp.net/
// also long lines SHOULD be split at 75 characters length
foreach ($events as $event) {
if ($event['adjust'] == 1) {
$UTC = 'Z';
} else {
$UTC = '';
}
$o .= 'BEGIN:VEVENT' . PHP_EOL;
if ($event[start]) {
$tmp = strtotime($event['start']);
$dtformat = "%Y%m%dT%H%M%S".$UTC;
$o .= 'DTSTART:'.strftime($dtformat, $tmp).PHP_EOL;
}
if (!$event['nofinish']) {
$tmp = strtotime($event['finish']);
$dtformat = "%Y%m%dT%H%M%S".$UTC;
$o .= 'DTEND:'.strftime($dtformat, $tmp).PHP_EOL;
}
if ($event['summary'])
$tmp = $event['summary'];
$tmp = str_replace(PHP_EOL, PHP_EOL.' ',$tmp);
$tmp = addcslashes($tmp, ',;');
$o .= 'SUMMARY:' . $tmp . PHP_EOL;
if ($event['desc'])
$tmp = $event['desc'];
$tmp = str_replace(PHP_EOL, PHP_EOL.' ',$tmp);
$tmp = addcslashes($tmp, ',;');
$o .= 'DESCRIPTION:' . $tmp . PHP_EOL;
if ($event['location']) {
$tmp = $event['location'];
$tmp = str_replace(PHP_EOL, PHP_EOL.' ',$tmp);
$tmp = addcslashes($tmp, ',;');
$o .= 'LOCATION:' . $tmp . PHP_EOL;
}
$o .= 'END:VEVENT' . PHP_EOL;
$o .= PHP_EOL;
}
$o .= 'END:VCALENDAR' . PHP_EOL;
break;
}
return $o;
}
/**
* @brief Get all events for a user ID
*
* The query for events is done permission sensitive
* If the user is the owner of the calendar he/she
* will get all of his/her available events.
* If the user is only a visitor only the public events will
* be available
*
* @param int $uid The user ID
* @param int $sql_extra Additional sql conditions for permission
*
* @return array Query results
*/
function events_by_uid($uid = 0, $sql_extra = '') {
if($uid == 0)
return;
// The permission condition if no condition was transmitted
if($sql_extra == '')
$sql_extra = " AND `allow_cid` = '' AND `allow_gid` = '' ";
// does the user who requests happen to be the owner of the events
// requested? then show all of your events, otherwise only those that
// don't have limitations set in allow_cid and allow_gid
if (local_user() == $uid) {
$r = q("SELECT `start`, `finish`, `adjust`, `summary`, `desc`, `location`, `nofinish`
FROM `event` WHERE `uid`= %d AND `cid` = 0 ",
intval($uid)
);
} else {
$r = q("SELECT `start`, `finish`, `adjust`, `summary`, `desc`, `location`, `nofinish`
FROM `event` WHERE `uid`= %d AND `cid` = 0 $sql_extra ",
intval($uid)
);
}
if(count($r))
return $r;
}
/**
*
* @param int $uid The user ID
* @param string $format Output format (ical/csv)
* @return array With the results
* bool 'success' => True if the processing was successful
* string 'format' => The output format
* string 'extension' => The file extension of the output format
* string 'content' => The formatted output content
*
* @todo Respect authenticated users with events_by_uid()
*/
function event_export($uid, $format = 'ical') {
$process = false;
// we are allowed to show events
// get the timezone the user is in
$r = q("SELECT `timezone` FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
if (count($r))
$timezone = $r[0]['timezone'];
// get all events which are owned by a uid (respects permissions);
$events = events_by_uid($uid);
// we have the events that are available for the requestor
// now format the output according to the requested format
if(count($events))
$res = event_format_export($events, $format, $timezone);
// If there are results the precess was successfull
if(x($res))
$process = true;
// get the file extension for the format
switch ($format) {
case "ical":
$file_ext = "ics";
break;
case "csv":
$file_ext = "csv";
break;
default:
$file_ext = "";
}
$arr = array(
'success' => $process,
'format' => $format,
'extension' => $file_ext,
'content' => $res,
);
return $arr;
}
/**
* @brief Get the events widget
*
* @return string Formated html of the evens widget
*/
function widget_events() {
$a = get_app();
$owner_uid = $a->data['user']['uid'];
// $a->data is only available if the profile page is visited. If the visited page is not part
// of the profile page it should be the personal /events page. So we can use $a->user
$user = ($a->data['user']['nickname'] ? $a->data['user']['nickname'] : $a->user['nickname']);
// The permission testing is a little bit tricky because we have to respect many cases
// It's not the private events page (we don't get the $owner_uid for /events)
if(! local_user() && ! $owner_uid)
return;
// Cal logged in user (test permission at foreign profile page)
// If the $owner uid is available we know it is part of one of the profile pages (like /cal)
// So we have to test if if it's the own profile page of the logged in user
// or a foreign one. For foreign profile pages we need to check if the feature
// for exporting the cal is enabled (otherwise the widget would appear for logged in users
// on foreigen profile pages even if the widget is disabled)
if(intval($owner_uid) && local_user() !== $owner_uid && ! feature_enabled($owner_uid, "export_calendar"))
return;
// If it's a kind of profile page (intval($owner_uid)) return if the user not logged in and
// export feature isn't enabled
if(intval($owner_uid) && ! local_user() && ! feature_enabled($owner_uid, "export_calendar"))
return;
return replace_macros(get_markup_template("events_aside.tpl"), array(
'$etitle' => t("Export"),
'$export_ical' => t("Export calendar as ical"),
'$export_csv' => t("Export calendar as csv"),
'$user' => $user
));
}

View file

@ -64,6 +64,7 @@ function get_features($filtered = true) {
//array('expire', t('Content Expiration'), t('Remove old posts/comments after a period of time')),
array('multi_profiles', t('Multiple Profiles'), t('Ability to create multiple profiles'), false, get_config('feature_lock','multi_profiles')),
array('photo_location', t('Photo Location'), t('Photo metadata is normally stripped. This extracts the location (if present) prior to stripping metadata and links it to a map.'), false, get_config('feature_lock','photo_location')),
array('export_calendar', t('Export Public Calendar'), t('Ability for visitors to download the public calendar'), false, get_config('feature_lock','export_calendar')),
),
// Post composition
@ -71,7 +72,7 @@ function get_features($filtered = true) {
t('Post Composition Features'),
array('richtext', t('Richtext Editor'), t('Enable richtext editor'), false, get_config('feature_lock','richtext')),
array('preview', t('Post Preview'), t('Allow previewing posts and comments before publishing them'), false, get_config('feature_lock','preview')),
array('aclautomention', t('Auto-mention Forums'), t('Add/remove mention when a fourm page is selected/deselected in ACL window.'), false, get_config('feature_lock','aclautomention')),
array('aclautomention', t('Auto-mention Forums'), t('Add/remove mention when a forum page is selected/deselected in ACL window.'), false, get_config('feature_lock','aclautomention')),
),
// Network sidebar widgets

View file

@ -17,10 +17,15 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
$a = get_app();
logger("Import Atom/RSS feed", LOGGER_DEBUG);
if (!$simulate)
logger("Import Atom/RSS feed '".$contact["name"]."' (Contact ".$contact["id"].") for user ".$importer["uid"], LOGGER_DEBUG);
else
logger("Test Atom/RSS feed", LOGGER_DEBUG);
if ($xml == "")
if ($xml == "") {
logger('XML is empty.', LOGGER_DEBUG);
return;
}
$doc = new DOMDocument();
@$doc->loadXML($xml);
@ -54,8 +59,6 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
if ($attributes->name == "href")
$author["author-link"] = $attributes->textContent;
$author["author-id"] = $xpath->evaluate('/atom:feed/atom:author/atom:uri/text()')->item(0)->nodeValue;
if ($author["author-link"] == "")
$author["author-link"] = $author["author-id"];
@ -84,9 +87,22 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
if ($value != "")
$author["author-name"] = $value;
$value = $xpath->evaluate('atom:author/poco:preferredUsername/text()')->item(0)->nodeValue;
if ($value != "")
$author["author-nick"] = $value;
if ($simulate) {
$author["author-id"] = $xpath->evaluate('/atom:feed/atom:author/atom:uri/text()')->item(0)->nodeValue;
$value = $xpath->evaluate('atom:author/poco:preferredUsername/text()')->item(0)->nodeValue;
if ($value != "")
$author["author-nick"] = $value;
$value = $xpath->evaluate('atom:author/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue;
if ($value != "")
$author["author-location"] = $value;
$value = $xpath->evaluate('atom:author/poco:note/text()')->item(0)->nodeValue;
if ($value != "")
$author["author-about"] = $value;
}
$author["edited"] = $author["created"] = $xpath->query('/atom:feed/atom:updated/text()')->item(0)->nodeValue;
@ -126,10 +142,6 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
$author["owner-link"] = $contact["url"];
$author["owner-name"] = $contact["name"];
$author["owner-avatar"] = $contact["thumb"];
// This is no field in the item table. So we have to unset it.
unset($author["author-nick"]);
unset($author["author-id"]);
}
$header = array();
@ -150,8 +162,10 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
$header["last-child"] = 0;
}
if (!is_object($entries))
if (!is_object($entries)) {
logger("There are no entries in this feed.", LOGGER_DEBUG);
return;
}
$items = array();

View file

@ -270,7 +270,7 @@ function new_contact($uid,$url,$interactive = false) {
// pull feed and consume it, which should subscribe to the hub.
proc_run('php',"include/onepoll.php","$contact_id", "force");
proc_run(PRIORITY_HIGH, "include/onepoll.php", $contact_id, "force");
// create a follow slap

View file

@ -12,11 +12,11 @@ function gprobe_run(&$argv, &$argc){
}
if(is_null($db)) {
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
};
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
};
require_once('include/session.php');
require_once('include/datetime.php');
@ -39,14 +39,13 @@ function gprobe_run(&$argv, &$argc){
logger("gprobe start for ".normalise_link($url), LOGGER_DEBUG);
if (!count($r)) {
if (!dbm::is_result($r)) {
// Is it a DDoS attempt?
$urlparts = parse_url($url);
$result = Cache::get("gprobe:".$urlparts["host"]);
if (!is_null($result)) {
$result = unserialize($result);
if (in_array($result["network"], array(NETWORK_FEED, NETWORK_PHANTOM))) {
logger("DDoS attempt detected for ".$urlparts["host"]." by ".$_SERVER["REMOTE_ADDR"].". server data: ".print_r($_SERVER, true), LOGGER_DEBUG);
return;
@ -56,7 +55,7 @@ function gprobe_run(&$argv, &$argc){
$arr = probe_url($url);
if (is_null($result))
Cache::set("gprobe:".$urlparts["host"],serialize($arr));
Cache::set("gprobe:".$urlparts["host"], $arr);
if (!in_array($arr["network"], array(NETWORK_FEED, NETWORK_PHANTOM)))
update_gcontact($arr);
@ -65,7 +64,7 @@ function gprobe_run(&$argv, &$argc){
dbesc(normalise_link($url))
);
}
if(count($r)) {
if(dbm::is_result($r)) {
// Check for accessibility and do a poco discovery
if (poco_last_updated($r[0]['url'], true) AND ($r[0]["network"] == NETWORK_DFRN))
poco_load(0,0,$r[0]['id'], str_replace('/profile/','/poco/',$r[0]['url']));
@ -76,6 +75,6 @@ function gprobe_run(&$argv, &$argc){
}
if (array_search(__file__,get_included_files())===0){
gprobe_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
gprobe_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -71,8 +71,8 @@ function profile_load(&$a, $nickname, $profile = 0, $profiledata = array()) {
$a->page['title'] = $a->profile['name'] . " @ " . $a->config['sitename'];
// if (!$profiledata)
// $_SESSION['theme'] = $a->profile['theme'];
if (!$profiledata && !get_pconfig(local_user(),'system','always_my_theme'))
$_SESSION['theme'] = $a->profile['theme'];
$_SESSION['mobile-theme'] = $a->profile['mobile-theme'];
@ -149,17 +149,23 @@ function get_profiledata_by_nick($nickname, $uid = 0, $profile = 0) {
if($profile) {
$profile_int = intval($profile);
$r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* FROM `profile`
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = '%s' AND `profile`.`id` = %d AND `contact`.`self` = 1 LIMIT 1",
$r = q("SELECT `contact`.`id` AS `contact_id`, `profile`.`uid` AS `profile_uid`, `profile`.*,
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.*
FROM `profile`
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = '%s' AND `profile`.`id` = %d LIMIT 1",
dbesc($nickname),
intval($profile_int)
);
}
if((!$r) && (!count($r))) {
$r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* FROM `profile`
INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` = 1 AND `contact`.`self` = 1 LIMIT 1",
$r = q("SELECT `contact`.`id` AS `contact_id`, `profile`.`uid` AS `profile_uid`, `profile`.*,
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.*
FROM `profile`
INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` LIMIT 1",
dbesc($nickname)
);
}
@ -310,15 +316,8 @@ function profile_sidebar($profile, $block = 0) {
);
}
// check if profile is a forum
if((intval($profile['page-flags']) == PAGE_COMMUNITY)
|| (intval($profile['page-flags']) == PAGE_PRVGROUP)
|| (isset($profile['forum']) && intval($profile['forum']))
|| (isset($profile['prv']) && intval($profile['prv']))
|| (isset($profile['community']) && intval($profile['community'])))
$account_type = t('Forum');
else
$account_type = "";
// Fetch the account type
$account_type = account_type($profile);
if((x($profile,'address') == 1)
|| (x($profile,'location') == 1)
@ -337,6 +336,8 @@ function profile_sidebar($profile, $block = 0) {
$about = ((x($profile,'about') == 1) ? t('About:') : False);
$xmpp = ((x($profile,'xmpp') == 1) ? t('XMPP:') : False);
if(($profile['hidewall'] || $block) && (! local_user()) && (! remote_user())) {
$location = $pdesc = $gender = $marital = $homepage = $about = False;
}
@ -405,6 +406,7 @@ function profile_sidebar($profile, $block = 0) {
$tpl = get_markup_template('profile_vcard.tpl');
$o .= replace_macros($tpl, array(
'$profile' => $p,
'$xmpp' => $xmpp,
'$connect' => $connect,
'$remoteconnect' => $remoteconnect,
'$subscribe_feed' => $subscribe_feed,
@ -687,6 +689,8 @@ function advanced_profile(&$a) {
return replace_macros($tpl, array(
'$title' => t('Profile'),
'$basic' => t('Basic'),
'$advanced' => t('Advanced'),
'$profile' => $profile
));
}
@ -740,8 +744,8 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){
),
);
if ($is_owner){
if ($a->theme_events_in_profile)
// the calendar link for the full featured events calendar
if ($is_owner && $a->theme_events_in_profile) {
$tabs[] = array(
'label' => t('Events'),
'url' => $a->get_baseurl() . '/events',
@ -750,6 +754,20 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){
'id' => 'events-tab',
'accesskey' => 'e',
);
// if the user is not the owner of the calendar we only show a calendar
// with the public events of the calendar owner
} elseif (! $is_owner) {
$tabs[] = array(
'label' => t('Events'),
'url' => $a->get_baseurl() . '/cal/' . $nickname,
'sel' =>((!isset($tab)&&$a->argv[0]=='cal')?'active':''),
'title' => t('Events and Calendar'),
'id' => 'events-tab',
'accesskey' => 'e',
);
}
if ($is_owner){
$tabs[] = array(
'label' => t('Personal Notes'),
'url' => $a->get_baseurl() . '/notes',
@ -802,7 +820,7 @@ function zrl_init(&$a) {
}
}
proc_run('php','include/gprobe.php',bin2hex($tmp_str));
proc_run(PRIORITY_LOW, 'include/gprobe.php',bin2hex($tmp_str));
$arr = array('zrl' => $tmp_str, 'url' => $a->cmd);
call_hooks('zrl_init',$arr);
}

File diff suppressed because it is too large Load diff

View file

@ -153,7 +153,7 @@ function do_like($item_id, $verb) {
);
$like_item_id = $like_item['id'];
proc_run('php',"include/notifier.php","like","$like_item_id");
proc_run(PRIORITY_HIGH, "include/notifier.php", "like", $like_item_id);
return true;
}
@ -245,7 +245,7 @@ EOT;
call_hooks('post_local_end', $arr);
proc_run('php',"include/notifier.php","like","$post_id");
proc_run(PRIORITY_HIGH, "include/notifier.php", "like", $post_id);
return true;
}

View file

@ -150,7 +150,7 @@ function send_message($recipient=0, $body='', $subject='', $replyto=''){
}
if($post_id) {
proc_run('php',"include/notifier.php","mail","$post_id");
proc_run(PRIORITY_HIGH, "include/notifier.php", "mail", $post_id);
return intval($post_id);
} else {
return -3;

View file

@ -43,181 +43,170 @@ function nav(&$a) {
call_hooks('page_header', $a->page['nav']);
}
function nav_info(&$a) {
/**
* @brief Prepares a list of navigation links
*
* @param App $a
* @return array Navigation links
* string 'sitelocation' => The webbie (username@site.com)
* array 'nav' => Array of links used in the nav menu
* string 'banner' => Formatted html link with banner image
* array 'userinfo' => Array of user information (name, icon)
*/
function nav_info(App $a)
{
$ssl_state = ((local_user()) ? true : false);
/*
*
* Our network is distributed, and as you visit friends some of the
* sites look exactly the same - it isn't always easy to know where you are.
* Display the current site location as a navigation aid.
*
*/
$myident = ((is_array($a->user) && isset($a->user['nickname'])) ? $a->user['nickname'] . '@' : '');
$sitelocation = $myident . substr($a->get_baseurl($ssl_state),strpos($a->get_baseurl($ssl_state),'//') + 2 );
$sitelocation = $myident . substr($a->get_baseurl($ssl_state), strpos($a->get_baseurl($ssl_state), '//') + 2 );
// nav links: array of array('href', 'text', 'extra css classes', 'title')
$nav = Array();
$nav = array();
/*
* Display login or logout
*/
$nav['usermenu']=array();
// Display login or logout
$nav['usermenu'] = array();
$userinfo = null;
if(local_user()) {
$nav['logout'] = Array('logout',t('Logout'), "", t('End this session'));
if (local_user()) {
$nav['logout'] = array('logout', t('Logout'), '', t('End this session'));
// user menu
$nav['usermenu'][] = Array('profile/' . $a->user['nickname'], t('Status'), "", t('Your posts and conversations'));
$nav['usermenu'][] = Array('profile/' . $a->user['nickname']. '?tab=profile', t('Profile'), "", t('Your profile page'));
$nav['usermenu'][] = Array('photos/' . $a->user['nickname'], t('Photos'), "", t('Your photos'));
$nav['usermenu'][] = Array('videos/' . $a->user['nickname'], t('Videos'), "", t('Your videos'));
$nav['usermenu'][] = Array('events/', t('Events'), "", t('Your events'));
$nav['usermenu'][] = Array('notes/', t('Personal notes'), "", t('Your personal notes'));
$nav['usermenu'][] = array('profile/' . $a->user['nickname'], t('Status'), '', t('Your posts and conversations'));
$nav['usermenu'][] = array('profile/' . $a->user['nickname'] . '?tab=profile', t('Profile'), '', t('Your profile page'));
$nav['usermenu'][] = array('photos/' . $a->user['nickname'], t('Photos'), '', t('Your photos'));
$nav['usermenu'][] = array('videos/' . $a->user['nickname'], t('Videos'), '', t('Your videos'));
$nav['usermenu'][] = array('events/', t('Events'), '', t('Your events'));
$nav['usermenu'][] = array('notes/', t('Personal notes'), '', t('Your personal notes'));
// user info
$r = q("SELECT micro FROM contact WHERE uid=%d AND self=1", intval($a->user['uid']));
$r = q("SELECT `micro` FROM `contact` WHERE `uid` = %d AND `self` = 1", intval($a->user['uid']));
$userinfo = array(
'icon' => (count($r) ? $a->remove_baseurl($r[0]['micro']) : "images/person-48.jpg"),
'icon' => (count($r) ? $a->remove_baseurl($r[0]['micro']) : 'images/person-48.jpg'),
'name' => $a->user['username'],
);
}
else {
$nav['login'] = Array('login',t('Login'), ($a->module == 'login'?'selected':''), t('Sign in'));
} else {
$nav['login'] = array('login', t('Login'), ($a->module == 'login' ? 'selected' : ''), t('Sign in'));
}
/*
* "Home" should also take you home from an authenticated remote profile connection
*/
// "Home" should also take you home from an authenticated remote profile connection
$homelink = get_my_url();
if(! $homelink)
if (! $homelink) {
$homelink = ((x($_SESSION,'visitor_home')) ? $_SESSION['visitor_home'] : '');
}
if(($a->module != 'home') && (! (local_user())))
$nav['home'] = array($homelink, t('Home'), "", t('Home Page'));
if (($a->module != 'home') && (! (local_user()))) {
$nav['home'] = array($homelink, t('Home'), '', t('Home Page'));
}
if(($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user()))
$nav['register'] = array('register',t('Register'), "", t('Create an account'));
if (($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user())) {
$nav['register'] = array('register', t('Register'), '', t('Create an account'));
}
$help_url = 'help';
if(! get_config('system','hide_help'))
$nav['help'] = array($help_url, t('Help'), "", t('Help and documentation'));
if (! get_config('system', 'hide_help')) {
$nav['help'] = array($help_url, t('Help'), '', t('Help and documentation'));
}
if(count($a->apps)>0)
$nav['apps'] = array('apps', t('Apps'), "", t('Addon applications, utilities, games'));
if (count($a->apps) > 0) {
$nav['apps'] = array('apps', t('Apps'), '', t('Addon applications, utilities, games'));
}
if (local_user() OR !get_config('system','local_search')) {
$nav['search'] = array('search', t('Search'), "", t('Search site content'));
if (local_user() OR !get_config('system', 'local_search')) {
$nav['search'] = array('search', t('Search'), '', t('Search site content'));
$nav['searchoption'] = array(
t("Full Text"),
t("Tags"),
t("Contacts"));
t('Full Text'),
t('Tags'),
t('Contacts'));
if (get_config('system','poco_local_search'))
$nav['searchoption'][] = t("Forums");
if (get_config('system', 'poco_local_search')) {
$nav['searchoption'][] = t('Forums');
}
}
$gdirpath = 'directory';
if(strlen(get_config('system','singleuser'))) {
$gdir = get_config('system','directory');
if(strlen($gdir))
$gdirpath = $gdir;
if (strlen(get_config('system', 'singleuser'))) {
$gdir = get_config('system', 'directory');
if(strlen($gdir)) {
$gdirpath = zrl($gdir, true);
}
} elseif (get_config('system', 'community_page_style') == CP_USERS_ON_SERVER) {
$nav['community'] = array('community', t('Community'), '', t('Conversations on this site'));
} elseif (get_config('system', 'community_page_style') == CP_GLOBAL_COMMUNITY) {
$nav['community'] = array('community', t('Community'), '', t('Conversations on the network'));
}
elseif(get_config('system','community_page_style') == CP_USERS_ON_SERVER)
$nav['community'] = array('community', t('Community'), "", t('Conversations on this site'));
elseif(get_config('system','community_page_style') == CP_GLOBAL_COMMUNITY)
$nav['community'] = array('community', t('Community'), "", t('Conversations on the network'));
if(local_user())
$nav['events'] = Array('events', t('Events'), "", t('Events and Calendar'));
if (local_user()) {
$nav['events'] = array('events', t('Events'), '', t('Events and Calendar'));
}
$nav['directory'] = array($gdirpath, t('Directory'), "", t('People directory'));
$nav['directory'] = array($gdirpath, t('Directory'), '', t('People directory'));
$nav['about'] = Array('friendica', t('Information'), "", t('Information about this friendica instance'));
$nav['about'] = array('friendica', t('Information'), '', t('Information about this friendica instance'));
/*
*
* The following nav links are only show to logged in users
*
*/
// The following nav links are only show to logged in users
if (local_user()) {
$nav['network'] = array('network', t('Network'), '', t('Conversations from your friends'));
$nav['net_reset'] = array('network/0?f=&order=comment&nets=all', t('Network Reset'), '', t('Load Network page with no filters'));
if(local_user()) {
$nav['home'] = array('profile/' . $a->user['nickname'], t('Home'), '', t('Your posts and conversations'));
$nav['network'] = array('network', t('Network'), "", t('Conversations from your friends'));
$nav['net_reset'] = array('network/0?f=&order=comment&nets=all', t('Network Reset'), "", t('Load Network page with no filters'));
$nav['home'] = array('profile/' . $a->user['nickname'], t('Home'), "", t('Your posts and conversations'));
if(in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE, PAGE_PRVGROUP))) {
/* only show friend requests for normal pages. Other page types have automatic friendship. */
if(in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_PRVGROUP)))
$nav['introductions'] = array('notifications/intros', t('Introductions'), "", t('Friend Requests'));
if(in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE))) {
$nav['notifications'] = array('notifications', t('Notifications'), "", t('Notifications'));
$nav['notifications']['all']=array('notifications/system', t('See all notifications'), "", "");
$nav['notifications']['mark'] = array('', t('Mark as seen'), '',t('Mark all system notifications seen'));
if (in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE, PAGE_PRVGROUP))) {
// only show friend requests for normal pages. Other page types have automatic friendship.
if (in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_PRVGROUP))) {
$nav['introductions'] = array('notifications/intros', t('Introductions'), '', t('Friend Requests'));
}
if (in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE))) {
$nav['notifications'] = array('notifications', t('Notifications'), '', t('Notifications'));
$nav['notifications']['all'] = array('notifications/system', t('See all notifications'), '', '');
$nav['notifications']['mark'] = array('', t('Mark as seen'), '', t('Mark all system notifications seen'));
}
}
$nav['messages'] = array('message', t('Messages'), "", t('Private mail'));
$nav['messages']['inbox'] = array('message', t('Inbox'), "", t('Inbox'));
$nav['messages']['outbox']= array('message/sent', t('Outbox'), "", t('Outbox'));
$nav['messages']['new'] = array('message/new', t('New Message'), "", t('New Message'));
$nav['messages'] = array('message', t('Messages'), '', t('Private mail'));
$nav['messages']['inbox'] = array('message', t('Inbox'), '', t('Inbox'));
$nav['messages']['outbox'] = array('message/sent', t('Outbox'), '', t('Outbox'));
$nav['messages']['new'] = array('message/new', t('New Message'), '', t('New Message'));
if(is_array($a->identities) && count($a->identities) > 1) {
$nav['manage'] = array('manage', t('Manage'), "", t('Manage other pages'));
if (is_array($a->identities) && count($a->identities) > 1) {
$nav['manage'] = array('manage', t('Manage'), '', t('Manage other pages'));
}
$nav['delegations'] = Array('delegate', t('Delegations'), "", t('Delegate Page Management'));
$nav['delegations'] = array('delegate', t('Delegations'), '', t('Delegate Page Management'));
$nav['settings'] = array('settings', t('Settings'),"", t('Account settings'));
$nav['settings'] = array('settings', t('Settings'), '', t('Account settings'));
if(feature_enabled(local_user(),'multi_profiles'))
$nav['profiles'] = array('profiles', t('Profiles'),"", t('Manage/Edit Profiles'));
if (feature_enabled(local_user(), 'multi_profiles')) {
$nav['profiles'] = array('profiles', t('Profiles'), '', t('Manage/Edit Profiles'));
}
$nav['contacts'] = array('contacts', t('Contacts'),"", t('Manage/edit friends and contacts'));
$nav['contacts'] = array('contacts', t('Contacts'), '', t('Manage/edit friends and contacts'));
}
/*
* Admin page
*/
if (is_site_admin()){
$nav['admin'] = array('admin/', t('Admin'), "", t('Site setup and configuration'));
}
// Show the link to the admin configuration page if user is admin
if (is_site_admin()) {
$nav['admin'] = array('admin/', t('Admin'), '', t('Site setup and configuration'));
}
$nav['navigation'] = array('navigation/', t('Navigation'), '', t('Site map'));
$nav['navigation'] = array('navigation/', t('Navigation'), "", t('Site map'));
/*
*
* Provide a banner/logo/whatever
*
*/
$banner = get_config('system','banner');
if($banner === false)
$banner .= '<a href="http://friendica.com"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="http://friendica.com">Friendica</a></span>';
// Provide a banner/logo/whatever
$banner = get_config('system', 'banner');
if ($banner === false) {
$banner = '<a href="http://friendica.com"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="http://friendica.com">Friendica</a></span>';
}
call_hooks('nav_info', $nav);
return array(
'sitelocation' => $sitelocation,
'nav' => $nav,
@ -226,7 +215,6 @@ function nav_info(&$a) {
);
}
/**
* Set a menu item in navbar as selected
*

View file

@ -5,7 +5,7 @@
*/
require_once("include/xml.php");
require_once('include/Probe.php');
/**
* @brief Curl wrapper
@ -371,324 +371,6 @@ function http_status_exit($val, $description = array()) {
}
// Given an email style address, perform webfinger lookup and
// return the resulting DFRN profile URL, or if no DFRN profile URL
// is located, returns an OStatus subscription template (prefixed
// with the string 'stat:' to identify it as on OStatus template).
// If this isn't an email style address just return $webbie.
// Return an empty string if email-style addresses but webfinger fails,
// or if the resultant personal XRD doesn't contain a supported
// subscription/friend-request attribute.
// amended 7/9/2011 to return an hcard which could save potentially loading
// a lengthy content page to scrape dfrn attributes
function webfinger_dfrn($webbie,&$hcard) {
if(! strstr($webbie,'@')) {
return $webbie;
}
$profile_link = '';
$links = webfinger($webbie);
logger('webfinger_dfrn: ' . $webbie . ':' . print_r($links,true), LOGGER_DATA);
if(count($links)) {
foreach($links as $link) {
if($link['@attributes']['rel'] === NAMESPACE_DFRN)
$profile_link = $link['@attributes']['href'];
if($link['@attributes']['rel'] === NAMESPACE_OSTATUSSUB)
$profile_link = 'stat:' . $link['@attributes']['template'];
if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
$hcard = $link['@attributes']['href'];
}
}
return $profile_link;
}
/**
* @brief Perform webfinger lookup on an email style address
*
* @param string $webbi An email style address
* @param boolean $debug
*
* @return array of link attributes from the personal XRD file
* empty array on error/failure
*/
function webfinger($webbie, $debug = false) {
$host = '';
if(strstr($webbie,'@')) {
$host = substr($webbie,strpos($webbie,'@') + 1);
}
if(strlen($host)) {
$tpl = fetch_lrdd_template($host);
logger('webfinger: lrdd template: ' . $tpl);
if(strlen($tpl)) {
$pxrd = str_replace('{uri}', urlencode('acct:' . $webbie), $tpl);
logger('webfinger: pxrd: ' . $pxrd);
$links = fetch_xrd_links($pxrd);
if(! count($links)) {
// try with double slashes
$pxrd = str_replace('{uri}', urlencode('acct://' . $webbie), $tpl);
logger('webfinger: pxrd: ' . $pxrd);
$links = fetch_xrd_links($pxrd);
}
return $links;
}
}
return array();
}
function lrdd($uri, $debug = false) {
$a = get_app();
// default priority is host priority, host-meta first
$priority = 'host';
// All we have is an email address. Resource-priority is irrelevant
// because our URI isn't directly resolvable.
if(strstr($uri,'@')) {
return(webfinger($uri));
}
// get the host meta file
$host = @parse_url($uri);
if($host) {
$url = ((x($host,'scheme')) ? $host['scheme'] : 'http') . '://';
$url .= $host['host'] . '/.well-known/host-meta' ;
}
else
return array();
logger('lrdd: constructed url: ' . $url);
$xml = fetch_url($url);
$headers = $a->get_curl_headers();
if (! $xml)
return array();
logger('lrdd: host_meta: ' . $xml, LOGGER_DATA);
if(! stristr($xml,'<xrd'))
return array();
$h = parse_xml_string($xml);
if(! $h)
return array();
$arr = xml::element_to_array($h);
if(isset($arr['xrd']['property'])) {
$property = $arr['crd']['property'];
if(! isset($property[0]))
$properties = array($property);
else
$properties = $property;
foreach($properties as $prop)
if((string) $prop['@attributes'] === 'http://lrdd.net/priority/resource')
$priority = 'resource';
}
// save the links in case we need them
$links = array();
if(isset($arr['xrd']['link'])) {
$link = $arr['xrd']['link'];
if(! isset($link[0]))
$links = array($link);
else
$links = $link;
}
// do we have a template or href?
if(count($links)) {
foreach($links as $link) {
if($link['@attributes']['rel'] && attribute_contains($link['@attributes']['rel'],'lrdd')) {
if(x($link['@attributes'],'template'))
$tpl = $link['@attributes']['template'];
elseif(x($link['@attributes'],'href'))
$href = $link['@attributes']['href'];
}
}
}
if((! isset($tpl)) || (! strpos($tpl,'{uri}')))
$tpl = '';
if($priority === 'host') {
if(strlen($tpl))
$pxrd = str_replace('{uri}', urlencode($uri), $tpl);
elseif(isset($href))
$pxrd = $href;
if(isset($pxrd)) {
logger('lrdd: (host priority) pxrd: ' . $pxrd);
$links = fetch_xrd_links($pxrd);
return $links;
}
$lines = explode("\n",$headers);
if(count($lines)) {
foreach($lines as $line) {
if((stristr($line,'link:')) && preg_match('/<([^>].*)>.*rel\=[\'\"]lrdd[\'\"]/',$line,$matches)) {
return(fetch_xrd_links($matches[1]));
break;
}
}
}
}
// priority 'resource'
$html = fetch_url($uri);
$headers = $a->get_curl_headers();
logger('lrdd: headers=' . $headers, LOGGER_DEBUG);
// don't try and parse raw xml as html
if(! strstr($html,'<?xml')) {
require_once('library/HTML5/Parser.php');
try {
$dom = HTML5_Parser::parse($html);
} catch (DOMException $e) {
logger('lrdd: parse error: ' . $e);
}
if(isset($dom) && $dom) {
$items = $dom->getElementsByTagName('link');
foreach($items as $item) {
$x = $item->getAttribute('rel');
if($x == "lrdd") {
$pagelink = $item->getAttribute('href');
break;
}
}
}
}
if(isset($pagelink))
return(fetch_xrd_links($pagelink));
// next look in HTTP headers
$lines = explode("\n",$headers);
if(count($lines)) {
foreach($lines as $line) {
/// @TODO Alter the following regex to support multiple relations (space separated)
if((stristr($line,'link:')) && preg_match('/<([^>].*)>.*rel\=[\'\"]lrdd[\'\"]/',$line,$matches)) {
$pagelink = $matches[1];
break;
}
// don't try and run feeds through the html5 parser
if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
return array();
if(stristr($html,'<rss') || stristr($html,'<feed'))
return array();
}
}
if(isset($pagelink))
return(fetch_xrd_links($pagelink));
// If we haven't found any links, return the host xrd links (which we have already fetched)
if(isset($links))
return $links;
return array();
}
// Given a host name, locate the LRDD template from that
// host. Returns the LRDD template or an empty string on
// error/failure.
function fetch_lrdd_template($host) {
$tpl = '';
$url1 = 'https://' . $host . '/.well-known/host-meta' ;
$url2 = 'http://' . $host . '/.well-known/host-meta' ;
$links = fetch_xrd_links($url1);
logger('fetch_lrdd_template from: ' . $url1);
logger('template (https): ' . print_r($links,true));
if(! count($links)) {
logger('fetch_lrdd_template from: ' . $url2);
$links = fetch_xrd_links($url2);
logger('template (http): ' . print_r($links,true));
}
if(count($links)) {
foreach($links as $link)
if($link['@attributes']['rel'] && $link['@attributes']['rel'] === 'lrdd' && (!$link['@attributes']['type'] || $link['@attributes']['type'] === 'application/xrd+xml'))
$tpl = $link['@attributes']['template'];
}
if(! strpos($tpl,'{uri}'))
$tpl = '';
return $tpl;
}
/**
* @brief Given a URL, retrieve the page as an XRD document.
*
* @param string $url An url
* @return array of links
* return empty array on error/failure
*/
function fetch_xrd_links($url) {
$xrd_timeout = intval(get_config('system','xrd_timeout'));
$redirects = 0;
$xml = fetch_url($url,false,$redirects,(($xrd_timeout) ? $xrd_timeout : 20), "application/xrd+xml");
logger('fetch_xrd_links: ' . $xml, LOGGER_DATA);
if ((! $xml) || (! stristr($xml,'<xrd')))
return array();
// fix diaspora's bad xml
$xml = str_replace(array('href=&quot;','&quot;/>'),array('href="','"/>'),$xml);
$h = parse_xml_string($xml);
if(! $h)
return array();
$arr = xml::element_to_array($h);
$links = array();
if(isset($arr['xrd']['link'])) {
$link = $arr['xrd']['link'];
if(! isset($link[0]))
$links = array($link);
else
$links = $link;
}
if(isset($arr['xrd']['alias'])) {
$alias = $arr['xrd']['alias'];
if(! isset($alias[0]))
$aliases = array($alias);
else
$aliases = $alias;
if(is_array($aliases) && count($aliases)) {
foreach($aliases as $alias) {
$links[]['@attributes'] = array('rel' => 'alias' , 'href' => $alias);
}
}
}
logger('fetch_xrd_links: ' . print_r($links,true), LOGGER_DATA);
return $links;
}
/**
* @brief Check URL to se if ts's real
*
@ -1123,7 +805,7 @@ function short_link($url) {
* This function encodes an array to json format
* and adds an application/json HTTP header to the output.
* After finishing the process is getting killed.
*
*
* @param array $x The input content
*/
function json_return_and_die($x) {
@ -1131,3 +813,57 @@ function json_return_and_die($x) {
echo json_encode($x);
killme();
}
/**
* @brief Find the matching part between two url
*
* @param string $url1
* @param string $url2
* @return string The matching part
*/
function matching_url($url1, $url2) {
if (($url1 == "") OR ($url2 == ""))
return "";
$url1 = normalise_link($url1);
$url2 = normalise_link($url2);
$parts1 = parse_url($url1);
$parts2 = parse_url($url2);
if (!isset($parts1["host"]) OR !isset($parts2["host"]))
return "";
if ($parts1["scheme"] != $parts2["scheme"])
return "";
if ($parts1["host"] != $parts2["host"])
return "";
if ($parts1["port"] != $parts2["port"])
return "";
$match = $parts1["scheme"]."://".$parts1["host"];
if ($parts1["port"])
$match .= ":".$parts1["port"];
$pathparts1 = explode("/", $parts1["path"]);
$pathparts2 = explode("/", $parts2["path"]);
$i = 0;
$path = "";
do {
$path1 = $pathparts1[$i];
$path2 = $pathparts2[$i];
if ($path1 == $path2)
$path .= $path1."/";
} while (($path1 == $path2) AND ($i++ <= count($pathparts1)));
$match .= $path;
return normalise_link($match);
}

View file

@ -16,7 +16,7 @@ require_once('include/salmon.php');
/*
* The notifier is typically called with:
*
* proc_run('php', "include/notifier.php", COMMAND, ITEM_ID);
* proc_run(PRIORITY_HIGH, "include/notifier.php", COMMAND, ITEM_ID);
*
* where COMMAND is one of the following:
*
@ -132,18 +132,25 @@ function notifier_run(&$argv, &$argc){
$recipients[] = $suggest[0]['cid'];
$item = $suggest[0];
} elseif($cmd === 'removeme') {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($item_id));
if (! $r)
$r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
`user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`, `user`.`guid`
FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
WHERE `contact`.`uid` = %d AND `contact`.`self` LIMIT 1",
intval($item_id));
if (!$r)
return;
$user = $r[0];
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($item_id));
if (! $r)
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", intval($item_id));
if (!$r)
return;
$self = $r[0];
$r = q("SELECT * FROM `contact` WHERE `self` = 0 AND `uid` = %d", intval($item_id));
if(! $r)
$r = q("SELECT * FROM `contact` WHERE NOT `self` AND `uid` = %d", intval($item_id));
if(!$r)
return;
require_once('include/Contact.php');
@ -197,7 +204,7 @@ function notifier_run(&$argv, &$argc){
$r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
`user`.`page-flags`, `user`.`prvnets`
`user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`
FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
intval($uid)
@ -348,7 +355,7 @@ function notifier_run(&$argv, &$argc){
// a delivery fork. private groups (forum_mode == 2) do not uplink
if((intval($parent['forum_mode']) == 1) && (! $top_level) && ($cmd !== 'uplink')) {
proc_run('php','include/notifier.php','uplink',$item_id);
proc_run(PRIORITY_HIGH,'include/notifier.php','uplink',$item_id);
}
$conversants = array();
@ -388,17 +395,30 @@ function notifier_run(&$argv, &$argc){
// We have not only to look at the parent, since it could be a Friendica thread.
if (($thr_parent AND ($thr_parent[0]['network'] == NETWORK_OSTATUS)) OR ($parent['network'] == NETWORK_OSTATUS)) {
logger('Some parent is OStatus for '.$target_item["guid"], LOGGER_DEBUG);
logger('Some parent is OStatus for '.$target_item["guid"]." - Author: ".$thr_parent[0]['author-link']." - Owner: ".$thr_parent[0]['owner-link'], LOGGER_DEBUG);
// Send a salmon to the parent author
$probed_contact = probe_url($thr_parent[0]['author-link']);
$r = q("SELECT `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''",
dbesc(normalise_link($thr_parent[0]['author-link'])),
intval($uid));
if ($r)
$probed_contact = $r[0];
else
$probed_contact = probe_url($thr_parent[0]['author-link']);
if ($probed_contact["notify"] != "") {
logger('Notify parent author '.$probed_contact["url"].': '.$probed_contact["notify"]);
$url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
}
// Send a salmon to the parent owner
$probed_contact = probe_url($thr_parent[0]['owner-link']);
$r = q("SELECT `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''",
dbesc(normalise_link($thr_parent[0]['owner-link'])),
intval($uid));
if ($r)
$probed_contact = $r[0];
else
$probed_contact = probe_url($thr_parent[0]['owner-link']);
if ($probed_contact["notify"] != "") {
logger('Notify parent owner '.$probed_contact["url"].': '.$probed_contact["notify"]);
$url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
@ -518,7 +538,7 @@ function notifier_run(&$argv, &$argc){
$this_batch[] = $contact['id'];
if(count($this_batch) >= $deliveries_per_process) {
proc_run('php','include/delivery.php',$cmd,$item_id,$this_batch);
proc_run(PRIORITY_HIGH,'include/delivery.php',$cmd,$item_id,$this_batch);
$this_batch = array();
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
@ -528,7 +548,7 @@ function notifier_run(&$argv, &$argc){
// be sure to pick up any stragglers
if(count($this_batch))
proc_run('php','include/delivery.php',$cmd,$item_id,$this_batch);
proc_run(PRIORITY_HIGH,'include/delivery.php',$cmd,$item_id,$this_batch);
}
// send salmon slaps to mentioned remote tags (@foo@example.com) in OStatus posts
@ -579,10 +599,10 @@ function notifier_run(&$argv, &$argc){
foreach($r as $rr) {
if((! $mail) && (! $fsuggest) && (! $followup)) {
q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )",
dbesc($cmd),
intval($item_id),
intval($rr['id'])
q("INSERT INTO `deliverq` (`cmd`,`item`,`contact`) VALUES ('%s', %d, %d)
ON DUPLICATE KEY UPDATE `cmd` = '%s', `item` = %d, `contact` = %d",
dbesc($cmd), intval($item_id), intval($rr['id']),
dbesc($cmd), intval($item_id), intval($rr['id'])
);
}
}
@ -599,7 +619,7 @@ function notifier_run(&$argv, &$argc){
if((! $mail) && (! $fsuggest) && (! $followup)) {
logger('notifier: delivery agent: '.$rr['name'].' '.$rr['id'].' '.$rr['network'].' '.$target_item["guid"]);
proc_run('php','include/delivery.php',$cmd,$item_id,$rr['id']);
proc_run(PRIORITY_HIGH,'include/delivery.php',$cmd,$item_id,$rr['id']);
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
}
@ -622,8 +642,8 @@ function notifier_run(&$argv, &$argc){
if ($h === '[internal]') {
// Set push flag for PuSH subscribers to this topic,
// they will be notified in queue.php
q("UPDATE `push_subscriber` SET `push` = 1 " .
"WHERE `nickname` = '%s'", dbesc($owner['nickname']));
q("UPDATE `push_subscriber` SET `push` = 1 ".
"WHERE `nickname` = '%s' AND `push` = 0", dbesc($owner['nickname']));
logger('Activating internal PuSH for item '.$item_id, LOGGER_DEBUG);
@ -639,7 +659,7 @@ function notifier_run(&$argv, &$argc){
}
// Handling the pubsubhubbub requests
proc_run('php','include/pubsubpublish.php');
proc_run(PRIORITY_HIGH,'include/pubsubpublish.php');
}
logger('notifier: calling hooks', LOGGER_DEBUG);

View file

@ -6,7 +6,15 @@ function oembed_replacecb($matches){
return $s;
}
/**
* @brief Get data from an URL to embed its content.
*
* @param string $embedurl The URL from which the data should be fetched.
* @param bool $no_rich_type If set to true rich type content won't be fetched.
*
* @return bool|object Returns object with embed content or false if no embedable
* content exists
*/
function oembed_fetch_url($embedurl, $no_rich_type = false){
$embedurl = trim($embedurl, "'");
$embedurl = trim($embedurl, '"');
@ -16,11 +24,11 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
$r = q("SELECT * FROM `oembed` WHERE `url` = '%s'",
dbesc(normalise_link($embedurl)));
if ($r)
if (dbm::is_result($r)) {
$txt = $r[0]["content"];
else
} else {
$txt = Cache::get($a->videowidth . $embedurl);
}
// These media files should now be caught in bbcode.php
// left here as a fallback in case this is called from another source
@ -28,27 +36,27 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
$ext = pathinfo(strtolower($embedurl),PATHINFO_EXTENSION);
if(is_null($txt)){
if (is_null($txt)) {
$txt = "";
if (!in_array($ext, $noexts)){
// try oembed autodiscovery
$redirects = 0;
$html_text = fetch_url($embedurl, false, $redirects, 15, "text/*"); /**/
if($html_text){
$html_text = fetch_url($embedurl, false, $redirects, 15, "text/*");
if ($html_text) {
$dom = @DOMDocument::loadHTML($html_text);
if ($dom){
if ($dom) {
$xpath = new DOMXPath($dom);
$attr = "oembed";
$xattr = oe_build_xpath("class","oembed");
$entries = $xpath->query("//link[@type='application/json+oembed']");
foreach($entries as $e){
foreach ($entries as $e) {
$href = $e->getAttributeNode("href")->nodeValue;
$txt = fetch_url($href . '&maxwidth=' . $a->videowidth);
break;
}
$entries = $xpath->query("//link[@type='text/json+oembed']");
foreach($entries as $e){
foreach ($entries as $e) {
$href = $e->getAttributeNode("href")->nodeValue;
$txt = fetch_url($href . '&maxwidth=' . $a->videowidth);
break;
@ -57,7 +65,7 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
}
}
if ($txt==false || $txt==""){
if ($txt==false || $txt=="") {
$embedly = get_config("system", "embedly");
if ($embedly != "") {
// try embedly service
@ -70,30 +78,33 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
$txt=trim($txt);
if ($txt[0]!="{")
if ($txt[0]!="{") {
$txt='{"type":"error"}';
else { //save in cache
} else { //save in cache
$j = json_decode($txt);
if ($j->type != "error")
if ($j->type != "error") {
q("INSERT INTO `oembed` (`url`, `content`, `created`) VALUES ('%s', '%s', '%s')
ON DUPLICATE KEY UPDATE `content` = '%s', `created` = '%s'",
dbesc(normalise_link($embedurl)),
dbesc($txt), dbesc(datetime_convert()),
dbesc($txt), dbesc(datetime_convert()));
}
Cache::set($a->videowidth.$embedurl,$txt, CACHE_DAY);
Cache::set($a->videowidth.$embedurl, $txt, CACHE_DAY);
}
}
$j = json_decode($txt);
if (!is_object($j))
if (!is_object($j)) {
return false;
}
// Always embed the SSL version
if (isset($j->html))
if (isset($j->html)) {
$j->html = str_replace(array("http://www.youtube.com/", "http://player.vimeo.com/"),
array("https://www.youtube.com/", "https://player.vimeo.com/"), $j->html);
}
$j->embedurl = $embedurl;
@ -109,16 +120,18 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
//$j->height = $data["images"][0]["height"];
}
if (isset($data["title"]))
$j->title = $data["title"];
if (isset($data["title"])) {
$j->title = $data["title"];
}
if (isset($data["text"]))
$j->description = $data["text"];
if (isset($data["text"])) {
$j->description = $data["text"];
}
if (is_array($data["images"])) {
$j->thumbnail_url = $data["images"][0]["src"];
$j->thumbnail_width = $data["images"][0]["width"];
$j->thumbnail_height = $data["images"][0]["height"];
$j->thumbnail_url = $data["images"][0]["src"];
$j->thumbnail_width = $data["images"][0]["width"];
$j->thumbnail_height = $data["images"][0]["height"];
}
}
@ -209,25 +222,34 @@ function oembed_format_object($j){
return mb_convert_encoding($ret, 'HTML-ENTITIES', mb_detect_encoding($ret));
}
function oembed_iframe($src,$width,$height) {
if(! $width || strstr($width,'%'))
$width = '640';
if(! $height || strstr($height,'%')) {
$height = '300';
$resize = 'onload="resizeIframe(this);"';
} else
$resize = '';
// try and leave some room for the description line.
$height = intval($height) + 80;
$width = intval($width) + 40;
/**
* @brief Generates the iframe HTML for an oembed attachment.
*
* Width and height are given by the remote, and are regularly too small for
* the generated iframe.
*
* The width is entirely discarded for the actual width of the post, while fixed
* height is used as a starting point before the inevitable resizing.
*
* Since the iframe is automatically resized on load, there are no need for ugly
* and impractical scrollbars.
*
* @param string $src Original remote URL to embed
* @param string $width
* @param string $height
* @return string formatted HTML
*
* @see oembed_format_object()
*/
function oembed_iframe($src, $width, $height) {
if (!$height || strstr($height,'%')) {
$height = '200';
}
$width = '100%';
$a = get_app();
$s = $a->get_baseurl()."/oembed/".base64url_encode($src);
return '<iframe '.$resize.' class="embed_rich" height="'.$height.'" width="'.$width.'" src="'.$s.'" frameborder="no">'.t('Embedded content').'</iframe>';
$s = $a->get_baseurl() . '/oembed/'.base64url_encode($src);
return '<iframe onload="resizeIframe(this);" class="embed_rich" height="' . $height . '" width="' . $width . '" src="' . $s . '" scrolling="no" frameborder="no">' . t('Embedded content') . '</iframe>';
}

View file

@ -24,7 +24,6 @@ function onepoll_run(&$argv, &$argc){
unset($db_host, $db_user, $db_pass, $db_data);
};
require_once('include/session.php');
require_once('include/datetime.php');
require_once('include/items.php');
@ -444,7 +443,7 @@ function onepoll_run(&$argv, &$argc){
$refs_arr[$x] = "'" . msgid2iri(str_replace(array('<','>',' '),array('','',''),dbesc($refs_arr[$x]))) . "'";
}
$qstr = implode(',',$refs_arr);
$r = q("SELECT `uri` , `parent-uri` FROM `item` WHERE `uri` IN ( $qstr ) AND `uid` = %d LIMIT 1",
$r = q("SELECT `uri` , `parent-uri` FROM `item` USE INDEX (`uid_uri`) WHERE `uri` IN ($qstr) AND `uid` = %d LIMIT 1",
intval($importer_uid)
);
if(count($r))

View file

@ -806,11 +806,20 @@ class ostatus {
}
// Get the parent
$parents = q("SELECT `item`.`id`, `item`.`parent`, `item`.`uri`, `item`.`contact-id`, `item`.`type`,
`item`.`verb`, `item`.`visible` FROM `term`
STRAIGHT_JOIN `item` AS `thritem` ON `thritem`.`parent` = `term`.`oid`
STRAIGHT_JOIN `item` ON `item`.`parent` = `thritem`.`parent`
WHERE `term`.`uid` = %d AND `term`.`otype` = %d AND `term`.`type` = %d AND `term`.`url` = '%s'",
intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
/* 2016-10-23: The old query will be kept until we are sure that the query above is a good and fast replacement
$parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
(SELECT `parent` FROM `item` WHERE `id` IN
(SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
*/
if ($parents)
$parent = $parents[0];
elseif (count($item) > 0) {
@ -1961,9 +1970,23 @@ class ostatus {
$last_update = 'now -30 days';
$check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
$authorid = get_contact($owner["url"], 0);
$items = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id` FROM `item`
INNER JOIN `thread` ON `thread`.`iid` = `item`.`parent`
$items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` USE INDEX (`uid_contactid_created`)
STRAIGHT_JOIN `thread` ON `thread`.`iid` = `item`.`parent`
WHERE `item`.`uid` = %d AND `item`.`contact-id` = %d AND
`item`.`author-id` = %d AND `item`.`created` > '%s' AND
NOT `item`.`deleted` AND NOT `item`.`private` AND
`thread`.`network` IN ('%s', '%s')
ORDER BY `item`.`created` DESC LIMIT 300",
intval($owner["uid"]), intval($owner["id"]),
intval($authorid), dbesc($check_date),
dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
/* 2016-10-23: The old query will be kept until we are sure that the query above is a good and fast replacement
$items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item`
STRAIGHT_JOIN `thread` ON `thread`.`iid` = `item`.`parent`
LEFT JOIN `item` AS `thritem` ON `thritem`.`uri`=`item`.`thr-parent` AND `thritem`.`uid`=`item`.`uid`
WHERE `item`.`uid` = %d AND `item`.`received` > '%s' AND NOT `item`.`private` AND NOT `item`.`deleted`
AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = ''
@ -1971,7 +1994,7 @@ class ostatus {
OR (`item`.`network` = '%s' AND ((`thread`.`network` IN ('%s', '%s')) OR (`thritem`.`network` IN ('%s', '%s')))) AND `thread`.`mention`)
AND ((`item`.`owner-link` IN ('%s', '%s') AND (`item`.`parent` = `item`.`id`))
OR (`item`.`author-link` IN ('%s', '%s')))
ORDER BY `item`.`received` DESC
ORDER BY `item`.`id` DESC
LIMIT 0, 300",
intval($owner["uid"]), dbesc($check_date), dbesc(NETWORK_DFRN),
//dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS),
@ -1981,7 +2004,7 @@ class ostatus {
dbesc($owner["nurl"]), dbesc(str_replace("http://", "https://", $owner["nurl"])),
dbesc($owner["nurl"]), dbesc(str_replace("http://", "https://", $owner["nurl"]))
);
*/
$doc = new DOMDocument('1.0', 'utf-8');
$doc->formatOutput = true;

View file

@ -1,13 +1,7 @@
<?php
require_once("include/dba.php");
/**
* translation support
*/
/**
* @brief translation support
*
* Get the language setting directly from system variables, bypassing get_config()
* as database may not yet be configured.
@ -16,8 +10,12 @@ require_once("include/dba.php");
*
*/
require_once("include/dba.php");
if(! function_exists('get_browser_language')) {
/**
* @brief get the prefered language from the HTTP_ACCEPT_LANGUAGE header
*/
function get_browser_language() {
if (x($_SERVER,'HTTP_ACCEPT_LANGUAGE')) {
@ -25,32 +23,34 @@ function get_browser_language() {
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
$lang_list = [];
if (count($lang_parse[1])) {
// create a list like "en" => 0.8
$langs = array_combine($lang_parse[1], $lang_parse[4]);
// set default to 1 for any without q factor
foreach ($langs as $lang => $val) {
if ($val === '') $langs[$lang] = 1;
}
// sort list based on value
arsort($langs, SORT_NUMERIC);
}
}
if(isset($langs) && count($langs)) {
foreach ($langs as $lang => $v) {
if(file_exists("view/$lang") && is_dir("view/$lang")) {
$preferred = $lang;
break;
// go through the list of prefered languages and add a generic language
// for sub-linguas (e.g. de-ch will add de) if not already in array
for ($i=0; $i<count($lang_parse[1]); $i++) {
$lang_list[] = strtolower($lang_parse[1][$i]);
if ( strlen($lang_parse[1][$i])>3 ) {
$dashpos = strpos($lang_parse[1][$i], '-');
if (! in_array(substr($lang_parse[1][$i], 0, $dashpos), $lang_list ) ) {
$lang_list[] = strtolower(substr($lang_parse[1][$i], 0, $dashpos));
}
}
}
}
}
// check if we have translations for the preferred languages and pick the 1st that has
for ($i=0; $i<count($lang_list); $i++) {
$lang = $lang_list[$i];
if(file_exists("view/lang/$lang") && is_dir("view/lang/$lang")) {
$preferred = $lang;
break;
}
}
if(isset($preferred))
return $preferred;
// in case none matches, get the system wide configured language, or fall back to English
$a = get_app();
return ((isset($a->config['system']['language'])) ? $a->config['system']['language'] : 'en');
}}
@ -112,8 +112,8 @@ function load_translation_table($lang) {
}
}
if(file_exists("view/$lang/strings.php")) {
include("view/$lang/strings.php");
if(file_exists("view/lang/$lang/strings.php")) {
include("view/lang/$lang/strings.php");
}
}}
@ -162,25 +162,31 @@ function string_plural_select_default($n) {
}}
/**
* Return installed languages as associative array
* [
* lang => lang,
* ...
* ]
*/
function get_avaiable_languages() {
$lang_choices = array();
$langs = glob('view/*/strings.php'); /**/
if(is_array($langs) && count($langs)) {
if(! in_array('view/en/strings.php',$langs))
$langs[] = 'view/en/';
asort($langs);
foreach($langs as $l) {
$t = explode("/",$l);
$lang_choices[$t[1]] = $t[1];
/**
* @brief Return installed languages codes as associative array
*
* Scans the view/lang directory for the existence of "strings.php" files, and
* returns an alphabetical list of their folder names (@-char language codes).
* Adds the english language if it's missing from the list.
*
* Ex: array('de' => 'de', 'en' => 'en', 'fr' => 'fr', ...)
*
* @return array
*/
function get_available_languages() {
$langs = array();
$strings_file_paths = glob('view/lang/*/strings.php');
if (is_array($strings_file_paths) && count($strings_file_paths)) {
if (!in_array('view/lang/en/strings.php', $strings_file_paths)) {
$strings_file_paths[] = 'view/lang/en/strings.php';
}
asort($strings_file_paths);
foreach($strings_file_paths as $strings_file_path) {
$path_array = explode('/', $strings_file_path);
$langs[$path_array[2]] = $path_array[2];
}
}
return $lang_choices;
return $langs;
}

View file

@ -25,3 +25,34 @@ function gps2Num($coordPart) {
return floatval($parts[0]) / floatval($parts[1]);
}
/**
* @brief Fetch the photo albums that are available for a viewer
*
* The query in this function is cost intensive, so it is cached.
*
* @param int $uid User id of the photos
* @param bool $update Update the cache
*
* @return array Returns array of the photo albums
*/
function photo_albums($uid, $update = false) {
$sql_extra = permissions_sql($uid);
$key = "photo_albums:".$uid.":".local_user().":".remote_user();
$albums = Cache::get($key);
if (is_null($albums) OR $update) {
/// @todo This query needs to be renewed. It is really slow
// At this time we just store the data in the cache
$albums = qu("SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`
FROM `photo` USE INDEX (`uid_album_created`)
WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' $sql_extra
GROUP BY `album` ORDER BY `created` DESC",
intval($uid),
dbesc('Contact Photos'),
dbesc(t('Contact Photos'))
);
Cache::set($key, $albums, CACHE_DAY);
}
return $albums;
}

View file

@ -82,7 +82,7 @@ function get_attachment_data($body) {
$data = array();
if (!preg_match("/(.*)\[attachment(.*)\](.*?)\[\/attachment\](.*)/ism", $body, $match))
if (!preg_match("/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism", $body, $match))
return get_old_attachment_data($body);
$attributes = $match[2];

View file

@ -205,37 +205,41 @@ function load_hooks() {
* @param string $name of the hook to call
* @param string|array &$data to transmit to the callback handler
*/
if(! function_exists('call_hooks')) {
function call_hooks($name, &$data = null) {
$stamp1 = microtime(true);
$a = get_app();
#logger($name, LOGGER_ALL);
if (is_array($a->hooks) && array_key_exists($name, $a->hooks))
foreach ($a->hooks[$name] as $hook)
call_single_hook($a, $name, $hook, $data);
}
if((is_array($a->hooks)) && (array_key_exists($name,$a->hooks))) {
foreach($a->hooks[$name] as $hook) {
// Don't run a theme's hook if the user isn't using the theme
if(strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/'.current_theme()) === false)
continue;
/**
* @brief Calls a single hook.
*
* @param string $name of the hook to call
* @param array $hook Hook data
* @param string|array &$data to transmit to the callback handler
*/
function call_single_hook($a, $name, $hook, &$data = null) {
// Don't run a theme's hook if the user isn't using the theme
if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/'.current_theme()) === false)
return;
@include_once($hook[0]);
if(function_exists($hook[1])) {
$func = $hook[1];
//logger($name." => ".$hook[0].":".$func."()", LOGGER_DEBUG);
$func($a,$data);
}
else {
// remove orphan hooks
q("DELETE FROM `hook` WHERE `hook` = '%s' AND `file` = '%s' AND `function` = '%s'",
dbesc($name),
dbesc($hook[0]),
dbesc($hook[1])
);
}
}
@include_once($hook[0]);
if (function_exists($hook[1])) {
$func = $hook[1];
$func($a, $data);
} else {
// remove orphan hooks
q("DELETE FROM `hook` WHERE `hook` = '%s' AND `file` = '%s' AND `function` = '%s'",
dbesc($name),
dbesc($hook[0]),
dbesc($hook[1])
);
}
}}
}
//check if an app_menu hook exist for plugin $name.
//Return true if the plugin is an app
@ -534,3 +538,41 @@ function upgrade_bool_message($bbcode = false) {
$x = upgrade_link($bbcode);
return t('This action is not available under your subscription plan.') . (($x) ? ' ' . $x : '') ;
}
/**
* @brief Get the full path to relevant theme files by filename
*
* This function search in the theme directory (and if not present in global theme directory)
* if there is a directory with the file extension and for a file with the given
* filename.
*
* @param string $file Filename
* @param string $root Full root path
* @return string Path to the file or empty string if the file isn't found
*/
function theme_include($file, $root = '') {
// Make sure $root ends with a slash / if it's not blank
if($root !== '' && $root[strlen($root)-1] !== '/')
$root = $root . '/';
$theme_info = $a->theme_info;
if(is_array($theme_info) AND array_key_exists('extends',$theme_info))
$parent = $theme_info['extends'];
else
$parent = 'NOPATH';
$theme = current_theme();
$thname = $theme;
$ext = substr($file,strrpos($file,'.')+1);
$paths = array(
"{$root}view/theme/$thname/$ext/$file",
"{$root}view/theme/$parent/$ext/$file",
"{$root}view/$ext/$file",
);
foreach($paths as $p) {
// strpos() is faster than strstr when checking if one string is in another (http://php.net/manual/en/function.strstr.php)
if(strpos($p,'NOPATH') !== false)
continue;
if(file_exists($p))
return $p;
}
return '';
}

View file

@ -10,8 +10,10 @@ if (!file_exists("boot.php") AND (sizeof($_SERVER["argv"]) != 0)) {
chdir($directory);
}
use \Friendica\Core\Config;
use \Friendica\Core\PConfig;
require_once("boot.php");
require_once("dbm.php");
function poller_run(&$argv, &$argc){
global $a, $db;
@ -27,19 +29,16 @@ function poller_run(&$argv, &$argc){
unset($db_host, $db_user, $db_pass, $db_data);
};
$max_processes = get_config('system', 'max_processes_backend');
if (intval($max_processes) == 0)
$max_processes = 5;
// Quit when in maintenance
if (get_config('system', 'maintenance', true))
return;
$processlist = dbm::processlist();
if ($processlist["list"] != "") {
logger("Processcheck: Processes: ".$processlist["amount"]." - Processlist: ".$processlist["list"], LOGGER_DEBUG);
$a->start_process();
if ($processlist["amount"] > $max_processes) {
logger("Processcheck: Maximum number of processes for backend tasks (".$max_processes.") reached.", LOGGER_DEBUG);
return;
}
}
$mypid = getmypid();
if ($a->max_processes_reached())
return;
if (poller_max_connections_reached())
return;
@ -48,17 +47,17 @@ function poller_run(&$argv, &$argc){
return;
// Checking the number of workers
if (poller_too_much_workers(1)) {
if (poller_too_much_workers()) {
poller_kill_stale_workers();
return;
}
if(($argc <= 1) OR ($argv[1] != "no_cron")) {
// Run the cron job that calls all other jobs
proc_run("php","include/cron.php");
proc_run(PRIORITY_MEDIUM, "include/cron.php");
// Run the cronhooks job separately from cron for being able to use a different timing
proc_run("php","include/cronhooks.php");
proc_run(PRIORITY_MEDIUM, "include/cronhooks.php");
// Cleaning dead processes
poller_kill_stale_workers();
@ -67,46 +66,59 @@ function poller_run(&$argv, &$argc){
sleep(4);
// Checking number of workers
if (poller_too_much_workers(2))
if (poller_too_much_workers())
return;
$cooldown = Config::get("system", "worker_cooldown", 0);
$starttime = time();
while ($r = q("SELECT * FROM `workerqueue` WHERE `executed` = '0000-00-00 00:00:00' ORDER BY `created` LIMIT 1")) {
while ($r = poller_worker_process()) {
// Log the type of database processes
$processlist = dbm::processlist();
if ($processlist["amount"] != "") {
logger("Processcheck: Processes: ".$processlist["amount"]." - Processlist: ".$processlist["list"], LOGGER_DEBUG);
// Quit when in maintenance
if (get_config('system', 'maintenance', true))
return;
if ($processlist["amount"] > $max_processes) {
logger("Processcheck: Maximum number of processes for backend tasks (".$max_processes.") reached.", LOGGER_DEBUG);
return;
}
}
// Constantly check the number of parallel database processes
if ($a->max_processes_reached())
return;
// Constantly check the number of available database connections to let the frontend be accessible at any time
if (poller_max_connections_reached())
return;
// Count active workers and compare them with a maximum value that depends on the load
if (poller_too_much_workers(3))
if (poller_too_much_workers())
return;
q("UPDATE `workerqueue` SET `executed` = '%s', `pid` = %d WHERE `id` = %d AND `executed` = '0000-00-00 00:00:00'",
$upd = q("UPDATE `workerqueue` SET `executed` = '%s', `pid` = %d WHERE `id` = %d AND `pid` = 0",
dbesc(datetime_convert()),
intval(getmypid()),
intval($mypid),
intval($r[0]["id"]));
// Assure that there are no tasks executed twice
$id = q("SELECT `id` FROM `workerqueue` WHERE `id` = %d AND `pid` = %d",
intval($r[0]["id"]),
intval(getmypid()));
if (!$id) {
logger("Queue item ".$r[0]["id"]." was executed multiple times - skip this execution", LOGGER_DEBUG);
if (!$upd) {
logger("Couldn't update queue entry ".$r[0]["id"]." - skip this execution", LOGGER_DEBUG);
q("COMMIT");
continue;
}
// Assure that there are no tasks executed twice
$id = q("SELECT `pid`, `executed` FROM `workerqueue` WHERE `id` = %d", intval($r[0]["id"]));
if (!$id) {
logger("Queue item ".$r[0]["id"]." vanished - skip this execution", LOGGER_DEBUG);
q("COMMIT");
continue;
} elseif ((strtotime($id[0]["executed"]) <= 0) OR ($id[0]["pid"] == 0)) {
logger("Entry for queue item ".$r[0]["id"]." wasn't stored - skip this execution", LOGGER_DEBUG);
q("COMMIT");
continue;
} elseif ($id[0]["pid"] != $mypid) {
logger("Queue item ".$r[0]["id"]." is to be executed by process ".$id[0]["pid"]." and not by me (".$mypid.") - skip this execution", LOGGER_DEBUG);
q("COMMIT");
continue;
}
q("COMMIT");
$argv = json_decode($r[0]["parameter"]);
$argc = count($argv);
@ -122,13 +134,26 @@ function poller_run(&$argv, &$argc){
require_once($include);
$funcname=str_replace(".php", "", basename($argv[0]))."_run";
$funcname = str_replace(".php", "", basename($argv[0]))."_run";
if (function_exists($funcname)) {
logger("Process ".getmypid()." - ID ".$r[0]["id"].": ".$funcname." ".$r[0]["parameter"]);
logger("Process ".$mypid." - Prio ".$r[0]["priority"]." - ID ".$r[0]["id"].": ".$funcname." ".$r[0]["parameter"]);
// For better logging create a new process id for every worker call
// But preserve the old one for the worker
$old_process_id = $a->process_id;
$a->process_id = uniqid("wrk", true);
$funcname($argv, $argc);
logger("Process ".getmypid()." - ID ".$r[0]["id"].": ".$funcname." - done");
$a->process_id = $old_process_id;
if ($cooldown > 0) {
logger("Process ".$mypid." - Prio ".$r[0]["priority"]." - ID ".$r[0]["id"].": ".$funcname." - in cooldown for ".$cooldown." seconds");
sleep($cooldown);
}
logger("Process ".$mypid." - Prio ".$r[0]["priority"]." - ID ".$r[0]["id"].": ".$funcname." - done");
q("DELETE FROM `workerqueue` WHERE `id` = %d", intval($r[0]["id"]));
} else
@ -226,9 +251,9 @@ function poller_max_connections_reached() {
*
*/
function poller_kill_stale_workers() {
$r = q("SELECT `pid`, `executed` FROM `workerqueue` WHERE `executed` != '0000-00-00 00:00:00'");
$r = q("SELECT `pid`, `executed`, `priority`, `parameter` FROM `workerqueue` WHERE `executed` != '0000-00-00 00:00:00'");
if (!is_array($r) || count($r) == 0) {
if (!dbm::is_result($r)) {
// No processing here needed
return;
}
@ -239,27 +264,47 @@ function poller_kill_stale_workers() {
intval($pid["pid"]));
else {
// Kill long running processes
// Check if the priority is in a valid range
if (!in_array($pid["priority"], array(PRIORITY_CRITICAL, PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORITY_LOW, PRIORITY_NEGLIGIBLE)))
$pid["priority"] = PRIORITY_MEDIUM;
// Define the maximum durations
$max_duration_defaults = array(PRIORITY_CRITICAL => 360, PRIORITY_HIGH => 10, PRIORITY_MEDIUM => 60, PRIORITY_LOW => 180, PRIORITY_NEGLIGIBLE => 360);
$max_duration = $max_duration_defaults[$pid["priority"]];
$argv = json_decode($pid["parameter"]);
$argv[0] = basename($argv[0]);
// How long is the process already running?
$duration = (time() - strtotime($pid["executed"])) / 60;
if ($duration > 180) {
logger("Worker process ".$pid["pid"]." took more than 3 hours. It will be killed now.");
if ($duration > $max_duration) {
logger("Worker process ".$pid["pid"]." (".implode(" ", $argv).") took more than ".$max_duration." minutes. It will be killed now.");
posix_kill($pid["pid"], SIGTERM);
// Question: If a process is stale: Should we remove it or should we reschedule it?
// By now we rescheduling it. It's maybe not the wisest decision?
q("UPDATE `workerqueue` SET `executed` = '0000-00-00 00:00:00', `pid` = 0 WHERE `pid` = %d",
// We killed the stale process.
// To avoid a blocking situation we reschedule the process at the beginning of the queue.
// Additionally we are lowering the priority.
q("UPDATE `workerqueue` SET `executed` = '0000-00-00 00:00:00', `created` = '%s',
`priority` = %d, `pid` = 0 WHERE `pid` = %d",
dbesc(datetime_convert()),
intval(PRIORITY_NEGLIGIBLE),
intval($pid["pid"]));
} else
logger("Worker process ".$pid["pid"]." now runs for ".round($duration)." minutes. That's okay.", LOGGER_DEBUG);
logger("Worker process ".$pid["pid"]." (".implode(" ", $argv).") now runs for ".round($duration)." of ".$max_duration." allowed minutes. That's okay.", LOGGER_DEBUG);
}
}
function poller_too_much_workers($stage) {
function poller_too_much_workers() {
$queues = get_config("system", "worker_queues");
if ($queues == 0)
$queues = 4;
$maxqueues = $queues;
$active = poller_active_workers();
// Decrease the number of workers at higher load
@ -276,21 +321,154 @@ function poller_too_much_workers($stage) {
$slope = $maxworkers / pow($maxsysload, $exponent);
$queues = ceil($slope * pow(max(0, $maxsysload - $load), $exponent));
logger("Current load stage ".$stage.": ".$load." - maximum: ".$maxsysload." - current queues: ".$active." - maximum: ".$queues, LOGGER_DEBUG);
$s = q("SELECT COUNT(*) AS `total` FROM `workerqueue` WHERE `executed` = '0000-00-00 00:00:00'");
$entries = $s[0]["total"];
if (Config::get("system", "worker_fastlane", false) AND ($queues > 0) AND ($entries > 0) AND ($active >= $queues)) {
$s = q("SELECT `priority` FROM `workerqueue` WHERE `executed` = '0000-00-00 00:00:00' ORDER BY `priority` LIMIT 1");
$top_priority = $s[0]["priority"];
$s = q("SELECT `id` FROM `workerqueue` WHERE `priority` <= %d AND `executed` != '0000-00-00 00:00:00' LIMIT 1",
intval($top_priority));
$high_running = dbm::is_result($s);
if (!$high_running AND ($top_priority > PRIORITY_UNDEFINED) AND ($top_priority < PRIORITY_NEGLIGIBLE)) {
logger("There are jobs with priority ".$top_priority." waiting but none is executed. Open a fastlane.", LOGGER_DEBUG);
$queues = $active + 1;
}
}
// Create a list of queue entries grouped by their priority
$running = array(PRIORITY_CRITICAL => 0,
PRIORITY_HIGH => 0,
PRIORITY_MEDIUM => 0,
PRIORITY_LOW => 0,
PRIORITY_NEGLIGIBLE => 0);
$r = q("SELECT COUNT(*) AS `running`, `priority` FROM `process` INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid` GROUP BY `priority`");
if (dbm::is_result($r))
foreach ($r AS $process)
$running[$process["priority"]] = $process["running"];
$processlist = "";
$r = q("SELECT COUNT(*) AS `entries`, `priority` FROM `workerqueue` GROUP BY `priority`");
if (dbm::is_result($r))
foreach ($r as $entry) {
if ($processlist != "")
$processlist .= ", ";
$processlist .= $entry["priority"].":".$running[$entry["priority"]]."/".$entry["entries"];
}
logger("Load: ".$load."/".$maxsysload." - processes: ".$active."/".$entries." (".$processlist.") - maximum: ".$queues."/".$maxqueues, LOGGER_DEBUG);
// Are there fewer workers running as possible? Then fork a new one.
if (!get_config("system", "worker_dont_fork") AND ($queues > ($active + 1)) AND ($entries > 1)) {
logger("Active workers: ".$active."/".$queues." Fork a new worker.", LOGGER_DEBUG);
$args = array("php", "include/poller.php", "no_cron");
$a = get_app();
$a->proc_run($args);
}
}
return($active >= $queues);
}
function poller_active_workers() {
$workers = q("SELECT COUNT(*) AS `workers` FROM `workerqueue` WHERE `executed` != '0000-00-00 00:00:00'");
$workers = q("SELECT COUNT(*) AS `processes` FROM `process` WHERE `command` = 'poller.php'");
return($workers[0]["workers"]);
return($workers[0]["processes"]);
}
/**
* @brief Check if we should pass some slow processes
*
* When the active processes of the highest priority are using more than 2/3
* of all processes, we let pass slower processes.
*
* @param string $highest_priority Returns the currently highest priority
* @return bool We let pass a slower process than $highest_priority
*/
function poller_passing_slow(&$highest_priority) {
$highest_priority = 0;
$r = q("SELECT `priority`
FROM `process`
INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid`
WHERE `process`.`command` = 'poller.php'");
// No active processes at all? Fine
if (!dbm::is_result($r))
return(false);
$priorities = array();
foreach ($r AS $line)
$priorities[] = $line["priority"];
// Should not happen
if (count($priorities) == 0)
return(false);
$highest_priority = min($priorities);
// The highest process is already the slowest one?
// Then we quit
if ($highest_priority == PRIORITY_NEGLIGIBLE)
return(false);
$high = 0;
foreach ($priorities AS $priority)
if ($priority == $highest_priority)
++$high;
logger("Highest priority: ".$highest_priority." Total processes: ".count($priorities)." Count high priority processes: ".$high, LOGGER_DEBUG);
$passing_slow = (($high/count($priorities)) > (2/3));
if ($passing_slow)
logger("Passing slower processes than priority ".$highest_priority, LOGGER_DEBUG);
return($passing_slow);
}
/**
* @brief Returns the next worker process
*
* @return string SQL statement
*/
function poller_worker_process() {
q("START TRANSACTION;");
// Check if we should pass some low priority process
$highest_priority = 0;
if (poller_passing_slow($highest_priority)) {
// Are there waiting processes with a higher priority than the currently highest?
$r = q("SELECT * FROM `workerqueue`
WHERE `executed` = '0000-00-00 00:00:00' AND `priority` < %d
ORDER BY `priority`, `created` LIMIT 1", dbesc($highest_priority));
if (dbm::is_result($r))
return $r;
// Give slower processes some processing time
$r = q("SELECT * FROM `workerqueue`
WHERE `executed` = '0000-00-00 00:00:00' AND `priority` > %d
ORDER BY `priority`, `created` LIMIT 1", dbesc($highest_priority));
}
// If there is no result (or we shouldn't pass lower processes) we check without priority limit
if (($highest_priority == 0) OR !dbm::is_result($r))
$r = q("SELECT * FROM `workerqueue` WHERE `executed` = '0000-00-00 00:00:00' ORDER BY `priority`, `created` LIMIT 1");
return $r;
}
if (array_search(__file__,get_included_files())===0){
poller_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
poller_run($_SERVER["argv"],$_SERVER["argc"]);
get_app()->end_process();
killme();
}
?>

View file

@ -8,11 +8,18 @@
*/
function post_update() {
if (!post_update_1192())
if (!post_update_1192()) {
return;
if (!post_update_1194())
}
if (!post_update_1194()) {
return;
}
if (!post_update_1198()) {
return;
}
if (!post_update_1206()) {
return;
}
}
/**
@ -138,4 +145,118 @@ function post_update_1194() {
logger("Done", LOGGER_DEBUG);
}
/**
* @brief set the author-id and owner-id in all item entries
*
* This job has to be started multiple times until all entries are set.
* It isn't started in the update function since it would consume too much time and can be done in the background.
*
* @return bool "true" when the job is done
*/
function post_update_1198() {
// Was the script completed?
if (get_config("system", "post_update_version") >= 1198)
return true;
logger("Start", LOGGER_DEBUG);
// Check if the first step is done (Setting "author-id" and "owner-id" in the item table)
$r = q("SELECT `author-link`, `owner-link`, `uid` FROM `item` WHERE `author-id` = 0 AND `owner-id` = 0 LIMIT 100");
if (!$r) {
// Are there unfinished entries in the thread table?
$r = q("SELECT COUNT(*) AS `total` FROM `thread`
INNER JOIN `item` ON `item`.`id` =`thread`.`iid`
WHERE `thread`.`author-id` = 0 AND `thread`.`owner-id` = 0 AND
(`thread`.`uid` IN (SELECT `uid` from `user`) OR `thread`.`uid` = 0)");
if ($r AND ($r[0]["total"] == 0)) {
set_config("system", "post_update_version", 1198);
logger("Done", LOGGER_DEBUG);
return true;
}
// Update the thread table from the item table
$r = q("UPDATE `thread` INNER JOIN `item` ON `item`.`id`=`thread`.`iid`
SET `thread`.`author-id` = `item`.`author-id`,
`thread`.`owner-id` = `item`.`owner-id`
WHERE `thread`.`author-id` = 0 AND `thread`.`owner-id` = 0 AND
(`thread`.`uid` IN (SELECT `uid` from `user`) OR `thread`.`uid` = 0)");
logger("Updated threads", LOGGER_DEBUG);
if (dbm::is_result($r)) {
set_config("system", "post_update_version", 1198);
logger("Done", LOGGER_DEBUG);
return true;
}
return false;
}
logger("Query done", LOGGER_DEBUG);
$item_arr = array();
foreach ($r AS $item) {
$index = $item["author-link"]."-".$item["owner-link"]."-".$item["uid"];
$item_arr[$index] = array("author-link" => $item["author-link"],
"owner-link" => $item["owner-link"],
"uid" => $item["uid"]);
}
// Set the "gcontact-id" in the item table and add a new gcontact entry if needed
foreach($item_arr AS $item) {
$author_id = get_contact($item["author-link"], 0);
$owner_id = get_contact($item["owner-link"], 0);
if ($author_id == 0)
$author_id = -1;
if ($owner_id == 0)
$owner_id = -1;
q("UPDATE `item` SET `author-id` = %d, `owner-id` = %d
WHERE `uid` = %d AND `author-link` = '%s' AND `owner-link` = '%s'
AND `author-id` = 0 AND `owner-id` = 0",
intval($author_id), intval($owner_id), intval($item["uid"]),
dbesc($item["author-link"]), dbesc($item["owner-link"]));
}
logger("Updated items", LOGGER_DEBUG);
return false;
}
/**
* @brief update the "last-item" field in the "self" contact
*
* This field avoids cost intensive calls in the admin panel and in "nodeinfo"
*
* @return bool "true" when the job is done
*/
function post_update_1206() {
// Was the script completed?
if (get_config("system", "post_update_version") >= 1206)
return true;
logger("Start", LOGGER_DEBUG);
$r = q("SELECT `contact`.`id`, `contact`.`last-item`,
(SELECT MAX(`changed`) FROM `item` FORCE INDEX (`uid_wall_changed`) WHERE `wall` AND `uid` = `user`.`uid`) AS `lastitem_date`
FROM `user`
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`");
if (!dbm::is_result($r)) {
return false;
}
foreach ($r AS $user) {
if (!empty($user["lastitem_date"]) AND ($user["lastitem_date"] > $user["last-item"])) {
q("UPDATE `contact` SET `last-item` = '%s' WHERE `id` = %d",
dbesc($user["lastitem_date"]),
intval($user["id"]));
}
}
set_config("system", "post_update_version", 1206);
logger("Done", LOGGER_DEBUG);
return true;
}
?>

View file

@ -2,60 +2,57 @@
require_once("boot.php");
require_once("include/ostatus.php");
function handle_pubsubhubbub() {
use \Friendica\Core\Config;
use \Friendica\Core\PConfig;
function handle_pubsubhubbub($id) {
global $a, $db;
logger('start');
$r = q("SELECT * FROM `push_subscriber` WHERE `id` = %d", intval($id));
if (!$r)
return;
else
$rr = $r[0];
// We'll push to each subscriber that has push > 0,
// i.e. there has been an update (set in notifier.php).
logger("Generate feed of user ".$rr['nickname']." to ".$rr['callback_url']." - last updated ".$rr['last_update'], LOGGER_DEBUG);
$r = q("SELECT * FROM `push_subscriber` WHERE `push` > 0");
$params = ostatus::feed($a, $rr['nickname'], $rr['last_update']);
$hmac_sig = hash_hmac("sha1", $params, $rr['secret']);
foreach($r as $rr) {
$headers = array("Content-type: application/atom+xml",
sprintf("Link: <%s>;rel=hub,<%s>;rel=self",
$a->get_baseurl().'/pubsubhubbub',
$rr['topic']),
"X-Hub-Signature: sha1=".$hmac_sig);
logger("Generate feed for user ".$rr['nickname']." - last updated ".$rr['last_update'], LOGGER_DEBUG);
logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG);
$params = ostatus::feed($a, $rr['nickname'], $rr['last_update']);
$hmac_sig = hash_hmac("sha1", $params, $rr['secret']);
post_url($rr['callback_url'], $params, $headers);
$ret = $a->get_curl_code();
$headers = array("Content-type: application/atom+xml",
sprintf("Link: <%s>;rel=hub,<%s>;rel=self",
$a->get_baseurl().'/pubsubhubbub',
$rr['topic']),
"X-Hub-Signature: sha1=".$hmac_sig);
if ($ret >= 200 && $ret <= 299) {
logger('successfully pushed to '.$rr['callback_url']);
logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG);
// set last_update to "now", and reset push=0
$date_now = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d",
dbesc($date_now),
intval($rr['id']));
post_url($rr['callback_url'], $params, $headers);
$ret = $a->get_curl_code();
} else {
logger('error when pushing to '.$rr['callback_url'].' HTTP: '.$ret);
if ($ret >= 200 && $ret <= 299) {
logger('successfully pushed to '.$rr['callback_url']);
// we use the push variable also as a counter, if we failed we
// increment this until some upper limit where we give up
$new_push = intval($rr['push']) + 1;
// set last_update to "now", and reset push=0
$date_now = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d",
dbesc($date_now),
intval($rr['id']));
if ($new_push > 30) // OK, let's give up
$new_push = 0;
} else {
logger('error when pushing to '.$rr['callback_url'].' HTTP: '.$ret);
// we use the push variable also as a counter, if we failed we
// increment this until some upper limit where we give up
$new_push = intval($rr['push']) + 1;
if ($new_push > 30) // OK, let's give up
$new_push = 0;
q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d",
$new_push,
intval($rr['id']));
}
q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d",
$new_push,
intval($rr['id']));
}
logger('done');
}
@ -89,10 +86,28 @@ function pubsubpublish_run(&$argv, &$argc){
if($argc > 1)
$pubsubpublish_id = intval($argv[1]);
else
$pubsubpublish_id = 0;
else {
// We'll push to each subscriber that has push > 0,
// i.e. there has been an update (set in notifier.php).
$r = q("SELECT `id`, `callback_url` FROM `push_subscriber` WHERE `push` > 0");
handle_pubsubhubbub();
// Use the delivery interval that is also used for the notifier
$interval = Config::get("system", "delivery_interval", 2);
// If we are using the worker we don't need a delivery interval
if (get_config("system", "worker"))
$interval = false;
foreach($r as $rr) {
logger("Publish feed to ".$rr["callback_url"], LOGGER_DEBUG);
proc_run(PRIORITY_HIGH, 'include/pubsubpublish.php', $rr["id"]);
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
}
}
handle_pubsubhubbub($pubsubpublish_id);
return;

View file

@ -17,7 +17,6 @@ function queue_run(&$argv, &$argc){
unset($db_host, $db_user, $db_pass, $db_data);
};
require_once("include/session.php");
require_once("include/datetime.php");
require_once('include/items.php');
@ -45,55 +44,57 @@ function queue_run(&$argv, &$argc){
$deadservers = array();
$serverlist = array();
logger('queue: start');
if (!$queue_id) {
// Handling the pubsubhubbub requests
proc_run('php','include/pubsubpublish.php');
logger('queue: start');
$interval = ((get_config('system','delivery_interval') === false) ? 2 : intval(get_config('system','delivery_interval')));
// Handling the pubsubhubbub requests
proc_run(PRIORITY_HIGH,'include/pubsubpublish.php');
// If we are using the worker we don't need a delivery interval
if (get_config("system", "worker"))
$interval = false;
$interval = ((get_config('system','delivery_interval') === false) ? 2 : intval(get_config('system','delivery_interval')));
$r = q("select * from deliverq where 1");
if($r) {
foreach($r as $rr) {
logger('queue: deliverq');
proc_run('php','include/delivery.php',$rr['cmd'],$rr['item'],$rr['contact']);
if($interval)
// If we are using the worker we don't need a delivery interval
if (get_config("system", "worker"))
$interval = false;
$r = q("select * from deliverq where 1");
if($r) {
foreach($r as $rr) {
logger('queue: deliverq');
proc_run(PRIORITY_HIGH,'include/delivery.php',$rr['cmd'],$rr['item'],$rr['contact']);
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
}
}
}
$r = q("SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue`
INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id`
WHERE `queue`.`created` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
if($r) {
foreach($r as $rr) {
logger('Removing expired queue item for ' . $rr['name'] . ', uid=' . $rr['uid']);
logger('Expired queue data :' . $rr['content'], LOGGER_DATA);
$r = q("SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue`
INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id`
WHERE `queue`.`created` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
if($r) {
foreach($r as $rr) {
logger('Removing expired queue item for ' . $rr['name'] . ', uid=' . $rr['uid']);
logger('Expired queue data :' . $rr['content'], LOGGER_DATA);
}
q("DELETE FROM `queue` WHERE `created` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
}
q("DELETE FROM `queue` WHERE `created` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
}
if($queue_id) {
$r = q("SELECT `id` FROM `queue` WHERE `id` = %d LIMIT 1",
intval($queue_id)
);
}
else {
// For the first 12 hours we'll try to deliver every 15 minutes
// After that, we'll only attempt delivery once per hour.
$r = q("SELECT `id` FROM `queue` WHERE ((`created` > UTC_TIMESTAMP() - INTERVAL 12 HOUR && `last` < UTC_TIMESTAMP() - INTERVAL 15 MINUTE) OR (`last` < UTC_TIMESTAMP() - INTERVAL 1 HOUR)) ORDER BY `cid`, `created`");
} else {
logger('queue: start for id '.$queue_id);
$r = q("SELECT `id` FROM `queue` WHERE `id` = %d LIMIT 1",
intval($queue_id)
);
}
if(! $r){
if (!$r){
return;
}
if(! $queue_id)
if (!$queue_id)
call_hooks('queue_predeliver', $a, $r);
@ -107,16 +108,17 @@ function queue_run(&$argv, &$argc){
// queue_predeliver hooks may have changed the queue db details,
// so check again if this entry still needs processing
if($queue_id) {
if($queue_id)
$qi = q("SELECT * FROM `queue` WHERE `id` = %d LIMIT 1",
intval($queue_id)
);
}
else {
intval($queue_id));
elseif (get_config("system", "worker")) {
logger('Call queue for id '.$q_item['id']);
proc_run(PRIORITY_LOW, "include/queue.php", $q_item['id']);
continue;
} else
$qi = q("SELECT * FROM `queue` WHERE `id` = %d AND `last` < UTC_TIMESTAMP() - INTERVAL 15 MINUTE ",
intval($q_item['id'])
);
}
intval($q_item['id']));
if(! count($qi))
continue;

View file

@ -1,15 +1,14 @@
<?php
require_once('include/crypto.php');
require_once('include/Probe.php');
function get_salmon_key($uri,$keyhash) {
$ret = array();
logger('Fetching salmon key for '.$uri);
$arr = lrdd($uri);
$arr = Probe::lrdd($uri);
if(is_array($arr)) {
foreach($arr as $a) {
@ -32,8 +31,7 @@ function get_salmon_key($uri,$keyhash) {
$ret[$x] = substr($ret[$x],strpos($ret[$x],',')+1);
else
$ret[$x] = substr($ret[$x],5);
}
else
} elseif (normalise_link($ret[$x]) == 'http://')
$ret[$x] = fetch_url($ret[$x]);
}
}

View file

@ -79,11 +79,9 @@ function authenticate_success($user_record, $login_initial = false, $interactive
header('X-Account-Management-Status: active; name="' . $a->user['username'] . '"; id="' . $a->user['nickname'] .'"');
if($login_initial || $login_refresh) {
$l = get_browser_language();
q("UPDATE `user` SET `login_date` = '%s', `language` = '%s' WHERE `uid` = %d",
q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d",
dbesc(datetime_convert()),
dbesc($l),
intval($_SESSION['uid'])
);

View file

@ -1,76 +1,111 @@
<?php
// Session management functions. These provide database storage of PHP
// session info.
require_once('include/cache.php');
$session_exists = 0;
$session_expire = 180000;
if(! function_exists('ref_session_open')) {
function ref_session_open ($s,$n) {
function ref_session_open($s, $n) {
return true;
}}
}
if(! function_exists('ref_session_read')) {
function ref_session_read ($id) {
function ref_session_read($id) {
global $session_exists;
if(x($id))
$r = q("SELECT `data` FROM `session` WHERE `sid`= '%s'", dbesc($id));
if(count($r)) {
if (!x($id)) {
return '';
}
$memcache = cache::memcache();
if (is_object($memcache)) {
$data = $memcache->get(get_app()->get_hostname().":session:".$id);
if (!is_bool($data)) {
return $data;
}
logger("no data for session $id", LOGGER_TRACE);
return '';
}
$r = q("SELECT `data` FROM `session` WHERE `sid`= '%s'", dbesc($id));
if (dbm::is_result($r)) {
$session_exists = true;
return $r[0]['data'];
} else {
logger("no data for session $id", LOGGER_TRACE);
}
return '';
}}
if(! function_exists('ref_session_write')) {
function ref_session_write ($id,$data) {
return '';
}
/**
* @brief Standard PHP session write callback
*
* This callback updates the DB-stored session data and/or the expiration depending
* on the case. Uses the $session_expire global for existing session, 5 minutes
* for newly created session.
*
* @global bool $session_exists Whether a session with the given id already exists
* @global int $session_expire Session expiration delay in seconds
* @param string $id Session ID with format: [a-z0-9]{26}
* @param string $data Serialized session data
* @return boolean Returns false if parameters are missing, true otherwise
*/
function ref_session_write($id, $data) {
global $session_exists, $session_expire;
if(! $id || ! $data) {
if (!$id || !$data) {
return false;
}
$expire = time() + $session_expire;
$default_expire = time() + 300;
if($session_exists) {
$r = q("UPDATE `session`
SET `data` = '%s'
WHERE `data` != '%s' AND `sid` = '%s'",
dbesc($data), dbesc($data), dbesc($id));
$memcache = cache::memcache();
if (is_object($memcache)) {
$memcache->set(get_app()->get_hostname().":session:".$id, $data, MEMCACHE_COMPRESSED, $expire);
return true;
}
if ($session_exists) {
$r = q("UPDATE `session`
SET `expire` = '%s'
WHERE `expire` != '%s' AND `sid` = '%s'",
dbesc($expire), dbesc($expire), dbesc($id));
} else
SET `data` = '%s', `expire` = '%s'
WHERE `sid` = '%s'
AND (`data` != '%s' OR `expire` != '%s')",
dbesc($data), dbesc($expire), dbesc($id), dbesc($data), dbesc($expire));
} else {
$r = q("INSERT INTO `session`
SET `sid` = '%s', `expire` = '%s', `data` = '%s'",
dbesc($id), dbesc($default_expire), dbesc($data));
}
return true;
}}
}
if(! function_exists('ref_session_close')) {
function ref_session_close() {
return true;
}}
}
function ref_session_destroy($id) {
$memcache = cache::memcache();
if (is_object($memcache)) {
$memcache->delete(get_app()->get_hostname().":session:".$id);
return true;
}
if(! function_exists('ref_session_destroy')) {
function ref_session_destroy ($id) {
q("DELETE FROM `session` WHERE `sid` = '%s'", dbesc($id));
return true;
}}
if(! function_exists('ref_session_gc')) {
return true;
}
function ref_session_gc($expire) {
q("DELETE FROM `session` WHERE `expire` < %d", dbesc(time()));
return true;
}}
}
$gc_probability = 50;
@ -78,7 +113,8 @@ ini_set('session.gc_probability', $gc_probability);
ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_httponly', 1);
if (!get_config('system', 'disable_database_session'))
if (!get_config('system', 'disable_database_session')) {
session_set_save_handler('ref_session_open', 'ref_session_close',
'ref_session_read', 'ref_session_write',
'ref_session_destroy', 'ref_session_gc');
}

View file

@ -9,6 +9,7 @@
require_once('include/datetime.php');
require_once("include/Scrape.php");
require_once("include/network.php");
require_once("include/html2bbcode.php");
require_once("include/Contact.php");
require_once("include/Photo.php");
@ -51,7 +52,7 @@ function poco_load($cid,$uid = 0,$zcid = 0,$url = null) {
if(! $url)
return;
$url = $url . (($uid) ? '/@me/@all?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation' : '?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation') ;
$url = $url . (($uid) ? '/@me/@all?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation' : '?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation') ;
logger('poco_load: ' . $url, LOGGER_DEBUG);
@ -85,6 +86,7 @@ function poco_load($cid,$uid = 0,$zcid = 0,$url = null) {
$about = '';
$keywords = '';
$gender = '';
$contact_type = -1;
$generation = 0;
$name = $entry->displayName;
@ -132,6 +134,9 @@ function poco_load($cid,$uid = 0,$zcid = 0,$url = null) {
foreach($entry->tags as $tag)
$keywords = implode(", ", $tag);
if(isset($entry->contactType) AND ($entry->contactType >= 0))
$contact_type = $entry->contactType;
// If you query a Friendica server for its profiles, the network has to be Friendica
/// TODO It could also be a Redmatrix server
//if ($uid == 0)
@ -139,6 +144,9 @@ function poco_load($cid,$uid = 0,$zcid = 0,$url = null) {
poco_check($profile_url, $name, $network, $profile_photo, $about, $location, $gender, $keywords, $connect_url, $updated, $generation, $cid, $uid, $zcid);
$gcontact = array("url" => $profile_url, "contact-type" => $contact_type, "generation" => $generation);
update_gcontact($gcontact);
// Update the Friendica contacts. Diaspora is doing it via a message. (See include/diaspora.php)
// Deactivated because we now update Friendica contacts in dfrn.php
//if (($location != "") OR ($about != "") OR ($keywords != "") OR ($gender != ""))
@ -1067,8 +1075,14 @@ function all_friends($uid,$cid,$start = 0, $limit = 80) {
function suggestion_query($uid, $start = 0, $limit = 80) {
if(! $uid)
if (!$uid) {
return array();
}
$list = Cache::get("suggestion_query:".$uid.":".$start.":".$limit);
if (!is_null($list)) {
return $list;
}
$network = array(NETWORK_DFRN);
@ -1079,9 +1093,10 @@ function suggestion_query($uid, $start = 0, $limit = 80) {
$network[] = NETWORK_OSTATUS;
$sql_network = implode("', '", $network);
//$sql_network = "'".$sql_network."', ''";
$sql_network = "'".$sql_network."'";
/// @todo This query is really slow
// By now we cache the data for five minutes
$r = q("SELECT count(glink.gcid) as `total`, gcontact.* from gcontact
INNER JOIN `glink` ON `glink`.`gcid` = `gcontact`.`id`
where uid = %d and not gcontact.nurl in ( select nurl from contact where uid = %d )
@ -1100,8 +1115,10 @@ function suggestion_query($uid, $start = 0, $limit = 80) {
intval($limit)
);
if(count($r) && count($r) >= ($limit -1))
if (count($r) && count($r) >= ($limit -1)) {
Cache::set("suggestion_query:".$uid.":".$start.":".$limit, $r, CACHE_FIVE_MINUTES);
return $r;
}
$r2 = q("SELECT gcontact.* FROM gcontact
INNER JOIN `glink` ON `glink`.`gcid` = `gcontact`.`id`
@ -1130,6 +1147,7 @@ function suggestion_query($uid, $start = 0, $limit = 80) {
while (sizeof($list) > ($limit))
array_pop($list);
Cache::set("suggestion_query:".$uid.":".$start.":".$limit, $list, CACHE_FIVE_MINUTES);
return $list;
}
@ -1235,7 +1253,7 @@ function poco_discover($complete = false) {
}
// Fetch all users from the other server
$url = $server["poco"]."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation";
$url = $server["poco"]."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation";
logger("Fetch all users from the server ".$server["nurl"], LOGGER_DEBUG);
@ -1254,7 +1272,7 @@ function poco_discover($complete = false) {
$updatedSince = date("Y-m-d H:i:s", time() - $timeframe * 86400);
// Fetch all global contacts from the other server (Not working with Redmatrix and Friendica versions before 3.3)
$url = $server["poco"]."/@global?updatedSince=".$updatedSince."&fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation";
$url = $server["poco"]."/@global?updatedSince=".$updatedSince."&fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation";
$success = false;
@ -1302,7 +1320,7 @@ function poco_discover_server_users($data, $server) {
logger("Fetch contacts for the user ".$username." from the server ".$server["nurl"], LOGGER_DEBUG);
// Fetch all contacts from a given user from the other server
$url = $server["poco"]."/".$username."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation";
$url = $server["poco"]."/".$username."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation";
$retdata = z_fetch_url($url);
if ($retdata["success"])
@ -1329,6 +1347,7 @@ function poco_discover_server($data, $default_generation = 0) {
$about = '';
$keywords = '';
$gender = '';
$contact_type = -1;
$generation = $default_generation;
$name = $entry->displayName;
@ -1373,6 +1392,9 @@ function poco_discover_server($data, $default_generation = 0) {
if(isset($entry->generation) AND ($entry->generation > 0))
$generation = ++$entry->generation;
if(isset($entry->contactType) AND ($entry->contactType >= 0))
$contact_type = $entry->contactType;
if(isset($entry->tags))
foreach($entry->tags as $tag)
$keywords = implode(", ", $tag);
@ -1382,6 +1404,10 @@ function poco_discover_server($data, $default_generation = 0) {
logger("Store profile ".$profile_url, LOGGER_DEBUG);
poco_check($profile_url, $name, $network, $profile_photo, $about, $location, $gender, $keywords, $connect_url, $updated, $generation, 0, 0, 0);
$gcontact = array("url" => $profile_url, "contact-type" => $contact_type, "generation" => $generation);
update_gcontact($gcontact);
logger("Done for profile ".$profile_url, LOGGER_DEBUG);
}
}
@ -1506,7 +1532,7 @@ function get_gcontact_id($contact) {
if ($doprobing) {
logger("Last Contact: ". $last_contact_str." - Last Failure: ".$last_failure_str." - Checking: ".$contact["url"], LOGGER_DEBUG);
proc_run('php', 'include/gprobe.php', bin2hex($contact["url"]));
proc_run(PRIORITY_LOW, 'include/gprobe.php', bin2hex($contact["url"]));
}
if ((count($r) > 1) AND ($gcontact_id > 0) AND ($contact["url"] != ""))
@ -1533,7 +1559,7 @@ function update_gcontact($contact) {
return false;
$r = q("SELECT `name`, `nick`, `photo`, `location`, `about`, `addr`, `generation`, `birthday`, `gender`, `keywords`,
`hide`, `nsfw`, `network`, `alias`, `notify`, `server_url`, `connect`, `updated`, `url`
`contact-type`, `hide`, `nsfw`, `network`, `alias`, `notify`, `server_url`, `connect`, `updated`, `url`
FROM `gcontact` WHERE `id` = %d LIMIT 1",
intval($gcontact_id));
@ -1613,20 +1639,20 @@ function update_gcontact($contact) {
}
if ($update) {
logger("Update gcontact for ".$contact["url"]." Callstack: ".App::callstack(), LOGGER_DEBUG);
logger("Update gcontact for ".$contact["url"], LOGGER_DEBUG);
q("UPDATE `gcontact` SET `photo` = '%s', `name` = '%s', `nick` = '%s', `addr` = '%s', `network` = '%s',
`birthday` = '%s', `gender` = '%s', `keywords` = '%s', `hide` = %d, `nsfw` = %d,
`alias` = '%s', `notify` = '%s', `url` = '%s',
`contact-type` = %d, `alias` = '%s', `notify` = '%s', `url` = '%s',
`location` = '%s', `about` = '%s', `generation` = %d, `updated` = '%s',
`server_url` = '%s', `connect` = '%s'
WHERE `nurl` = '%s' AND (`generation` = 0 OR `generation` >= %d)",
dbesc($contact["photo"]), dbesc($contact["name"]), dbesc($contact["nick"]),
dbesc($contact["addr"]), dbesc($contact["network"]), dbesc($contact["birthday"]),
dbesc($contact["gender"]), dbesc($contact["keywords"]), intval($contact["hide"]),
intval($contact["nsfw"]), dbesc($contact["alias"]), dbesc($contact["notify"]),
dbesc($contact["url"]), dbesc($contact["location"]), dbesc($contact["about"]),
intval($contact["generation"]), dbesc($contact["updated"]),
intval($contact["nsfw"]), intval($contact["contact-type"]), dbesc($contact["alias"]),
dbesc($contact["notify"]), dbesc($contact["url"]), dbesc($contact["location"]),
dbesc($contact["about"]), intval($contact["generation"]), dbesc($contact["updated"]),
dbesc($contact["server_url"]), dbesc($contact["connect"]),
dbesc(normalise_link($contact["url"])), intval($contact["generation"]));
@ -1643,13 +1669,14 @@ function update_gcontact($contact) {
q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `addr` = '%s',
`network` = '%s', `bd` = '%s', `gender` = '%s',
`keywords` = '%s', `alias` = '%s', `url` = '%s',
`location` = '%s', `about` = '%s'
`keywords` = '%s', `alias` = '%s', `contact-type` = %d,
`url` = '%s', `location` = '%s', `about` = '%s'
WHERE `id` = %d",
dbesc($contact["name"]), dbesc($contact["nick"]), dbesc($contact["addr"]),
dbesc($contact["network"]), dbesc($contact["birthday"]), dbesc($contact["gender"]),
dbesc($contact["keywords"]), dbesc($contact["alias"]), dbesc($contact["url"]),
dbesc($contact["location"]), dbesc($contact["about"]), intval($r[0]["id"]));
dbesc($contact["keywords"]), dbesc($contact["alias"]), intval($contact["contact-type"]),
dbesc($contact["url"]), dbesc($contact["location"]), dbesc($contact["about"]),
intval($r[0]["id"]));
}
}

View file

@ -581,14 +581,14 @@ function get_intltext_template($s) {
if(! isset($lang))
$lang = 'en';
if(file_exists("view/$lang$engine/$s")) {
if(file_exists("view/lang/$lang$engine/$s")) {
$stamp1 = microtime(true);
$content = file_get_contents("view/$lang$engine/$s");
$content = file_get_contents("view/lang/$lang$engine/$s");
$a->save_timestamp($stamp1, "file");
return $content;
} elseif(file_exists("view/en$engine/$s")) {
} elseif(file_exists("view/lang/en$engine/$s")) {
$stamp1 = microtime(true);
$content = file_get_contents("view/en$engine/$s");
$content = file_get_contents("view/lang/en$engine/$s");
$a->save_timestamp($stamp1, "file");
return $content;
} else {
@ -678,11 +678,13 @@ function attribute_contains($attr,$s) {
return false;
}}
if(! function_exists('logger')) {
if (! function_exists('logger')) {
/* setup int->string log level map */
$LOGGER_LEVELS = array();
/**
* @brief Logs the given message at the given log level
*
* log levels:
* LOGGER_NORMAL (default)
* LOGGER_TRACE
@ -692,46 +694,63 @@ $LOGGER_LEVELS = array();
*
* @global App $a
* @global dba $db
* @global array $LOGGER_LEVELS
* @param string $msg
* @param int $level
*/
function logger($msg,$level = 0) {
// turn off logger in install mode
function logger($msg, $level = 0) {
global $a;
global $db;
global $LOGGER_LEVELS;
if(($a->module == 'install') || (! ($db && $db->connected))) return;
if (count($LOGGER_LEVELS)==0){
foreach (get_defined_constants() as $k=>$v){
if (substr($k,0,7)=="LOGGER_")
$LOGGER_LEVELS[$v] = substr($k,7,7);
}
// turn off logger in install mode
if (
$a->module == 'install'
|| ! ($db && $db->connected)
) {
return;
}
$debugging = get_config('system','debugging');
$loglevel = intval(get_config('system','loglevel'));
$logfile = get_config('system','logfile');
$loglevel = intval(get_config('system','loglevel'));
if((! $debugging) || (! $logfile) || ($level > $loglevel))
if (
! $debugging
|| ! $logfile
|| $level > $loglevel
) {
return;
}
if (count($LOGGER_LEVELS) == 0) {
foreach (get_defined_constants() as $k => $v) {
if (substr($k, 0, 7) == "LOGGER_") {
$LOGGER_LEVELS[$v] = substr($k, 7, 7);
}
}
}
$process_id = session_id();
if ($process_id == '') {
$process_id = get_app()->process_id;
}
$callers = debug_backtrace();
$logline = sprintf("%s@%s\t[%s]:%s:%s:%s\t%s\n",
datetime_convert(),
session_id(),
$LOGGER_LEVELS[$level],
basename($callers[0]['file']),
$callers[0]['line'],
$callers[1]['function'],
$msg
);
$logline = sprintf("%s@%s\t[%s]:%s:%s:%s\t%s\n",
datetime_convert(),
$process_id,
$LOGGER_LEVELS[$level],
basename($callers[0]['file']),
$callers[0]['line'],
$callers[1]['function'],
$msg
);
$stamp1 = microtime(true);
@file_put_contents($logfile, $logline, FILE_APPEND);
$a->save_timestamp($stamp1, "file");
return;
}}
@ -750,71 +769,75 @@ function activity_match($haystack,$needle) {
}}
if(! function_exists('get_tags')) {
/**
* Pull out all #hashtags and @person tags from $s;
* @brief Pull out all #hashtags and @person tags from $string.
*
* We also get @person@domain.com - which would make
* the regex quite complicated as tags can also
* end a sentence. So we'll run through our results
* and strip the period from any tags which end with one.
* Returns array of tags found, or empty array.
*
* @param string $s
* @return array
* @param string $string Post content
* @return array List of tag and person names
*/
function get_tags($s) {
function get_tags($string) {
$ret = array();
// Convert hashtag links to hashtags
$s = preg_replace("/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism", "#$2", $s);
$string = preg_replace('/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism', '#$2', $string);
// ignore anything in a code block
$s = preg_replace('/\[code\](.*?)\[\/code\]/sm','',$s);
$string = preg_replace('/\[code\](.*?)\[\/code\]/sm', '', $string);
// Force line feeds at bbtags
$s = str_replace(array("[", "]"), array("\n[", "]\n"), $s);
$string = str_replace(array('[', ']'), array("\n[", "]\n"), $string);
// ignore anything in a bbtag
$s = preg_replace('/\[(.*?)\]/sm','',$s);
$string = preg_replace('/\[(.*?)\]/sm', '', $string);
// Match full names against @tags including the space between first and last
// We will look these up afterward to see if they are full names or not recognisable.
if(preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/',$s,$match)) {
foreach($match[1] as $mtch) {
if(strstr($mtch,"]")) {
if (preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/', $string, $matches)) {
foreach ($matches[1] as $match) {
if (strstr($match, ']')) {
// we might be inside a bbcode color tag - leave it alone
continue;
}
if(substr($mtch,-1,1) === '.')
$ret[] = substr($mtch,0,-1);
else
$ret[] = $mtch;
if (substr($match, -1, 1) === '.') {
$ret[] = substr($match, 0, -1);
} else {
$ret[] = $match;
}
}
}
// Otherwise pull out single word tags. These can be @nickname, @first_last
// and #hash tags.
if(preg_match_all('/([!#@][^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/',$s,$match)) {
foreach($match[1] as $mtch) {
if(strstr($mtch,"]")) {
if (preg_match_all('/([!#@][^\^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/', $string, $matches)) {
foreach($matches[1] as $match) {
if (strstr($match, ']')) {
// we might be inside a bbcode color tag - leave it alone
continue;
}
if(substr($mtch,-1,1) === '.')
$mtch = substr($mtch,0,-1);
if (substr($match, -1, 1) === '.') {
$match = substr($match,0,-1);
}
// ignore strictly numeric tags like #1
if((strpos($mtch,'#') === 0) && ctype_digit(substr($mtch,1)))
if ((strpos($match, '#') === 0) && ctype_digit(substr($match, 1))) {
continue;
}
// try not to catch url fragments
if(strpos($s,$mtch) && preg_match('/[a-zA-z0-9\/]/',substr($s,strpos($s,$mtch)-1,1)))
if (strpos($string, $match) && preg_match('/[a-zA-z0-9\/]/', substr($string, strpos($string, $match) - 1, 1))) {
continue;
$ret[] = $mtch;
}
$ret[] = $match;
}
}
return $ret;
}}
}
//
@ -867,7 +890,8 @@ function contact_block() {
$micropro = Null;
} else {
$r = q("SELECT `id`, `uid`, `addr`, `url`, `name`, `micro`, `network` FROM `contact`
// Splitting the query in two parts makes it much faster
$r = q("SELECT `id` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending`
AND NOT `hidden` AND NOT `archive`
AND `network` IN ('%s', '%s', '%s') ORDER BY RAND() LIMIT %d",
@ -877,11 +901,19 @@ function contact_block() {
dbesc(NETWORK_DIASPORA),
intval($shown)
);
if(count($r)) {
$contacts = sprintf( tt('%d Contact','%d Contacts', $total),$total);
$micropro = Array();
foreach($r as $rr) {
$micropro[] = micropro($rr,true,'mpfriend');
if ($r) {
$contacts = "";
foreach ($r AS $contact)
$contacts[] = $contact["id"];
$r = q("SELECT `id`, `uid`, `addr`, `url`, `name`, `thumb`, `network` FROM `contact` WHERE `id` IN (%s)",
dbesc(implode(",", $contacts)));
if(count($r)) {
$contacts = sprintf( tt('%d Contact','%d Contacts', $total),$total);
$micropro = Array();
foreach($r as $rr) {
$micropro[] = micropro($rr,true,'mpfriend');
}
}
}
}
@ -901,20 +933,28 @@ function contact_block() {
}}
if(! function_exists('micropro')) {
/**
* @brief Format contacts as picture links or as texxt links
*
* @param array $contact
* @param boolean $redirect
* @param string $class
* @param boolean $textmode
* @return string #FIXME: remove html
* @param array $contact Array with contacts which contains an array with
* int 'id' => The ID of the contact
* int 'uid' => The user ID of the user who owns this data
* string 'name' => The name of the contact
* string 'url' => The url to the profile page of the contact
* string 'addr' => The webbie of the contact (e.g.) username@friendica.com
* string 'network' => The network to which the contact belongs to
* string 'thumb' => The contact picture
* string 'click' => js code which is performed when clicking on the contact
* @param boolean $redirect If true try to use the redir url if it's possible
* @param string $class CSS class for the
* @param boolean $textmode If true display the contacts as text links
* if false display the contacts as picture links
* @return string Formatted html
*/
function micropro($contact, $redirect = false, $class = '', $textmode = false) {
if($class)
$class = ' ' . $class;
// Use the contact URL if no address is available
if ($contact["addr"] == "")
$contact["addr"] = $contact["url"];
@ -933,26 +973,23 @@ function micropro($contact, $redirect = false, $class = '', $textmode = false) {
else
$url = zrl($url);
}
$click = ((x($contact,'click')) ? ' onclick="' . $contact['click'] . '" ' : '');
if($click)
// If there is some js available we don't need the url
if(x($contact,'click'))
$url = '';
if($textmode) {
return '<div class="contact-block-textdiv' . $class . '"><a class="contact-block-link' . $class . $sparkle
. (($click) ? ' fakelink' : '') . '" '
. (($redir) ? ' target="redir" ' : '')
. (($url) ? ' href="' . $url . '"' : '') . $click
. '" title="' . $contact['name'] . ' [' . $contact['addr'] . ']" alt="' . $contact['name']
. '" >'. $contact['name'] . '</a></div>' . "\r\n";
}
else {
return '<div class="contact-block-div' . $class . '"><a class="contact-block-link' . $class . $sparkle
. (($click) ? ' fakelink' : '') . '" '
. (($redir) ? ' target="redir" ' : '')
. (($url) ? ' href="' . $url . '"' : '') . $click . ' ><img class="contact-block-img' . $class . $sparkle . '" src="'
. proxy_url($contact['micro'], false, PROXY_SIZE_THUMB) . '" title="' . $contact['name'] . ' [' . $contact['addr'] . ']" alt="' . $contact['name']
. '" /></a></div>' . "\r\n";
}
}}
return replace_macros(get_markup_template(($textmode)?'micropro_txt.tpl':'micropro_img.tpl'),array(
'$click' => (($contact['click']) ? $contact['click'] : ''),
'$class' => $class,
'$url' => $url,
'$photo' => proxy_url($contact['thumb'], false, PROXY_SIZE_THUMB),
'$name' => $contact['name'],
'title' => $contact['name'] . ' [' . $contact['addr'] . ']',
'$parkle' => $sparkle,
'$redir' => $redir,
));
}
@ -969,7 +1006,7 @@ function search($s,$id='search-box',$url='search',$save = false, $aside = true)
$a = get_app();
$values = array(
'$s' => $s,
'$s' => htmlspecialchars($s),
'$id' => $id,
'$action_url' => $url,
'$search_label' => t('Search'),
@ -2068,7 +2105,7 @@ function formatBytes($bytes, $precision = 2) {
/**
* @brief translate and format the networkname of a contact
*
*
* @param string $network
* Networkname of the contact (e.g. dfrn, rss and so on)
* @param sting $url
@ -2087,3 +2124,54 @@ function format_network_name($network, $url = 0) {
}
}
/**
* @brief Syntax based code highlighting for popular languages.
* @param string $s Code block
* @param string $lang Programming language
* @return string Formated html
*/
function text_highlight($s,$lang) {
if($lang === 'js')
$lang = 'javascript';
if(! strpos('Text_Highlighter',get_include_path())) {
set_include_path(get_include_path() . PATH_SEPARATOR . 'library/Text_Highlighter');
}
require_once('library/Text_Highlighter/Text/Highlighter.php');
require_once('library/Text_Highlighter/Text/Highlighter/Renderer/Html.php');
$options = array(
'numbers' => HL_NUMBERS_LI,
'tabsize' => 4,
);
$tag_added = false;
$s = trim(html_entity_decode($s,ENT_COMPAT));
$s = str_replace(" ","\t",$s);
// The highlighter library insists on an opening php tag for php code blocks. If
// it isn't present, nothing is highlighted. So we're going to see if it's present.
// If not, we'll add it, and then quietly remove it after we get the processed output back.
if($lang === 'php') {
if(strpos('<?php',$s) !== 0) {
$s = '<?php' . "\n" . $s;
$tag_added = true;
}
}
$renderer = new Text_Highlighter_Renderer_HTML($options);
$hl = Text_Highlighter::factory($lang);
$hl->setRenderer($renderer);
$o = $hl->highlight($s);
$o = str_replace([" ","\n"],["&nbsp;&nbsp;&nbsp;&nbsp;",''],$o);
if($tag_added) {
$b = substr($o,0,strpos($o,'<li>'));
$e = substr($o,strpos($o,'</li>'));
$o = $b . $e;
}
return('<code>' . $o . '</code>');
}

View file

@ -1,7 +1,9 @@
<?php
function add_thread($itemid, $onlyshadow = false) {
$items = q("SELECT `uid`, `created`, `edited`, `commented`, `received`, `changed`, `wall`, `private`, `pubmail`, `moderated`, `visible`, `spam`, `starred`, `bookmark`, `contact-id`, `gcontact-id`,
`deleted`, `origin`, `forum_mode`, `mention`, `network` FROM `item` WHERE `id` = %d AND (`parent` = %d OR `parent` = 0) LIMIT 1", intval($itemid), intval($itemid));
$items = q("SELECT `uid`, `created`, `edited`, `commented`, `received`, `changed`, `wall`, `private`, `pubmail`,
`moderated`, `visible`, `spam`, `starred`, `bookmark`, `contact-id`, `gcontact-id`,
`deleted`, `origin`, `forum_mode`, `mention`, `network`, `author-id`, `owner-id`
FROM `item` WHERE `id` = %d AND (`parent` = %d OR `parent` = 0) LIMIT 1", intval($itemid), intval($itemid));
if (!$items)
return;
@ -16,42 +18,70 @@ function add_thread($itemid, $onlyshadow = false) {
.implode("', '", array_values($item))
."')");
logger("add_thread: Add thread for item ".$itemid." - ".print_r($result, true), LOGGER_DEBUG);
logger("Add thread for item ".$itemid." - ".print_r($result, true), LOGGER_DEBUG);
}
}
/**
* @brief Add a shadow entry for a given item id that is a thread starter
*
* We store every public item entry additionally with the user id "0".
* This is used for the community page and for the search.
* It is planned that in the future we will store public item entries only once.
*
* @param integer $itemid Item ID that should be added
*/
function add_shadow_thread($itemid) {
$items = q("SELECT `uid`, `wall`, `private`, `moderated`, `visible`, `contact-id`, `deleted`, `network`
FROM `item` WHERE `id` = %d AND (`parent` = %d OR `parent` = 0) LIMIT 1", intval($itemid), intval($itemid));
if (!dbm::is_result($items)) {
return;
}
$item = $items[0];
// is it already a copy?
if (($itemid == 0) OR ($item['uid'] == 0))
if (($itemid == 0) OR ($item['uid'] == 0)) {
return;
}
// Is it a visible public post?
if (!$item["visible"] OR $item["deleted"] OR $item["moderated"] OR $item["private"])
if (!$item["visible"] OR $item["deleted"] OR $item["moderated"] OR $item["private"]) {
return;
}
// is it an entry from a connector? Only add an entry for natively connected networks
if (!in_array($item["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, "")))
if (!in_array($item["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""))) {
return;
}
// Only do these checks if the post isn't a wall post
if (!$item["wall"]) {
// Check, if hide-friends is activated - then don't do a shadow entry
$r = q("SELECT `hide-friends` FROM `profile` WHERE `is-default` AND `uid` = %d AND NOT `hide-friends`",
$item['uid']);
if (!count($r))
if (!dbm::is_result($r)) {
return;
}
// Check if the contact is hidden or blocked
$r = q("SELECT `id` FROM `contact` WHERE NOT `hidden` AND NOT `blocked` AND `id` = %d",
$item['contact-id']);
if (!count($r))
if (!dbm::is_result($r)) {
return;
}
}
// Only add a shadow, if the profile isn't hidden
$r = q("SELECT `uid` FROM `user` where `uid` = %d AND NOT `hidewall`", $item['uid']);
if (!count($r))
if (!dbm::is_result($r)) {
return;
}
$item = q("SELECT * FROM `item` WHERE `id` = %d",
intval($itemid));
$item = q("SELECT * FROM `item` WHERE `id` = %d", intval($itemid));
if (count($item) AND ($item[0]["allow_cid"] == '') AND ($item[0]["allow_gid"] == '') AND
($item[0]["deny_cid"] == '') AND ($item[0]["deny_gid"] == '')) {
@ -59,7 +89,7 @@ function add_thread($itemid, $onlyshadow = false) {
$r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = 0 LIMIT 1",
dbesc($item['uri']));
if (!$r) {
if (!dbm::is_result($r)) {
// Preparing public shadow (removing user specific data)
require_once("include/items.php");
require_once("include/Contact.php");
@ -67,15 +97,33 @@ function add_thread($itemid, $onlyshadow = false) {
unset($item[0]['id']);
$item[0]['uid'] = 0;
$item[0]['origin'] = 0;
$item[0]['wall'] = 0;
$item[0]['contact-id'] = get_contact($item[0]['author-link'], 0);
if (in_array($item[0]['type'], array("net-comment", "wall-comment"))) {
$item[0]['type'] = 'remote-comment';
} elseif ($item[0]['type'] == 'wall') {
$item[0]['type'] = 'remote';
}
$public_shadow = item_store($item[0], false, false, true);
logger("add_thread: Stored public shadow for post ".$itemid." under id ".$public_shadow, LOGGER_DEBUG);
logger("Stored public shadow for thread ".$itemid." under id ".$public_shadow, LOGGER_DEBUG);
}
}
}
function add_shadow_entry($item) {
/**
* @brief Add a shadow entry for a given item id that is a comment
*
* This function does the same like the function above - but for comments
*
* @param integer $itemid Item ID that should be added
*/
function add_shadow_entry($itemid) {
$items = q("SELECT * FROM `item` WHERE `id` = %d", intval($itemid));
$item = $items[0];
// Is this a shadow entry?
if ($item['uid'] == 0)
@ -97,7 +145,16 @@ function add_shadow_entry($item) {
unset($item['id']);
$item['uid'] = 0;
$item['origin'] = 0;
$item['wall'] = 0;
$item['contact-id'] = get_contact($item['author-link'], 0);
if (in_array($item['type'], array("net-comment", "wall-comment"))) {
$item['type'] = 'remote-comment';
} elseif ($item['type'] == 'wall') {
$item['type'] = 'remote';
}
$public_shadow = item_store($item, false, false, true);
logger("Stored public shadow for comment ".$item['uri']." under id ".$public_shadow, LOGGER_DEBUG);
@ -174,7 +231,7 @@ function delete_thread($itemid, $itemuri = "") {
intval($item["uid"])
);
if (!count($r)) {
$r = q("DELETE FROM `item` WHERE `uri` = '%s' AND `uid` = 0)",
$r = q("DELETE FROM `item` WHERE `uri` = '%s' AND `uid` = 0",
dbesc($itemuri)
);
logger("delete_thread: Deleted shadow for item ".$itemuri." - ".print_r($result, true), LOGGER_DEBUG);
@ -191,8 +248,10 @@ function update_threads() {
logger("update_threads: fetched messages: ".count($messages));
while ($message = $db->qfetch())
while ($message = $db->qfetch()) {
add_thread($message["id"]);
add_shadow_thread($message["id"]);
}
$db->qclose();
}
@ -225,7 +284,7 @@ function update_shadow_copy() {
logger("fetched messages: ".count($messages));
while ($message = $db->qfetch())
add_thread($message["iid"], true);
add_shadow_thread($message["iid"]);
$db->qclose();
}

View file

@ -287,7 +287,7 @@ function import_account(&$a, $file) {
}
// send relocate messages
proc_run('php', 'include/notifier.php', 'relocate', $newuid);
proc_run(PRIORITY_HIGH, 'include/notifier.php', 'relocate', $newuid);
info(t("Done. You can now login with your username and password"));
goaway($a->get_baseurl() . "/login");

View file

@ -27,8 +27,11 @@ class xml {
foreach ($namespaces AS $nskey => $nsvalue)
$key .= " xmlns".($nskey == "" ? "":":").$nskey.'="'.$nsvalue.'"';
$root = new SimpleXMLElement("<".$key."/>");
self::from_array($value, $root, $remove_header, $namespaces, false);
if (is_array($value)) {
$root = new SimpleXMLElement("<".$key."/>");
self::from_array($value, $root, $remove_header, $namespaces, false);
} else
$root = new SimpleXMLElement("<".$key.">".xmlify($value)."</".$key.">");
$dom = dom_import_simplexml($root)->ownerDocument;
$dom->formatOutput = true;
@ -44,7 +47,33 @@ class xml {
}
foreach($array as $key => $value) {
if ($key == "@attributes") {
if (!isset($element) AND isset($xml))
$element = $xml;
if (is_integer($key)) {
if (isset($element)) {
if (is_scalar($value)) {
$element[0] = $value;
} else {
/// @todo: handle nested array values
}
}
continue;
}
$element_parts = explode(":", $key);
if ((count($element_parts) > 1) AND isset($namespaces[$element_parts[0]]))
$namespace = $namespaces[$element_parts[0]];
elseif (isset($namespaces[""])) {
$namespace = $namespaces[""];
} else
$namespace = NULL;
// Remove undefined namespaces from the key
if ((count($element_parts) > 1) AND is_null($namespace))
$key = $element_parts[1];
if (substr($key, 0, 11) == "@attributes") {
if (!isset($element) OR !is_array($value))
continue;
@ -55,18 +84,12 @@ class xml {
else
$namespace = NULL;
$element->addAttribute ($attr_key, $attr_value, $namespace);
$element->addAttribute($attr_key, $attr_value, $namespace);
}
continue;
}
$element_parts = explode(":", $key);
if ((count($element_parts) > 1) AND isset($namespaces[$element_parts[0]]))
$namespace = $namespaces[$element_parts[0]];
else
$namespace = NULL;
if (!is_array($value))
$element = $xml->addChild($key, xmlify($value), $namespace);
elseif (is_array($value)) {
@ -131,11 +154,11 @@ class xml {
/**
* @brief Convert an XML document to a normalised, case-corrected array
* used by webfinger
*
*
* @param object $xml_element The XML document
* @param integer $recursion_depth recursion counter for internal use - default 0
* @param integer $recursion_depth recursion counter for internal use - default 0
* internal use, recursion counter
*
*
* @return array | sring The array from the xml element or the string
*/
public static function element_to_array($xml_element, &$recursion_depth=0) {
@ -181,23 +204,23 @@ class xml {
/**
* @brief Convert the given XML text to an array in the XML structure.
*
*
* xml::to_array() will convert the given XML text to an array in the XML structure.
* Link: http://www.bin-co.com/php/scripts/xml2array/
* Portions significantly re-written by mike@macgirvin.com for Friendica
* (namespaces, lowercase tags, get_attribute default changed, more...)
*
*
* Examples: $array = xml::to_array(file_get_contents('feed.xml'));
* $array = xml::to_array(file_get_contents('feed.xml', true, 1, 'attribute'));
*
*
* @param object $contents The XML text
* @param boolean $namespaces True or false include namespace information
* in the returned array as array elements.
* @param integer $get_attributes 1 or 0. If this is 1 the function will get the attributes as well as the tag values -
* @param integer $get_attributes 1 or 0. If this is 1 the function will get the attributes as well as the tag values -
* this results in a different array structure in the return value.
* @param string $priority Can be 'tag' or 'attribute'. This will change the way the resulting
* array sturcture. For 'tag', the tags are given more importance.
*
*
* @return array The parsed XML in an array form. Use print_r() to see the resulting array structure.
*/
public static function to_array($contents, $namespaces = true, $get_attributes=1, $priority = 'attribute') {

View file

@ -19,6 +19,10 @@ require_once('object/BaseObject.php');
$a = new App;
BaseObject::set_app($a);
// We assume that the index.php is called by a frontend process
// The value is set to "true" by default in boot.php
$a->backend = false;
/**
*
* Load the configuration file which contains our DB credentials.
@ -41,7 +45,6 @@ $install = ((file_exists('.htconfig.php') && filesize('.htconfig.php')) ? false
*/
require_once("include/dba.php");
require_once("include/dbm.php");
if(!$install) {
$db = new dba($db_host, $db_user, $db_pass, $db_data, $install);
@ -54,36 +57,13 @@ if(!$install) {
load_config('config');
load_config('system');
$processlist = dbm::processlist();
if ($processlist["list"] != "") {
logger("Processcheck: Processes: ".$processlist["amount"]." - Processlist: ".$processlist["list"], LOGGER_DEBUG);
$max_processes = get_config('system', 'max_processes_frontend');
if (intval($max_processes) == 0)
$max_processes = 20;
if ($processlist["amount"] > $max_processes) {
logger("Processcheck: Maximum number of processes for frontend tasks (".$max_processes.") reached.", LOGGER_DEBUG);
system_unavailable();
}
if ($a->max_processes_reached() OR $a->maxload_reached()) {
header($_SERVER["SERVER_PROTOCOL"].' 503 Service Temporarily Unavailable');
header('Retry-After: 120');
header('Refresh: 120; url='.$a->get_baseurl()."/".$a->query_string);
die("System is currently unavailable. Please try again later");
}
$maxsysload_frontend = intval(get_config('system','maxloadavg_frontend'));
if($maxsysload_frontend < 1)
$maxsysload_frontend = 50;
$load = current_load();
if($load) {
if($load > $maxsysload_frontend) {
logger('system: load ' . $load . ' too high. Service Temporarily Unavailable.');
header($_SERVER["SERVER_PROTOCOL"].' 503 Service Temporarily Unavailable');
header('Retry-After: 300');
die("System is currently unavailable. Please try again later");
}
}
if (get_config('system','force_ssl') AND ($a->get_scheme() == "http") AND
(intval(get_config('system','ssl_policy')) == SSL_POLICY_FULL) AND
(substr($a->get_baseurl(), 0, 8) == "https://")) {
@ -114,9 +94,12 @@ load_translation_table($lang);
*
*/
$stamp1 = microtime(true);
session_start();
$a->save_timestamp($stamp1, "parser");
// Exclude the backend processes from the session management
if (!$a->is_backend()) {
$stamp1 = microtime(true);
session_start();
$a->save_timestamp($stamp1, "parser");
}
/**
* Language was set earlier, but we can over-ride it in the session.
@ -126,7 +109,7 @@ if (x($_SESSION,'authenticated') && !x($_SESSION,'language')) {
// we didn't loaded user data yet, but we need user language
$r = q("SELECT language FROM user WHERE uid=%d", intval($_SESSION['uid']));
$_SESSION['language'] = $lang;
if (count($r)>0) $_SESSION['language'] = $r[0]['language'];
if (dbm::is_result($r)) $_SESSION['language'] = $r[0]['language'];
}
if((x($_SESSION,'language')) && ($_SESSION['language'] !== $lang)) {
@ -506,7 +489,8 @@ if (isset($_GET["mode"]) AND ($_GET["mode"] == "raw")) {
echo substr($target->saveHTML(), 6, -8);
session_write_close();
if (!$a->is_backend())
session_write_close();
exit;
}
@ -517,21 +501,20 @@ $profile = $a->profile;
header("X-Friendica-Version: ".FRIENDICA_VERSION);
header("Content-type: text/html; charset=utf-8");
if (isset($_GET["mode"]) AND ($_GET["mode"] == "minimal")) {
//$page['content'] = substr($target->saveHTML(), 6, -8)."\n\n".
// '<div id="conversation-end"></div>'."\n\n";
require "view/minimal.php";
} else {
$template = 'view/theme/' . current_theme() . '/'
. ((x($a->page,'template')) ? $a->page['template'] : 'default' ) . '.php';
if(file_exists($template))
require_once($template);
else
require_once(str_replace('theme/' . current_theme() . '/', '', $template));
// We use $_GET["mode"] for special page templates. So we will check if we have
// to load another page template than the default one
// The page templates are located in /view/php/ or in the theme directory
if (isset($_GET["mode"])) {
$template = theme_include($_GET["mode"].'.php');
}
session_write_close();
// If there is no page template use the default page template
if(!$template) {
$template = theme_include("default.php");
}
require_once($template);
if (!$a->is_backend())
session_write_close();
exit;

View file

@ -41,7 +41,7 @@ function contact_search(term, callback, backend_url, type, mode) {
postdata['conversation'] = conv_id[0];
if(mode !== null)
postdata['mode'] = mode;
postdata['smode'] = mode;
$.ajax({

View file

@ -5,36 +5,38 @@
function _resizeIframe(obj, desth) {
var h = obj.style.height;
var ch = obj.contentWindow.document.body.scrollHeight + 'px';
if (h==ch) {
var ch = obj.contentWindow.document.body.scrollHeight;
if (h == (ch + 'px')) {
return;
}
//console.log("_resizeIframe", obj, desth, ch);
if (desth!=ch) {
setTimeout(_resizeIframe, 500, obj, ch);
} else {
if (ch>0) obj.style.height = ch;
setTimeout(_resizeIframe, 1000, obj, ch);
if (desth == ch && ch>0) {
obj.style.height = ch + 'px';
}
setTimeout(_resizeIframe, 100, obj, ch);
}
function openClose(theID) {
if(document.getElementById(theID).style.display == "block") {
document.getElementById(theID).style.display = "none"
}
else {
document.getElementById(theID).style.display = "block"
}
}
function openClose(theID) {
if(document.getElementById(theID).style.display == "block") {
document.getElementById(theID).style.display = "none"
}
else {
document.getElementById(theID).style.display = "block"
}
}
function openMenu(theID) {
document.getElementById(theID).style.display = "block"
}
function openMenu(theID) {
document.getElementById(theID).style.display = "block"
}
function closeMenu(theID) {
document.getElementById(theID).style.display = "none"
}
function closeMenu(theID) {
document.getElementById(theID).style.display = "none"
}
function decodeHtml(html) {
var txt = document.createElement("textarea");
txt.innerHTML = html;
return txt.value;
}
var src = null;
@ -125,6 +127,7 @@
function close_last_popup_menu() {
if(last_popup_menu) {
last_popup_menu.hide();
last_popup_menu.off('click', function(e) {e.stopPropagation()});
last_popup_button.removeClass("selected");
last_popup_menu = null;
last_popup_button = null;
@ -147,6 +150,7 @@
last_popup_button = null;
} else {
last_popup_menu = menu;
last_popup_menu.on('click', function(e) {e.stopPropagation()});
last_popup_button = parent;
$('#nav-notifications-menu').perfectScrollbar('update');
}
@ -259,13 +263,13 @@
var html = notifications_tpl.format(
e.attr('href'), // {0} // link to the source
e.attr('photo'), // {1} // photo of the contact
text, // {2} // preformatet text (autor + text)
text, // {2} // preformatted text (autor + text)
e.attr('date'), // {3} // date of notification (time ago)
seenclass, // {4} // vistiting status of the notification
new Date(e.attr('timestamp')*1000), // {5} //date of notification
seenclass, // {4} // visited status of the notification
new Date(e.attr('timestamp')*1000), // {5} // date of notification
e.attr('url'), // {6} // profile url of the contact
e.text().format(""), // {7} // clean status text
contact // {8} //preformatat author (name + profile url)
e.text().format(contact), // {7} // preformatted html (text including author profile url)
'' // {8} // Deprecated
);
nnm.append(html);
});
@ -275,7 +279,7 @@
if (notification_lastitem!== null && notification_id > notification_lastitem) {
if (getNotificationPermission()==="granted") {
var notification = new Notification(document.title, {
body: e.text().replace('&rarr; ','').format(e.attr('name')),
body: decodeHtml(e.text().replace('&rarr; ','').format(e.attr('name'))),
icon: e.attr('photo'),
});
notification['url'] = e.attr('href');
@ -513,7 +517,7 @@
$(".comment-edit-form textarea").editor_autocomplete(baseurl+"/acl");
/* autocomplete bbcode */
$(".comment-edit-form textarea").bbco_autocomplete('bbcode');
// setup videos, since VideoJS won't take care of any loaded via AJAX
if(typeof videojs != 'undefined') videojs.autoSetup();
});

View file

@ -0,0 +1,455 @@
# $Id$
Introduction
============
Text_Highlighter is a class for syntax highlighting. The main idea is to
simplify creation of subclasses implementing syntax highlighting for
particular language. Subclasses do not implement any new functioanality, they
just provide syntax highlighting rules. The rules sources are in XML format.
To create a highlighter for a language, there is no need to code a new class
manually. Simply describe the rules in XML file and use Text_Highlighter_Generator
to create a new class.
This document does not contain a formal description of API - it is very
simple, and I believe providing some examples of code is sufficient.
Highlighter XML source
======================
Basics
------
Creating a new syntax highlighter begins with describing the highlighting
rules. There are two basic elements: block and region. A block is just a
portion of text matching a regular expression and highlighted with a single
color. Keyword is an example of a block. A region is defined by two regular
expressions: one for start of region, and another for the end. The main
difference from a block is that a region can contain blocks and regions
(including same-named regions). An example of a region is a group of
statements enclosed in curly brackets (this is used in many languages, for
example PHP and C). Also, characters matching start and end of a region may be
highlighted with their own color, and region contents with another.
Blocks and regions may be declared as contained. Contained blocks and regions
can only appear inside regions. If a region or a block is not declared as
contained, it can appear both on top level and inside regions. Block or region
declared as not-contained can only appear on top level.
For any region, a list of blocks and regions that can appear inside this
region can be specified.
In this document, the term "color group" is used. Chunks of text assigned to
same color group will be highlighted with same color. Note that in versions
prior 0.5.0 color goups were refered as CSS classes, but since 0.5.0 not only
HTML output is supported, so "color group" is more appropriate term.
Elements
--------
The toplevel element is <highlight>. Attribute lang is required and denotes
the name of the language. Its value is used as a part of generated class name,
and must only contain letters, digits and underscores. Optional attribute
case, when given value yes, makes the language case sensitive (default is case
insensitive). Allowed subelements are:
* <authors>: Information about the authors of the file.
<author>: Information about a single author of the file. (May be used
multiple times, one per author.)
- name="...": Author's name. Required.
- email="...": Author's email address. Optional.
* <default>: Default color group.
- innerGroup="...": color group name. Required.
* <region>: Region definition
- name="...": Region name. Required.
- innerGroup="...": Default color group of region contents. Required.
- delimGroup="...": color group of start and end of region. Optional,
defaults to value of innerGroup attribute.
- start="...", end="...": Regular expression matching start and end
of region. Required. Regular expression delimiters are optional, but
if you need to specify delimiter, use /. The only case when the
delimiters are needed, is specifying regular expression modifiers,
such as m or U. Examples: \/\* or /$/m.
- contained="yes": Marks region as contained.
- never-contained="yes": Marks region as not-contained.
- <contains>: Elements allowed inside this region.
- all="yes" Region can contain any other region or block
(except not-contained). May be used multiple times.
- <but> Do not allow certain regions or blocks.
- region="..." Name of region not allowed within
current region.
- block="..." Name of block not allowed within
current region.
- region="..." Name of region allowed within current region.
- block="..." Name of block allowed within current region.
- <onlyin> Only allow this region within certain regions. May be
used multiple times.
- block="..." Name of parent region
* <block>: Block definition
- name="...": Block name. Required.
- innerGroup="...": color group of block contents. Optional. If not
specified, color group of parent region or default color group will be
used. One would only want to omit this attribute if there are
keyword groups (see below) inherited from this block, and no special
highlighting should apply when the block does not match the keyword.
- match="..." Regular expression matching the block. Required.
Regular expression delimiters are optional, but if you need to
specify delimiter, use /. The only case when the delimiters are
needed, is specifying regular expression modifiers, such as m or U.
Examples: #|\/\/ or /$/m.
- contained="yes": Marks block as contained.
- never-contained="yes": Marks block as not-contained.
- <onlyin> Only allow this block within certain regions. May be used
multiple times.
- block="..." Name of parent region
- multiline="yes": Marks block as multi-line. By default, whole
blocks are assumed to reside in a single line. This make the things
faster. If you need to declare a multi-line block, use this
attribute.
- <partgroup>: Assigns another color group to a part of the block that
matched a subpattern.
- index="n": Subpattern index. Required.
- innerGroup="...": color group name. Required.
This is an example from CSS highlighter: the measure is matched as
a whole, but the measurement units are highlighted with different
color.
<block name="measure" match="\d*\.?\d+(\%|em|ex|pc|pt|px|in|mm|cm)"
innerGroup="number" contained="yes">
<onlyin region="property"/>
<partGroup index="1" innerGroup="string" />
</block>
* <keywords>: Keyword group definition. Keyword groups are useful when you
want to highlight some words that match a condition for a block with a
different color. Keywords are defined with literal match, not regular
expressions. For example, you have a block named identifier matching a
general identifier, and want to highlight reserved words (which match
this block as well) with different color. You inherit a keyword group
"reserved" from "identifier" block.
- name="...": Keyword group. Required.
- ifdef="...", ifndef="..." : Conditional declaration. See
"Conditions" below.
- inherits="...": Inherited block name. Required.
- innerGroup="...": color group of keyword group. Required.
- case="yes|no": Overrides case-sensitivity of the language.
Optional, defaults to global value.
- <keyword>: Single keyword definition.
- match="..." The keyword. Note: this is not a regular
expression, but literal match (possibly case insensitive).
Note that for BC reasons element partClass is alias for partGroup, and
attributes innerClass and delimClass are aliases of innerGroup and
delimGroup, respectively.
Conditions
----------
Conditional declarations allow enabling or disabling certain highlighting
rules at runtime. For example, Java highlighter has a very big list of
keywords matching Java standard classes. Finding a match in this list can take
much time. For that reason, corresponding keyword group is declared with
"ifdef" attribute :
<keywords name="builtin" inherits="identifier" innerClass="builtin"
case="yes" ifdef="java.builtins">
<keyword match="AbstractAction" />
<keyword match="AbstractBorder" />
<keyword match="AbstractButton" />
...
...
<keyword match="_Remote_Stub" />
<keyword match="_ServantActivatorStub" />
<keyword match="_ServantLocatorStub" />
</keywords>
This keyword group will be only enabled when "java.builtins" is passed as an
element of "defines" option:
$options = array(
'defines' => array(
'java.builtins',
),
'numbers' => HL_NUMBERS_TABLE,
);
$highlighter = Text_Highlighter::factory('java', $options);
"ifndef" attribute has reverse meaning.
Currently, "ifdef" and "ifndef" attributes are only supported for <keywords>
tag.
Class generation
================
Creating XML description of highlighting rules is the most complicated part of
the process. To generate the class, you need just few lines of code:
<?php
require_once 'Text/Highlighter/Generator.php';
$generator = new Text_Highlighter_Generator('php.xml');
$generator->generate();
$generator->saveCode('PHP.php');
?>
Command-line class generation tool
==================================
Example from previous section looks pretty simple, but it does not handle any
errors which may occur during parsing of XML source. The package provides a
command-line script to make generation of classes even more simple, and takes
care of possible errors. It is called generate (on Unix/Linux) or generate.bat
(on Windows). This script is able to process multiple files in one run, and
also to process XML from standard input and write generated code to standard
output.
Usage:
generate options
Options:
-x filename, --xml=filename
source XML file. Multiple input files can be specified, in which
case each -x option must be followed by -p unless -d is specified
Defaults to stdin
-p filename, --php=filename
destination PHP file. Defaults to stdout. If specied multiple times,
each -p must follow -x
-d dirname, --dir=dirname
Default destination directory. File names will be taken from XML input
("lang" attribute of <highlight> tag)
-h, --help
This help
Examples
Read from php.xml, write to PHP.php
generate -x php.xml -p PHP.php
Read from php.xml, write to standard output
generate -x php.xml
Read from php.xml, write to PHP.php, read from xml.xml, write to XML.php
generate -x php.xml -p PHP.php -x xml.xml -p XML.php
Read from php.xml, write to /some/dir/PHP.php, read from xml.xml, write to
/some/dir/XML.php (assuming that xml.xml contains <highlight lang="xml">, and
php.xml contains <highlight lang="php">)
generate -x php.xml -x xml.xml -d /some/dir/
Renderers
=========
Introduction
------------
Text_Highlighter supports renderes. Using renderers, you can get output in
different formats. Two renderers are included in the package:
- HTML renderer. Generates HTML output. A style sheet should be linked to
the document to display colored text
- Console renderer. Can be used to output highlighted text to
color-capable terminals, either directly or trough less -r
Renderers API
-------------
Renderers are subclasses of Text_Highlighter_Renderer. Renderer should
override at least two methods - acceptToken and getOutput. Overriding other
methods is optional, depending on the nature of renderer's output and details
of implementation.
string reset()
resets renderer state. This method is called every time before a new
source file is highlighted.
string preprocess(string $code)
preprocesses code. Can be used, for example, to normalize whitespace
before highlighting. Returns preprocessed string.
void acceptToken(string $group, string $content)
the core method of the renderer. Highlighter passes chunks of text to
this method in $content, and color group in $group
void finalize()
signals the renderer that no more tokens are available.
mixed getOutput()
returns generated output.
Setting renderer options
--------------------------------
Renderers accept an optional argument to their constructor - options array.
Elements of this array are renderer-specific.
HTML renderer
-------------
HTML renderer produces HTML output with optional line numbering. The renderer
itself does not provide information about actual colors of highlighted text.
Instead, <span class="hl-XXX"> is used, where XXX is replaced with color group
name (hl-var, hl-string, etc.). It is up to you to create a CSS stylesheet.
If 'use_language' option with value evaluating to true was passed, class names
will be formatted as "LANG-hl-XXX", where LANG is language name as defined in
highlighter XML source ("lang" attribute of <highlight> tag) in lower case.
There are 3 special CSS classes:
hl-main - this class applies to whole output or right table column,
depending on 'numbers' option
hl-gutter - applies to left column in table
hl-table - applies to whole table
HTML renderer accepts following options (each being optional):
* numbers - line numbering style.
0 - no numbering (default)
HL_NUMBERS_LI - use <ol></ol> for line numbering
HL_NUMBERS_TABLE - create a 2-column table, with line numbers in left
column and highlighted text in right column
* tabsize - tabulation size. Defaults to 4
Example:
require_once 'Text/Highlighter/Renderer/Html.php';
$options = array(
'numbers' => HL_NUMBERS_LI,
'tabsize' => 8,
);
$renderer = new Text_Highlighter_Renderer_HTML($options);
Console renderer
----------------
Console renderer produces output for displaying on a color-capable terminal,
either directly or through less -r, using ANSI escape sequences. By default,
this renderer only highlights most common color groups. Additional colors
can be specified using 'colors' option. This renderer also accepts 'numbers'
option - a boolean value, and 'tabsize' option.
Example :
require_once 'Text/Highlighter/Renderer/Console.php';
$colors = array(
'prepro' => "\033[35m",
'types' => "\033[32m",
);
$options = array(
'numbers' => true,
'tabsize' => 8,
'colors' => $colors,
);
$renderer = new Text_Highlighter_Renderer_Console($options);
ANSI color escape sequences have the following format:
ESC[#;#;....;#m
where ESC is character with ASCII code 27 (033 octal, 0x1B hexadecimal). # is
one of the following:
0 for normal display
1 for bold on
4 underline (mono only)
5 blink on
7 reverse video on
8 nondisplayed (invisible)
30 black foreground
31 red foreground
32 green foreground
33 yellow foreground
34 blue foreground
35 magenta foreground
36 cyan foreground
37 white foreground
40 black background
41 red background
42 green background
43 yellow background
44 blue background
45 magenta background
46 cyan background
47 white background
How to use Text_Highlighter class
=================================
Creating a highlighter object
-----------------------------
To create a highlighter for a certain language, use Text_Highlighter::factory()
static method:
require_once 'Text/Highlighter.php';
$hl = Text_Highlighter::factory('php');
Setting a renderer
------------------
Actual output is produced by a renderer.
require_once 'Text/Highlighter.php';
require_once 'Text/Highlighter/Renderer/Html.php';
$options = array(
'numbers' => HL_NUMBERS_LI,
'tabsize' => 8,
);
$renderer = new Text_Highlighter_Renderer_HTML($options);
$hl = Text_Highlighter::factory('php');
$hl->setRenderer($renderer);
Note that for BC reasons, it is possible to use highlighter without setting a
renderer. If no renderer is set, HTML renderer will be used by default. In
this case, you should pass options as second parameter to factory method. The
following example works exactly as previous one:
require_once 'Text/Highlighter.php';
$options = array(
'numbers' => HL_NUMBERS_LI,
'tabsize' => 8,
);
$hl = Text_Highlighter::factory('php', $options);
Getting output
--------------
And finally, do the highlighting and get the output:
require_once 'Text/Highlighter.php';
require_once 'Text/Highlighter/Renderer/Html.php';
$options = array(
'numbers' => HL_NUMBERS_LI,
'tabsize' => 8,
);
$renderer = new Text_Highlighter_Renderer_HTML($options);
$hl = Text_Highlighter::factory('php');
$hl->setRenderer($renderer);
$html = $hl->highlight(file_get_contents('example.php'));
# vim: set autoindent tabstop=4 shiftwidth=4 softtabstop=4 tw=78: */

View file

@ -0,0 +1,12 @@
# $Id$
Major issues to solve (but I currently have no idea how) :
- speedup highlighting process
- switching between highlighters depending on context, for example :
PHP code -> HTML -> (JavaScript|CSS)
# vim: set autoindent tabstop=4 shiftwidth=4 softtabstop=4 tw=78: */

View file

@ -0,0 +1,398 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Highlighter base class
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category Text
* @package Text_Highlighter
* @author Andrey Demenev <demenev@gmail.com>
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version CVS: $Id$
* @link http://pear.php.net/package/Text_Highlighter
*/
// require_once 'PEAR.php';
// {{{ BC constants
// BC trick : define constants related to default
// renderer if needed
if (!defined('HL_NUMBERS_LI')) {
/**#@+
* Constant for use with $options['numbers']
* @see Text_Highlighter_Renderer_Html::_init()
*/
/**
* use numbered list
*/
define ('HL_NUMBERS_LI' , 1);
/**
* Use 2-column table with line numbers in left column and code in right column.
* Forces $options['tag'] = HL_TAG_PRE
*/
define ('HL_NUMBERS_TABLE' , 2);
/**#@-*/
}
// }}}
// {{{ constants
/**
* for our purpose, it is infinity
*/
define ('HL_INFINITY', 1000000000);
// }}}
/**
* Text highlighter base class
*
* @author Andrey Demenev <demenev@gmail.com>
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: @package_version@
* @link http://pear.php.net/package/Text_Highlighter
*/
// {{{ Text_Highlighter
/**
* Text highlighter base class
*
* This class implements all functions necessary for highlighting,
* but it does not contain highlighting rules. Actual highlighting is
* done using a descendent of this class.
*
* One is not supposed to manually create descendent classes.
* Instead, describe highlighting rules in XML format and
* use {@link Text_Highlighter_Generator} to create descendent class.
* Alternatively, an instance of a descendent class can be created
* directly.
*
* Use {@link Text_Highlighter::factory()} to create an
* object for particular language highlighter
*
* Usage example
* <code>
*require_once 'Text/Highlighter.php';
*$hlSQL = Text_Highlighter::factory('SQL',array('numbers'=>true));
*echo $hlSQL->highlight('SELECT * FROM table a WHERE id = 12');
* </code>
*
* @author Andrey Demenev <demenev@gmail.com>
* @package Text_Highlighter
* @access public
*/
class Text_Highlighter
{
// {{{ members
/**
* Syntax highlighting rules.
* Auto-generated classes set this var
*
* @access protected
* @see _init
* @var array
*/
var $_syntax;
/**
* Renderer object.
*
* @access private
* @var array
*/
var $_renderer;
/**
* Options. Keeped for BC
*
* @access protected
* @var array
*/
var $_options = array();
/**
* Conditionds
*
* @access protected
* @var array
*/
var $_conditions = array();
/**
* Disabled keywords
*
* @access protected
* @var array
*/
var $_disabled = array();
/**
* Language
*
* @access protected
* @var string
*/
var $_language = '';
// }}}
// {{{ _checkDefines
/**
* Called by subclssses' constructors to enable/disable
* optional highlighter rules
*
* @param array $defines Conditional defines
*
* @access protected
*/
function _checkDefines()
{
if (isset($this->_options['defines'])) {
$defines = $this->_options['defines'];
} else {
$defines = array();
}
foreach ($this->_conditions as $name => $actions) {
foreach($actions as $action) {
$present = in_array($name, $defines);
if (!$action[1]) {
$present = !$present;
}
if ($present) {
unset($this->_disabled[$action[0]]);
} else {
$this->_disabled[$action[0]] = true;
}
}
}
}
// }}}
// {{{ factory
/**
* Create a new Highlighter object for specified language
*
* @param string $lang language, for example "SQL"
* @param array $options Rendering options. This
* parameter is only keeped for BC reasons, use
* {@link Text_Highlighter::setRenderer()} instead
*
* @return mixed a newly created Highlighter object, or
* a PEAR error object on error
*
* @static
* @access public
*/
function &factory($lang, $options = array())
{
$lang = strtoupper($lang);
@include_once 'Text/Highlighter/' . $lang . '.php';
$classname = 'Text_Highlighter_' . $lang;
if (!class_exists($classname)) {
return PEAR::raiseError('Highlighter for ' . $lang . ' not found');
}
$obj = new $classname($options);
return $obj;
}
// }}}
// {{{ setRenderer
/**
* Set renderer object
*
* @param object $renderer Text_Highlighter_Renderer
*
* @access public
*/
function setRenderer(&$renderer)
{
$this->_renderer = $renderer;
}
// }}}
/**
* Helper function to find matching brackets
*
* @access private
*/
function _matchingBrackets($str)
{
return strtr($str, '()<>[]{}', ')(><][}{');
}
function _getToken()
{
if (!empty($this->_tokenStack)) {
return array_pop($this->_tokenStack);
}
if ($this->_pos >= $this->_len) {
return NULL;
}
if ($this->_state != -1 && preg_match($this->_endpattern, $this->_str, $m, PREG_OFFSET_CAPTURE, $this->_pos)) {
$endpos = $m[0][1];
$endmatch = $m[0][0];
} else {
$endpos = -1;
}
preg_match ($this->_regs[$this->_state], $this->_str, $m, PREG_OFFSET_CAPTURE, $this->_pos);
$n = 1;
foreach ($this->_counts[$this->_state] as $i=>$count) {
if (!isset($m[$n])) {
break;
}
if ($m[$n][1]>-1 && ($endpos == -1 || $m[$n][1] < $endpos)) {
if ($this->_states[$this->_state][$i] != -1) {
$this->_tokenStack[] = array($this->_delim[$this->_state][$i], $m[$n][0]);
} else {
$inner = $this->_inner[$this->_state][$i];
if (isset($this->_parts[$this->_state][$i])) {
$parts = array();
$partpos = $m[$n][1];
for ($j=1; $j<=$count; $j++) {
if ($m[$j+$n][1] < 0) {
continue;
}
if (isset($this->_parts[$this->_state][$i][$j])) {
if ($m[$j+$n][1] > $partpos) {
array_unshift($parts, array($inner, substr($this->_str, $partpos, $m[$j+$n][1]-$partpos)));
}
array_unshift($parts, array($this->_parts[$this->_state][$i][$j], $m[$j+$n][0]));
}
$partpos = $m[$j+$n][1] + strlen($m[$j+$n][0]);
}
if ($partpos < $m[$n][1] + strlen($m[$n][0])) {
array_unshift($parts, array($inner, substr($this->_str, $partpos, $m[$n][1] - $partpos + strlen($m[$n][0]))));
}
$this->_tokenStack = array_merge($this->_tokenStack, $parts);
} else {
foreach ($this->_keywords[$this->_state][$i] as $g => $re) {
if (isset($this->_disabled[$g])) {
continue;
}
if (preg_match($re, $m[$n][0])) {
$inner = $this->_kwmap[$g];
break;
}
}
$this->_tokenStack[] = array($inner, $m[$n][0]);
}
}
if ($m[$n][1] > $this->_pos) {
$this->_tokenStack[] = array($this->_lastinner, substr($this->_str, $this->_pos, $m[$n][1]-$this->_pos));
}
$this->_pos = $m[$n][1] + strlen($m[$n][0]);
if ($this->_states[$this->_state][$i] != -1) {
$this->_stack[] = array($this->_state, $this->_lastdelim, $this->_lastinner, $this->_endpattern);
$this->_lastinner = $this->_inner[$this->_state][$i];
$this->_lastdelim = $this->_delim[$this->_state][$i];
$l = $this->_state;
$this->_state = $this->_states[$this->_state][$i];
$this->_endpattern = $this->_end[$this->_state];
if ($this->_subst[$l][$i]) {
for ($k=0; $k<=$this->_counts[$l][$i]; $k++) {
if (!isset($m[$i+$k])) {
break;
}
$quoted = preg_quote($m[$n+$k][0], '/');
$this->_endpattern = str_replace('%'.$k.'%', $quoted, $this->_endpattern);
$this->_endpattern = str_replace('%b'.$k.'%', $this->_matchingBrackets($quoted), $this->_endpattern);
}
}
}
return array_pop($this->_tokenStack);
}
$n += $count + 1;
}
if ($endpos > -1) {
$this->_tokenStack[] = array($this->_lastdelim, $endmatch);
if ($endpos > $this->_pos) {
$this->_tokenStack[] = array($this->_lastinner, substr($this->_str, $this->_pos, $endpos-$this->_pos));
}
list($this->_state, $this->_lastdelim, $this->_lastinner, $this->_endpattern) = array_pop($this->_stack);
$this->_pos = $endpos + strlen($endmatch);
return array_pop($this->_tokenStack);
}
$p = $this->_pos;
$this->_pos = HL_INFINITY;
return array($this->_lastinner, substr($this->_str, $p));
}
// {{{ highlight
/**
* Highlights code
*
* @param string $str Code to highlight
* @access public
* @return string Highlighted text
*
*/
function highlight($str)
{
if (!($this->_renderer)) {
include_once('Text/Highlighter/Renderer/Html.php');
$this->_renderer = new Text_Highlighter_Renderer_Html($this->_options);
}
$this->_state = -1;
$this->_pos = 0;
$this->_stack = array();
$this->_tokenStack = array();
$this->_lastinner = $this->_defClass;
$this->_lastdelim = $this->_defClass;
$this->_endpattern = '';
$this->_renderer->reset();
$this->_renderer->setCurrentLanguage($this->_language);
$this->_str = $this->_renderer->preprocess($str);
$this->_len = strlen($this->_str);
while ($token = $this->_getToken()) {
$this->_renderer->acceptToken($token[0], $token[1]);
}
$this->_renderer->finalize();
return $this->_renderer->getOutput();
}
// }}}
}
// }}}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* c-hanging-comment-ender-p: nil
* End:
*/
?>

View file

@ -0,0 +1,519 @@
<?php
/**
* Auto-generated class. ABAP syntax highlighting
*
* PHP version 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @link http://pear.php.net/package/Text_Highlighter
* @category Text
* @package Text_Highlighter
* @version generated from: : abap.xml,v 1.1 2007/06/03 02:35:28 ssttoo Exp
* @author Stoyan Stefanov <ssttoo@gmail.com>
*
*/
/**
* @ignore
*/
require_once 'Text/Highlighter.php';
/**
* Auto-generated class. ABAP syntax highlighting
*
* @author Stoyan Stefanov <ssttoo@gmail.com>
* @category Text
* @package Text_Highlighter
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: @package_version@
* @link http://pear.php.net/package/Text_Highlighter
*/
class Text_Highlighter_ABAP extends Text_Highlighter
{
var $_language = 'abap';
/**
* PHP4 Compatible Constructor
*
* @param array $options
* @access public
*/
function Text_Highlighter_ABAP($options=array())
{
$this->__construct($options);
}
/**
* Constructor
*
* @param array $options
* @access public
*/
function __construct($options=array())
{
$this->_options = $options;
$this->_regs = array (
-1 => '/((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)^\\*|")|((?i)\')|((?i)[a-z_\\-]\\w*)/',
0 => '/((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)^\\*|")|((?i)\')|((?i)0[xX][\\da-f]+)|((?i)\\d\\d*|\\b0\\b)|((?i)0[0-7]+)|((?i)(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?i)[a-z_\\-]\\w*)/',
1 => '/((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)^\\*|")|((?i)\')|((?i)0[xX][\\da-f]+)|((?i)\\d\\d*|\\b0\\b)|((?i)0[0-7]+)|((?i)(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?i)[a-z_\\-]\\w*)/',
2 => '/((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)^\\*|")|((?i)\')|((?i)0[xX][\\da-f]+)|((?i)\\d\\d*|\\b0\\b)|((?i)0[0-7]+)|((?i)(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?i)[a-z_\\-]\\w*)/',
3 => '//',
4 => '//',
);
$this->_counts = array (
-1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
),
0 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
),
1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
),
2 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
),
3 =>
array (
),
4 =>
array (
),
);
$this->_delim = array (
-1 =>
array (
0 => 'brackets',
1 => 'brackets',
2 => 'brackets',
3 => 'comment',
4 => 'quotes',
5 => '',
),
0 =>
array (
0 => 'brackets',
1 => 'brackets',
2 => 'brackets',
3 => 'comment',
4 => 'quotes',
5 => '',
6 => '',
7 => '',
8 => '',
9 => '',
),
1 =>
array (
0 => 'brackets',
1 => 'brackets',
2 => 'brackets',
3 => 'comment',
4 => 'quotes',
5 => '',
6 => '',
7 => '',
8 => '',
9 => '',
),
2 =>
array (
0 => 'brackets',
1 => 'brackets',
2 => 'brackets',
3 => 'comment',
4 => 'quotes',
5 => '',
6 => '',
7 => '',
8 => '',
9 => '',
),
3 =>
array (
),
4 =>
array (
),
);
$this->_inner = array (
-1 =>
array (
0 => 'code',
1 => 'code',
2 => 'code',
3 => 'comment',
4 => 'string',
5 => 'identifier',
),
0 =>
array (
0 => 'code',
1 => 'code',
2 => 'code',
3 => 'comment',
4 => 'string',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'identifier',
),
1 =>
array (
0 => 'code',
1 => 'code',
2 => 'code',
3 => 'comment',
4 => 'string',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'identifier',
),
2 =>
array (
0 => 'code',
1 => 'code',
2 => 'code',
3 => 'comment',
4 => 'string',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'identifier',
),
3 =>
array (
),
4 =>
array (
),
);
$this->_end = array (
0 => '/(?i)\\}/',
1 => '/(?i)\\)/',
2 => '/(?i)\\]/',
3 => '/(?mi)$/',
4 => '/(?i)\'/',
);
$this->_states = array (
-1 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => -1,
),
0 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => -1,
),
1 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => -1,
),
2 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => -1,
),
3 =>
array (
),
4 =>
array (
),
);
$this->_keywords = array (
-1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 => -1,
5 =>
array (
'sy' => '/^((?i)screen-name|screen-group1|screen-group2|screen-group3|screen-group4|screen-required|screen-input|screen-output|screen-intensified|screen-invisible|screen-length|screen-active|sy-index|sy-pagno|sy-tabix|sy-tfill|sy-tlopc|sy-tmaxl|sy-toccu|sy-ttabc|sy-tstis|sy-ttabi|sy-dbcnt|sy-fdpos|sy-colno|sy-linct|sy-linno|sy-linsz|sy-pagct|sy-macol|sy-marow|sy-tleng|sy-sfoff|sy-willi|sy-lilli|sy-subrc|sy-fleng|sy-cucol|sy-curow|sy-lsind|sy-listi|sy-stepl|sy-tpagi|sy-winx1|sy-winy1|sy-winx2|sy-winy2|sy-winco|sy-winro|sy-windi|sy-srows|sy-scols|sy-loopc|sy-folen|sy-fodec|sy-tzone|sy-dayst|sy-ftype|sy-appli|sy-fdayw|sy-ccurs|sy-ccurt|sy-debug|sy-ctype|sy-input|sy-langu|sy-modno|sy-batch|sy-binpt|sy-calld|sy-dynnr|sy-dyngr|sy-newpa|sy-pri40|sy-rstrt|sy-wtitl|sy-cpage|sy-dbnam|sy-mandt|sy-prefx|sy-fmkey|sy-pexpi|sy-prini|sy-primm|sy-prrel|sy-playo|sy-prbig|sy-playp|sy-prnew|sy-prlog|sy-pdest|sy-plist|sy-pauth|sy-prdsn|sy-pnwpa|sy-callr|sy-repi2|sy-rtitl|sy-prrec|sy-prtxt|sy-prabt|sy-lpass|sy-nrpag|sy-paart|sy-prcop|sy-batzs|sy-bspld|sy-brep4|sy-batzo|sy-batzd|sy-batzw|sy-batzm|sy-ctabl|sy-dbsys|sy-dcsys|sy-macdb|sy-sysid|sy-opsys|sy-pfkey|sy-saprl|sy-tcode|sy-ucomm|sy-cfwae|sy-chwae|sy-spono|sy-sponr|sy-waers|sy-cdate|sy-datum|sy-slset|sy-subty|sy-subcs|sy-group|sy-ffile|sy-uzeit|sy-dsnam|sy-repid|sy-tabid|sy-tfdsn|sy-uname|sy-lstat|sy-abcde|sy-marky|sy-sfnam|sy-tname|sy-msgli|sy-title|sy-entry|sy-lisel|sy-uline|sy-xcode|sy-cprog|sy-xprog|sy-xform|sy-ldbpg|sy-tvar0|sy-tvar1|sy-tvar2|sy-tvar3|sy-tvar4|sy-tvar5|sy-tvar6|sy-tvar7|sy-tvar8|sy-tvar9|sy-msgid|sy-msgty|sy-msgno|sy-msgv1|sy-msgv2|sy-msgv3|sy-msgv4|sy-oncom|sy-vline|sy-winsl|sy-staco|sy-staro|sy-datar|sy-host|sy-locdb|sy-locop|sy-datlo|sy-timlo|sy-zonlo|syst-index|syst-pagno|syst-tabix|syst-tfill|syst-tlopc|syst-tmaxl|syst-toccu|syst-ttabc|syst-tstis|syst-ttabi|syst-dbcnt|syst-fdpos|syst-colno|syst-linct|syst-linno|syst-linsz|syst-pagct|syst-macol|syst-marow|syst-tleng|syst-sfoff|syst-willi|syst-lilli|syst-subrc|syst-fleng|syst-cucol|syst-curow|syst-lsind|syst-listi|syst-stepl|syst-tpagi|syst-winx1|syst-winy1|syst-winx2|syst-winy2|syst-winco|syst-winro|syst-windi|syst-srows|syst-scols|syst-loopc|syst-folen|syst-fodec|syst-tzone|syst-dayst|syst-ftype|syst-appli|syst-fdayw|syst-ccurs|syst-ccurt|syst-debug|syst-ctype|syst-input|syst-langu|syst-modno|syst-batch|syst-binpt|syst-calld|syst-dynnr|syst-dyngr|syst-newpa|syst-pri40|syst-rstrt|syst-wtitl|syst-cpage|syst-dbnam|syst-mandt|syst-prefx|syst-fmkey|syst-pexpi|syst-prini|syst-primm|syst-prrel|syst-playo|syst-prbig|syst-playp|syst-prnew|syst-prlog|syst-pdest|syst-plist|syst-pauth|syst-prdsn|syst-pnwpa|syst-callr|syst-repi2|syst-rtitl|syst-prrec|syst-prtxt|syst-prabt|syst-lpass|syst-nrpag|syst-paart|syst-prcop|syst-batzs|syst-bspld|syst-brep4|syst-batzo|syst-batzd|syst-batzw|syst-batzm|syst-ctabl|syst-dbsys|syst-dcsys|syst-macdb|syst-sysid|syst-opsys|syst-pfkey|syst-saprl|syst-tcode|syst-ucomm|syst-cfwae|syst-chwae|syst-spono|syst-sponr|syst-waers|syst-cdate|syst-datum|syst-slset|syst-subty|syst-subcs|syst-group|syst-ffile|syst-uzeit|syst-dsnam|syst-repid|syst-tabid|syst-tfdsn|syst-uname|syst-lstat|syst-abcde|syst-marky|syst-sfnam|syst-tname|syst-msgli|syst-title|syst-entry|syst-lisel|syst-uline|syst-xcode|syst-cprog|syst-xprog|syst-xform|syst-ldbpg|syst-tvar0|syst-tvar1|syst-tvar2|syst-tvar3|syst-tvar4|syst-tvar5|syst-tvar6|syst-tvar7|syst-tvar8|syst-tvar9|syst-msgid|syst-msgty|syst-msgno|syst-msgv1|syst-msgv2|syst-msgv3|syst-msgv4|syst-oncom|syst-vline|syst-winsl|syst-staco|syst-staro|syst-datar|syst-host|syst-locdb|syst-locop|syst-datlo|syst-timlo|syst-zonlo)$/',
'reserved' => '/^((?i)abs|acos|add|add-corresponding|adjacent|after|aliases|all|analyzer|and|any|append|as|ascending|asin|assign|assigned|assigning|at|atan|authority-check|avg|back|before|begin|binary|bit|bit-and|bit-not|bit-or|bit-xor|blank|block|break-point|buffer|by|c|call|case|catch|ceil|centered|chain|change|changing|check|checkbox|class|class-data|class-events|class-methods|class-pool|clear|client|close|cnt|code|collect|color|comment|commit|communication|compute|concatenate|condense|constants|context|contexts|continue|control|controls|convert|copy|corresponding|cos|cosh|count|country|create|currency|cursor|customer-function|data|database|dataset|delete|decimals|default|define|demand|descending|describe|dialog|distinct|div|divide|divide-corresponding|do|duplicates|dynpro|edit|editor-call|else|elseif|end|end-of-definition|end-of-page|end-of-selection|endat|endcase|endcatch|endchain|endclass|enddo|endexec|endform|endfunction|endif|endinterface|endloop|endmethod|endmodule|endon|endprovide|endselect|endwhile|entries|events|exec|exit|exit-command|exp|exponent|export|exporting|exceptions|extended|extract|fetch|field|field-groups|field-symbols|fields|floor|for|form|format|frac|frame|free|from|function|function-pool|generate|get|group|hashed|header|help-id|help-request|hide|hotspot|icon|id|if|import|importing|include|index|infotypes|initialization|inner|input|insert|intensified|interface|interface-pool|interfaces|into|inverse|join|key|language|last|leave|left|left-justified|like|line|line-count|line-selection|line-size|lines|list-processing|load|load-of-program|local|locale|log|log10|loop|m|margin|mask|matchcode|max|memory|message|message-id|messages|method|methods|min|mod|mode|modif|modify|module|move|move-corresponding|multiply|multiply-corresponding|new|new-line|new-page|next|no|no-gap|no-gaps|no-heading|no-scrolling|no-sign|no-title|no-zero|nodes|non-unique|o|object|obligatory|occurs|of|off|on|open|or|order|others|outer|output|overlay|pack|page|parameter|parameters|perform|pf-status|position|print|print-control|private|process|program|property|protected|provide|public|put|radiobutton|raise|raising|range|ranges|read|receive|refresh|reject|replace|report|requested|reserve|reset|right-justified|rollback|round|rows|rtti|run|scan|screen|search|separated|scroll|scroll-boundary|select|select-options|selection-screen|selection-table|set|shared|shift|sign|sin|single|sinh|size|skip|sort|sorted|split|sql|sqrt|stamp|standard|start-of-selection|statics|stop|string|strlen|structure|submit|subtract|subtract-corresponding|sum|supply|suppress|symbol|syntax-check|syntax-trace|system-call|system-exceptions|table|table_line|tables|tan|tanh|text|textpool|time|times|title|titlebar|to|top-of-page|transaction|transfer|translate|transporting|trunc|type|type-pool|type-pools|types|uline|under|unique|unit|unpack|up|update|user-command|using|value|value-request|values|vary|when|where|while|window|with|with-title|work|write|x|xstring|z|zone)$/',
'constants' => '/^((?i)initial|null|space|col_background|col_heading|col_normal|col_total|col_key|col_positive|col_negative|col_group)$/',
),
),
0 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 => -1,
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 =>
array (
'sy' => '/^((?i)screen-name|screen-group1|screen-group2|screen-group3|screen-group4|screen-required|screen-input|screen-output|screen-intensified|screen-invisible|screen-length|screen-active|sy-index|sy-pagno|sy-tabix|sy-tfill|sy-tlopc|sy-tmaxl|sy-toccu|sy-ttabc|sy-tstis|sy-ttabi|sy-dbcnt|sy-fdpos|sy-colno|sy-linct|sy-linno|sy-linsz|sy-pagct|sy-macol|sy-marow|sy-tleng|sy-sfoff|sy-willi|sy-lilli|sy-subrc|sy-fleng|sy-cucol|sy-curow|sy-lsind|sy-listi|sy-stepl|sy-tpagi|sy-winx1|sy-winy1|sy-winx2|sy-winy2|sy-winco|sy-winro|sy-windi|sy-srows|sy-scols|sy-loopc|sy-folen|sy-fodec|sy-tzone|sy-dayst|sy-ftype|sy-appli|sy-fdayw|sy-ccurs|sy-ccurt|sy-debug|sy-ctype|sy-input|sy-langu|sy-modno|sy-batch|sy-binpt|sy-calld|sy-dynnr|sy-dyngr|sy-newpa|sy-pri40|sy-rstrt|sy-wtitl|sy-cpage|sy-dbnam|sy-mandt|sy-prefx|sy-fmkey|sy-pexpi|sy-prini|sy-primm|sy-prrel|sy-playo|sy-prbig|sy-playp|sy-prnew|sy-prlog|sy-pdest|sy-plist|sy-pauth|sy-prdsn|sy-pnwpa|sy-callr|sy-repi2|sy-rtitl|sy-prrec|sy-prtxt|sy-prabt|sy-lpass|sy-nrpag|sy-paart|sy-prcop|sy-batzs|sy-bspld|sy-brep4|sy-batzo|sy-batzd|sy-batzw|sy-batzm|sy-ctabl|sy-dbsys|sy-dcsys|sy-macdb|sy-sysid|sy-opsys|sy-pfkey|sy-saprl|sy-tcode|sy-ucomm|sy-cfwae|sy-chwae|sy-spono|sy-sponr|sy-waers|sy-cdate|sy-datum|sy-slset|sy-subty|sy-subcs|sy-group|sy-ffile|sy-uzeit|sy-dsnam|sy-repid|sy-tabid|sy-tfdsn|sy-uname|sy-lstat|sy-abcde|sy-marky|sy-sfnam|sy-tname|sy-msgli|sy-title|sy-entry|sy-lisel|sy-uline|sy-xcode|sy-cprog|sy-xprog|sy-xform|sy-ldbpg|sy-tvar0|sy-tvar1|sy-tvar2|sy-tvar3|sy-tvar4|sy-tvar5|sy-tvar6|sy-tvar7|sy-tvar8|sy-tvar9|sy-msgid|sy-msgty|sy-msgno|sy-msgv1|sy-msgv2|sy-msgv3|sy-msgv4|sy-oncom|sy-vline|sy-winsl|sy-staco|sy-staro|sy-datar|sy-host|sy-locdb|sy-locop|sy-datlo|sy-timlo|sy-zonlo|syst-index|syst-pagno|syst-tabix|syst-tfill|syst-tlopc|syst-tmaxl|syst-toccu|syst-ttabc|syst-tstis|syst-ttabi|syst-dbcnt|syst-fdpos|syst-colno|syst-linct|syst-linno|syst-linsz|syst-pagct|syst-macol|syst-marow|syst-tleng|syst-sfoff|syst-willi|syst-lilli|syst-subrc|syst-fleng|syst-cucol|syst-curow|syst-lsind|syst-listi|syst-stepl|syst-tpagi|syst-winx1|syst-winy1|syst-winx2|syst-winy2|syst-winco|syst-winro|syst-windi|syst-srows|syst-scols|syst-loopc|syst-folen|syst-fodec|syst-tzone|syst-dayst|syst-ftype|syst-appli|syst-fdayw|syst-ccurs|syst-ccurt|syst-debug|syst-ctype|syst-input|syst-langu|syst-modno|syst-batch|syst-binpt|syst-calld|syst-dynnr|syst-dyngr|syst-newpa|syst-pri40|syst-rstrt|syst-wtitl|syst-cpage|syst-dbnam|syst-mandt|syst-prefx|syst-fmkey|syst-pexpi|syst-prini|syst-primm|syst-prrel|syst-playo|syst-prbig|syst-playp|syst-prnew|syst-prlog|syst-pdest|syst-plist|syst-pauth|syst-prdsn|syst-pnwpa|syst-callr|syst-repi2|syst-rtitl|syst-prrec|syst-prtxt|syst-prabt|syst-lpass|syst-nrpag|syst-paart|syst-prcop|syst-batzs|syst-bspld|syst-brep4|syst-batzo|syst-batzd|syst-batzw|syst-batzm|syst-ctabl|syst-dbsys|syst-dcsys|syst-macdb|syst-sysid|syst-opsys|syst-pfkey|syst-saprl|syst-tcode|syst-ucomm|syst-cfwae|syst-chwae|syst-spono|syst-sponr|syst-waers|syst-cdate|syst-datum|syst-slset|syst-subty|syst-subcs|syst-group|syst-ffile|syst-uzeit|syst-dsnam|syst-repid|syst-tabid|syst-tfdsn|syst-uname|syst-lstat|syst-abcde|syst-marky|syst-sfnam|syst-tname|syst-msgli|syst-title|syst-entry|syst-lisel|syst-uline|syst-xcode|syst-cprog|syst-xprog|syst-xform|syst-ldbpg|syst-tvar0|syst-tvar1|syst-tvar2|syst-tvar3|syst-tvar4|syst-tvar5|syst-tvar6|syst-tvar7|syst-tvar8|syst-tvar9|syst-msgid|syst-msgty|syst-msgno|syst-msgv1|syst-msgv2|syst-msgv3|syst-msgv4|syst-oncom|syst-vline|syst-winsl|syst-staco|syst-staro|syst-datar|syst-host|syst-locdb|syst-locop|syst-datlo|syst-timlo|syst-zonlo)$/',
'reserved' => '/^((?i)abs|acos|add|add-corresponding|adjacent|after|aliases|all|analyzer|and|any|append|as|ascending|asin|assign|assigned|assigning|at|atan|authority-check|avg|back|before|begin|binary|bit|bit-and|bit-not|bit-or|bit-xor|blank|block|break-point|buffer|by|c|call|case|catch|ceil|centered|chain|change|changing|check|checkbox|class|class-data|class-events|class-methods|class-pool|clear|client|close|cnt|code|collect|color|comment|commit|communication|compute|concatenate|condense|constants|context|contexts|continue|control|controls|convert|copy|corresponding|cos|cosh|count|country|create|currency|cursor|customer-function|data|database|dataset|delete|decimals|default|define|demand|descending|describe|dialog|distinct|div|divide|divide-corresponding|do|duplicates|dynpro|edit|editor-call|else|elseif|end|end-of-definition|end-of-page|end-of-selection|endat|endcase|endcatch|endchain|endclass|enddo|endexec|endform|endfunction|endif|endinterface|endloop|endmethod|endmodule|endon|endprovide|endselect|endwhile|entries|events|exec|exit|exit-command|exp|exponent|export|exporting|exceptions|extended|extract|fetch|field|field-groups|field-symbols|fields|floor|for|form|format|frac|frame|free|from|function|function-pool|generate|get|group|hashed|header|help-id|help-request|hide|hotspot|icon|id|if|import|importing|include|index|infotypes|initialization|inner|input|insert|intensified|interface|interface-pool|interfaces|into|inverse|join|key|language|last|leave|left|left-justified|like|line|line-count|line-selection|line-size|lines|list-processing|load|load-of-program|local|locale|log|log10|loop|m|margin|mask|matchcode|max|memory|message|message-id|messages|method|methods|min|mod|mode|modif|modify|module|move|move-corresponding|multiply|multiply-corresponding|new|new-line|new-page|next|no|no-gap|no-gaps|no-heading|no-scrolling|no-sign|no-title|no-zero|nodes|non-unique|o|object|obligatory|occurs|of|off|on|open|or|order|others|outer|output|overlay|pack|page|parameter|parameters|perform|pf-status|position|print|print-control|private|process|program|property|protected|provide|public|put|radiobutton|raise|raising|range|ranges|read|receive|refresh|reject|replace|report|requested|reserve|reset|right-justified|rollback|round|rows|rtti|run|scan|screen|search|separated|scroll|scroll-boundary|select|select-options|selection-screen|selection-table|set|shared|shift|sign|sin|single|sinh|size|skip|sort|sorted|split|sql|sqrt|stamp|standard|start-of-selection|statics|stop|string|strlen|structure|submit|subtract|subtract-corresponding|sum|supply|suppress|symbol|syntax-check|syntax-trace|system-call|system-exceptions|table|table_line|tables|tan|tanh|text|textpool|time|times|title|titlebar|to|top-of-page|transaction|transfer|translate|transporting|trunc|type|type-pool|type-pools|types|uline|under|unique|unit|unpack|up|update|user-command|using|value|value-request|values|vary|when|where|while|window|with|with-title|work|write|x|xstring|z|zone)$/',
'constants' => '/^((?i)initial|null|space|col_background|col_heading|col_normal|col_total|col_key|col_positive|col_negative|col_group)$/',
),
),
1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 => -1,
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 =>
array (
'sy' => '/^((?i)screen-name|screen-group1|screen-group2|screen-group3|screen-group4|screen-required|screen-input|screen-output|screen-intensified|screen-invisible|screen-length|screen-active|sy-index|sy-pagno|sy-tabix|sy-tfill|sy-tlopc|sy-tmaxl|sy-toccu|sy-ttabc|sy-tstis|sy-ttabi|sy-dbcnt|sy-fdpos|sy-colno|sy-linct|sy-linno|sy-linsz|sy-pagct|sy-macol|sy-marow|sy-tleng|sy-sfoff|sy-willi|sy-lilli|sy-subrc|sy-fleng|sy-cucol|sy-curow|sy-lsind|sy-listi|sy-stepl|sy-tpagi|sy-winx1|sy-winy1|sy-winx2|sy-winy2|sy-winco|sy-winro|sy-windi|sy-srows|sy-scols|sy-loopc|sy-folen|sy-fodec|sy-tzone|sy-dayst|sy-ftype|sy-appli|sy-fdayw|sy-ccurs|sy-ccurt|sy-debug|sy-ctype|sy-input|sy-langu|sy-modno|sy-batch|sy-binpt|sy-calld|sy-dynnr|sy-dyngr|sy-newpa|sy-pri40|sy-rstrt|sy-wtitl|sy-cpage|sy-dbnam|sy-mandt|sy-prefx|sy-fmkey|sy-pexpi|sy-prini|sy-primm|sy-prrel|sy-playo|sy-prbig|sy-playp|sy-prnew|sy-prlog|sy-pdest|sy-plist|sy-pauth|sy-prdsn|sy-pnwpa|sy-callr|sy-repi2|sy-rtitl|sy-prrec|sy-prtxt|sy-prabt|sy-lpass|sy-nrpag|sy-paart|sy-prcop|sy-batzs|sy-bspld|sy-brep4|sy-batzo|sy-batzd|sy-batzw|sy-batzm|sy-ctabl|sy-dbsys|sy-dcsys|sy-macdb|sy-sysid|sy-opsys|sy-pfkey|sy-saprl|sy-tcode|sy-ucomm|sy-cfwae|sy-chwae|sy-spono|sy-sponr|sy-waers|sy-cdate|sy-datum|sy-slset|sy-subty|sy-subcs|sy-group|sy-ffile|sy-uzeit|sy-dsnam|sy-repid|sy-tabid|sy-tfdsn|sy-uname|sy-lstat|sy-abcde|sy-marky|sy-sfnam|sy-tname|sy-msgli|sy-title|sy-entry|sy-lisel|sy-uline|sy-xcode|sy-cprog|sy-xprog|sy-xform|sy-ldbpg|sy-tvar0|sy-tvar1|sy-tvar2|sy-tvar3|sy-tvar4|sy-tvar5|sy-tvar6|sy-tvar7|sy-tvar8|sy-tvar9|sy-msgid|sy-msgty|sy-msgno|sy-msgv1|sy-msgv2|sy-msgv3|sy-msgv4|sy-oncom|sy-vline|sy-winsl|sy-staco|sy-staro|sy-datar|sy-host|sy-locdb|sy-locop|sy-datlo|sy-timlo|sy-zonlo|syst-index|syst-pagno|syst-tabix|syst-tfill|syst-tlopc|syst-tmaxl|syst-toccu|syst-ttabc|syst-tstis|syst-ttabi|syst-dbcnt|syst-fdpos|syst-colno|syst-linct|syst-linno|syst-linsz|syst-pagct|syst-macol|syst-marow|syst-tleng|syst-sfoff|syst-willi|syst-lilli|syst-subrc|syst-fleng|syst-cucol|syst-curow|syst-lsind|syst-listi|syst-stepl|syst-tpagi|syst-winx1|syst-winy1|syst-winx2|syst-winy2|syst-winco|syst-winro|syst-windi|syst-srows|syst-scols|syst-loopc|syst-folen|syst-fodec|syst-tzone|syst-dayst|syst-ftype|syst-appli|syst-fdayw|syst-ccurs|syst-ccurt|syst-debug|syst-ctype|syst-input|syst-langu|syst-modno|syst-batch|syst-binpt|syst-calld|syst-dynnr|syst-dyngr|syst-newpa|syst-pri40|syst-rstrt|syst-wtitl|syst-cpage|syst-dbnam|syst-mandt|syst-prefx|syst-fmkey|syst-pexpi|syst-prini|syst-primm|syst-prrel|syst-playo|syst-prbig|syst-playp|syst-prnew|syst-prlog|syst-pdest|syst-plist|syst-pauth|syst-prdsn|syst-pnwpa|syst-callr|syst-repi2|syst-rtitl|syst-prrec|syst-prtxt|syst-prabt|syst-lpass|syst-nrpag|syst-paart|syst-prcop|syst-batzs|syst-bspld|syst-brep4|syst-batzo|syst-batzd|syst-batzw|syst-batzm|syst-ctabl|syst-dbsys|syst-dcsys|syst-macdb|syst-sysid|syst-opsys|syst-pfkey|syst-saprl|syst-tcode|syst-ucomm|syst-cfwae|syst-chwae|syst-spono|syst-sponr|syst-waers|syst-cdate|syst-datum|syst-slset|syst-subty|syst-subcs|syst-group|syst-ffile|syst-uzeit|syst-dsnam|syst-repid|syst-tabid|syst-tfdsn|syst-uname|syst-lstat|syst-abcde|syst-marky|syst-sfnam|syst-tname|syst-msgli|syst-title|syst-entry|syst-lisel|syst-uline|syst-xcode|syst-cprog|syst-xprog|syst-xform|syst-ldbpg|syst-tvar0|syst-tvar1|syst-tvar2|syst-tvar3|syst-tvar4|syst-tvar5|syst-tvar6|syst-tvar7|syst-tvar8|syst-tvar9|syst-msgid|syst-msgty|syst-msgno|syst-msgv1|syst-msgv2|syst-msgv3|syst-msgv4|syst-oncom|syst-vline|syst-winsl|syst-staco|syst-staro|syst-datar|syst-host|syst-locdb|syst-locop|syst-datlo|syst-timlo|syst-zonlo)$/',
'reserved' => '/^((?i)abs|acos|add|add-corresponding|adjacent|after|aliases|all|analyzer|and|any|append|as|ascending|asin|assign|assigned|assigning|at|atan|authority-check|avg|back|before|begin|binary|bit|bit-and|bit-not|bit-or|bit-xor|blank|block|break-point|buffer|by|c|call|case|catch|ceil|centered|chain|change|changing|check|checkbox|class|class-data|class-events|class-methods|class-pool|clear|client|close|cnt|code|collect|color|comment|commit|communication|compute|concatenate|condense|constants|context|contexts|continue|control|controls|convert|copy|corresponding|cos|cosh|count|country|create|currency|cursor|customer-function|data|database|dataset|delete|decimals|default|define|demand|descending|describe|dialog|distinct|div|divide|divide-corresponding|do|duplicates|dynpro|edit|editor-call|else|elseif|end|end-of-definition|end-of-page|end-of-selection|endat|endcase|endcatch|endchain|endclass|enddo|endexec|endform|endfunction|endif|endinterface|endloop|endmethod|endmodule|endon|endprovide|endselect|endwhile|entries|events|exec|exit|exit-command|exp|exponent|export|exporting|exceptions|extended|extract|fetch|field|field-groups|field-symbols|fields|floor|for|form|format|frac|frame|free|from|function|function-pool|generate|get|group|hashed|header|help-id|help-request|hide|hotspot|icon|id|if|import|importing|include|index|infotypes|initialization|inner|input|insert|intensified|interface|interface-pool|interfaces|into|inverse|join|key|language|last|leave|left|left-justified|like|line|line-count|line-selection|line-size|lines|list-processing|load|load-of-program|local|locale|log|log10|loop|m|margin|mask|matchcode|max|memory|message|message-id|messages|method|methods|min|mod|mode|modif|modify|module|move|move-corresponding|multiply|multiply-corresponding|new|new-line|new-page|next|no|no-gap|no-gaps|no-heading|no-scrolling|no-sign|no-title|no-zero|nodes|non-unique|o|object|obligatory|occurs|of|off|on|open|or|order|others|outer|output|overlay|pack|page|parameter|parameters|perform|pf-status|position|print|print-control|private|process|program|property|protected|provide|public|put|radiobutton|raise|raising|range|ranges|read|receive|refresh|reject|replace|report|requested|reserve|reset|right-justified|rollback|round|rows|rtti|run|scan|screen|search|separated|scroll|scroll-boundary|select|select-options|selection-screen|selection-table|set|shared|shift|sign|sin|single|sinh|size|skip|sort|sorted|split|sql|sqrt|stamp|standard|start-of-selection|statics|stop|string|strlen|structure|submit|subtract|subtract-corresponding|sum|supply|suppress|symbol|syntax-check|syntax-trace|system-call|system-exceptions|table|table_line|tables|tan|tanh|text|textpool|time|times|title|titlebar|to|top-of-page|transaction|transfer|translate|transporting|trunc|type|type-pool|type-pools|types|uline|under|unique|unit|unpack|up|update|user-command|using|value|value-request|values|vary|when|where|while|window|with|with-title|work|write|x|xstring|z|zone)$/',
'constants' => '/^((?i)initial|null|space|col_background|col_heading|col_normal|col_total|col_key|col_positive|col_negative|col_group)$/',
),
),
2 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 => -1,
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 =>
array (
'sy' => '/^((?i)screen-name|screen-group1|screen-group2|screen-group3|screen-group4|screen-required|screen-input|screen-output|screen-intensified|screen-invisible|screen-length|screen-active|sy-index|sy-pagno|sy-tabix|sy-tfill|sy-tlopc|sy-tmaxl|sy-toccu|sy-ttabc|sy-tstis|sy-ttabi|sy-dbcnt|sy-fdpos|sy-colno|sy-linct|sy-linno|sy-linsz|sy-pagct|sy-macol|sy-marow|sy-tleng|sy-sfoff|sy-willi|sy-lilli|sy-subrc|sy-fleng|sy-cucol|sy-curow|sy-lsind|sy-listi|sy-stepl|sy-tpagi|sy-winx1|sy-winy1|sy-winx2|sy-winy2|sy-winco|sy-winro|sy-windi|sy-srows|sy-scols|sy-loopc|sy-folen|sy-fodec|sy-tzone|sy-dayst|sy-ftype|sy-appli|sy-fdayw|sy-ccurs|sy-ccurt|sy-debug|sy-ctype|sy-input|sy-langu|sy-modno|sy-batch|sy-binpt|sy-calld|sy-dynnr|sy-dyngr|sy-newpa|sy-pri40|sy-rstrt|sy-wtitl|sy-cpage|sy-dbnam|sy-mandt|sy-prefx|sy-fmkey|sy-pexpi|sy-prini|sy-primm|sy-prrel|sy-playo|sy-prbig|sy-playp|sy-prnew|sy-prlog|sy-pdest|sy-plist|sy-pauth|sy-prdsn|sy-pnwpa|sy-callr|sy-repi2|sy-rtitl|sy-prrec|sy-prtxt|sy-prabt|sy-lpass|sy-nrpag|sy-paart|sy-prcop|sy-batzs|sy-bspld|sy-brep4|sy-batzo|sy-batzd|sy-batzw|sy-batzm|sy-ctabl|sy-dbsys|sy-dcsys|sy-macdb|sy-sysid|sy-opsys|sy-pfkey|sy-saprl|sy-tcode|sy-ucomm|sy-cfwae|sy-chwae|sy-spono|sy-sponr|sy-waers|sy-cdate|sy-datum|sy-slset|sy-subty|sy-subcs|sy-group|sy-ffile|sy-uzeit|sy-dsnam|sy-repid|sy-tabid|sy-tfdsn|sy-uname|sy-lstat|sy-abcde|sy-marky|sy-sfnam|sy-tname|sy-msgli|sy-title|sy-entry|sy-lisel|sy-uline|sy-xcode|sy-cprog|sy-xprog|sy-xform|sy-ldbpg|sy-tvar0|sy-tvar1|sy-tvar2|sy-tvar3|sy-tvar4|sy-tvar5|sy-tvar6|sy-tvar7|sy-tvar8|sy-tvar9|sy-msgid|sy-msgty|sy-msgno|sy-msgv1|sy-msgv2|sy-msgv3|sy-msgv4|sy-oncom|sy-vline|sy-winsl|sy-staco|sy-staro|sy-datar|sy-host|sy-locdb|sy-locop|sy-datlo|sy-timlo|sy-zonlo|syst-index|syst-pagno|syst-tabix|syst-tfill|syst-tlopc|syst-tmaxl|syst-toccu|syst-ttabc|syst-tstis|syst-ttabi|syst-dbcnt|syst-fdpos|syst-colno|syst-linct|syst-linno|syst-linsz|syst-pagct|syst-macol|syst-marow|syst-tleng|syst-sfoff|syst-willi|syst-lilli|syst-subrc|syst-fleng|syst-cucol|syst-curow|syst-lsind|syst-listi|syst-stepl|syst-tpagi|syst-winx1|syst-winy1|syst-winx2|syst-winy2|syst-winco|syst-winro|syst-windi|syst-srows|syst-scols|syst-loopc|syst-folen|syst-fodec|syst-tzone|syst-dayst|syst-ftype|syst-appli|syst-fdayw|syst-ccurs|syst-ccurt|syst-debug|syst-ctype|syst-input|syst-langu|syst-modno|syst-batch|syst-binpt|syst-calld|syst-dynnr|syst-dyngr|syst-newpa|syst-pri40|syst-rstrt|syst-wtitl|syst-cpage|syst-dbnam|syst-mandt|syst-prefx|syst-fmkey|syst-pexpi|syst-prini|syst-primm|syst-prrel|syst-playo|syst-prbig|syst-playp|syst-prnew|syst-prlog|syst-pdest|syst-plist|syst-pauth|syst-prdsn|syst-pnwpa|syst-callr|syst-repi2|syst-rtitl|syst-prrec|syst-prtxt|syst-prabt|syst-lpass|syst-nrpag|syst-paart|syst-prcop|syst-batzs|syst-bspld|syst-brep4|syst-batzo|syst-batzd|syst-batzw|syst-batzm|syst-ctabl|syst-dbsys|syst-dcsys|syst-macdb|syst-sysid|syst-opsys|syst-pfkey|syst-saprl|syst-tcode|syst-ucomm|syst-cfwae|syst-chwae|syst-spono|syst-sponr|syst-waers|syst-cdate|syst-datum|syst-slset|syst-subty|syst-subcs|syst-group|syst-ffile|syst-uzeit|syst-dsnam|syst-repid|syst-tabid|syst-tfdsn|syst-uname|syst-lstat|syst-abcde|syst-marky|syst-sfnam|syst-tname|syst-msgli|syst-title|syst-entry|syst-lisel|syst-uline|syst-xcode|syst-cprog|syst-xprog|syst-xform|syst-ldbpg|syst-tvar0|syst-tvar1|syst-tvar2|syst-tvar3|syst-tvar4|syst-tvar5|syst-tvar6|syst-tvar7|syst-tvar8|syst-tvar9|syst-msgid|syst-msgty|syst-msgno|syst-msgv1|syst-msgv2|syst-msgv3|syst-msgv4|syst-oncom|syst-vline|syst-winsl|syst-staco|syst-staro|syst-datar|syst-host|syst-locdb|syst-locop|syst-datlo|syst-timlo|syst-zonlo)$/',
'reserved' => '/^((?i)abs|acos|add|add-corresponding|adjacent|after|aliases|all|analyzer|and|any|append|as|ascending|asin|assign|assigned|assigning|at|atan|authority-check|avg|back|before|begin|binary|bit|bit-and|bit-not|bit-or|bit-xor|blank|block|break-point|buffer|by|c|call|case|catch|ceil|centered|chain|change|changing|check|checkbox|class|class-data|class-events|class-methods|class-pool|clear|client|close|cnt|code|collect|color|comment|commit|communication|compute|concatenate|condense|constants|context|contexts|continue|control|controls|convert|copy|corresponding|cos|cosh|count|country|create|currency|cursor|customer-function|data|database|dataset|delete|decimals|default|define|demand|descending|describe|dialog|distinct|div|divide|divide-corresponding|do|duplicates|dynpro|edit|editor-call|else|elseif|end|end-of-definition|end-of-page|end-of-selection|endat|endcase|endcatch|endchain|endclass|enddo|endexec|endform|endfunction|endif|endinterface|endloop|endmethod|endmodule|endon|endprovide|endselect|endwhile|entries|events|exec|exit|exit-command|exp|exponent|export|exporting|exceptions|extended|extract|fetch|field|field-groups|field-symbols|fields|floor|for|form|format|frac|frame|free|from|function|function-pool|generate|get|group|hashed|header|help-id|help-request|hide|hotspot|icon|id|if|import|importing|include|index|infotypes|initialization|inner|input|insert|intensified|interface|interface-pool|interfaces|into|inverse|join|key|language|last|leave|left|left-justified|like|line|line-count|line-selection|line-size|lines|list-processing|load|load-of-program|local|locale|log|log10|loop|m|margin|mask|matchcode|max|memory|message|message-id|messages|method|methods|min|mod|mode|modif|modify|module|move|move-corresponding|multiply|multiply-corresponding|new|new-line|new-page|next|no|no-gap|no-gaps|no-heading|no-scrolling|no-sign|no-title|no-zero|nodes|non-unique|o|object|obligatory|occurs|of|off|on|open|or|order|others|outer|output|overlay|pack|page|parameter|parameters|perform|pf-status|position|print|print-control|private|process|program|property|protected|provide|public|put|radiobutton|raise|raising|range|ranges|read|receive|refresh|reject|replace|report|requested|reserve|reset|right-justified|rollback|round|rows|rtti|run|scan|screen|search|separated|scroll|scroll-boundary|select|select-options|selection-screen|selection-table|set|shared|shift|sign|sin|single|sinh|size|skip|sort|sorted|split|sql|sqrt|stamp|standard|start-of-selection|statics|stop|string|strlen|structure|submit|subtract|subtract-corresponding|sum|supply|suppress|symbol|syntax-check|syntax-trace|system-call|system-exceptions|table|table_line|tables|tan|tanh|text|textpool|time|times|title|titlebar|to|top-of-page|transaction|transfer|translate|transporting|trunc|type|type-pool|type-pools|types|uline|under|unique|unit|unpack|up|update|user-command|using|value|value-request|values|vary|when|where|while|window|with|with-title|work|write|x|xstring|z|zone)$/',
'constants' => '/^((?i)initial|null|space|col_background|col_heading|col_normal|col_total|col_key|col_positive|col_negative|col_group)$/',
),
),
3 =>
array (
),
4 =>
array (
),
);
$this->_parts = array (
0 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
),
1 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
),
2 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
),
3 =>
array (
),
4 =>
array (
),
);
$this->_subst = array (
-1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
),
0 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
),
1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
),
2 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
),
3 =>
array (
),
4 =>
array (
),
);
$this->_conditions = array (
);
$this->_kwmap = array (
'sy' => 'reserved',
'reserved' => 'reserved',
'constants' => 'reserved',
);
$this->_defClass = 'code';
$this->_checkDefines();
}
}

View file

@ -0,0 +1,894 @@
<?php
/**
* Auto-generated class. AVRC syntax highlighting
*
*
* C/C++ highlighter specific to Atmel AVR microcontrollers
*
*
* PHP version 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @link http://pear.php.net/package/Text_Highlighter
* @category Text
* @package Text_Highlighter
* @version generated from: avrc.xml
* @author Andrey Demenev <demenev@gmail.com>
*
*/
/**
* @ignore
*/
require_once 'Text/Highlighter.php';
/**
* Auto-generated class. AVRC syntax highlighting
*
* @author Andrey Demenev <demenev@gmail.com>
* @category Text
* @package Text_Highlighter
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: 0.7.0
* @link http://pear.php.net/package/Text_Highlighter
*/
class Text_Highlighter_AVRC extends Text_Highlighter
{
var $_language = 'avrc';
/**
* PHP4 Compatible Constructor
*
* @param array $options
* @access public
*/
function Text_Highlighter_AVRC($options=array())
{
$this->__construct($options);
}
/**
* Constructor
*
* @param array $options
* @access public
*/
function __construct($options=array())
{
$this->_options = $options;
$this->_regs = array (
-1 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
0 => '/((?i)\\\\)/',
1 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
2 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
3 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
4 => '//',
5 => '/((?i)")|((?i)<)/',
6 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?i)\\/\\*)|((?i)\\/\\/.+)/',
7 => '/((?i)\\$\\w+\\s*:.+\\$)/',
8 => '/((?i)\\$\\w+\\s*:.+\\$)/',
);
$this->_counts = array (
-1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
0 =>
array (
0 => 0,
),
1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
2 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
3 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
4 =>
array (
),
5 =>
array (
0 => 0,
1 => 0,
),
6 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 2,
8 => 0,
9 => 0,
),
7 =>
array (
0 => 0,
),
8 =>
array (
0 => 0,
),
);
$this->_delim = array (
-1 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
0 =>
array (
0 => '',
),
1 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
2 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
3 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
4 =>
array (
),
5 =>
array (
0 => 'quotes',
1 => 'quotes',
),
6 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => '',
4 => '',
5 => '',
6 => '',
7 => '',
8 => 'mlcomment',
9 => 'comment',
),
7 =>
array (
0 => '',
),
8 =>
array (
0 => '',
),
);
$this->_inner = array (
-1 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
0 =>
array (
0 => 'special',
),
1 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
2 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
3 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
4 =>
array (
),
5 =>
array (
0 => 'string',
1 => 'string',
),
6 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'identifier',
4 => 'number',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'mlcomment',
9 => 'comment',
),
7 =>
array (
0 => 'inlinedoc',
),
8 =>
array (
0 => 'inlinedoc',
),
);
$this->_end = array (
0 => '/(?i)"/',
1 => '/(?i)\\}/',
2 => '/(?i)\\)/',
3 => '/(?i)\\]/',
4 => '/(?i)>/',
5 => '/(?mi)(?<!\\\\)$/',
6 => '/(?mi)(?<!\\\\)$/',
7 => '/(?i)\\*\\//',
8 => '/(?mi)$/',
);
$this->_states = array (
-1 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
0 =>
array (
0 => -1,
),
1 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
2 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
3 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
4 =>
array (
),
5 =>
array (
0 => 0,
1 => 4,
),
6 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => -1,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => 7,
9 => 8,
),
7 =>
array (
0 => -1,
),
8 =>
array (
0 => -1,
),
);
$this->_keywords = array (
-1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'registers' => '/^(ACSR|ADCH|ADCL|ADCSRA|ADMUX|ASSR|DDRA|DDRB|DDRC|DDRD|DDRE|DDRF|DDRG|EEARH|EEARL|EECR|EEDR|EICRA|EICRB|EIFR|EIMSK|ETIFR|ETIMSK|GICR|GIFR|ICR1H|ICR1L|ICR3H|ICR3L|MCUCR|MCUCSR|OCDR|OCR0|OCR1AH|OCR1AL|OCR1BH|OCR1BL|OCR1CH|OCR1CL|OCR2|OCR3AH|OCR3AL|OCR3BH|OCR3BL|OCR3CH|OCR3CL|OSCCAL|PINA|PINB|PINC|PIND|PINE|PINF|PING|PORTA|PORTB|PORTC|PORTD|PORTE|PORTF|PORTG|RAMPZ|SFIOR|SPCR|SPDR|SPH|SPL|SPMCR|SPMCSR|SPSR|SREG|TCCR0|TCCR1A|TCCR1B|TCCR1C|TCCR2|TCCR3A|TCCR3B|TCCR3C|TCNT0|TCNT1H|TCNT1L|TCNT2|TCNT3H|TCNT3L|TIFR|TIMSK|TWAR|TWBR|TWCR|TWDR|TWSR|UBRR0H|UBRR0L|UBRR1H|UBRR1L|UBRRH|UBRRL|UCSR0A|UCSR0B|UCSR0C|UCSR1A|UCSR1B|UCSR1C|UCSRA|UCSRB|UCSRC|UDR|UDR0|UDR1|WDTCR|XDIV|XMCRA|XMCRB)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
0 =>
array (
0 =>
array (
),
),
1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'registers' => '/^(ACSR|ADCH|ADCL|ADCSRA|ADMUX|ASSR|DDRA|DDRB|DDRC|DDRD|DDRE|DDRF|DDRG|EEARH|EEARL|EECR|EEDR|EICRA|EICRB|EIFR|EIMSK|ETIFR|ETIMSK|GICR|GIFR|ICR1H|ICR1L|ICR3H|ICR3L|MCUCR|MCUCSR|OCDR|OCR0|OCR1AH|OCR1AL|OCR1BH|OCR1BL|OCR1CH|OCR1CL|OCR2|OCR3AH|OCR3AL|OCR3BH|OCR3BL|OCR3CH|OCR3CL|OSCCAL|PINA|PINB|PINC|PIND|PINE|PINF|PING|PORTA|PORTB|PORTC|PORTD|PORTE|PORTF|PORTG|RAMPZ|SFIOR|SPCR|SPDR|SPH|SPL|SPMCR|SPMCSR|SPSR|SREG|TCCR0|TCCR1A|TCCR1B|TCCR1C|TCCR2|TCCR3A|TCCR3B|TCCR3C|TCNT0|TCNT1H|TCNT1L|TCNT2|TCNT3H|TCNT3L|TIFR|TIMSK|TWAR|TWBR|TWCR|TWDR|TWSR|UBRR0H|UBRR0L|UBRR1H|UBRR1L|UBRRH|UBRRL|UCSR0A|UCSR0B|UCSR0C|UCSR1A|UCSR1B|UCSR1C|UCSRA|UCSRB|UCSRC|UDR|UDR0|UDR1|WDTCR|XDIV|XMCRA|XMCRB)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
2 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'registers' => '/^(ACSR|ADCH|ADCL|ADCSRA|ADMUX|ASSR|DDRA|DDRB|DDRC|DDRD|DDRE|DDRF|DDRG|EEARH|EEARL|EECR|EEDR|EICRA|EICRB|EIFR|EIMSK|ETIFR|ETIMSK|GICR|GIFR|ICR1H|ICR1L|ICR3H|ICR3L|MCUCR|MCUCSR|OCDR|OCR0|OCR1AH|OCR1AL|OCR1BH|OCR1BL|OCR1CH|OCR1CL|OCR2|OCR3AH|OCR3AL|OCR3BH|OCR3BL|OCR3CH|OCR3CL|OSCCAL|PINA|PINB|PINC|PIND|PINE|PINF|PING|PORTA|PORTB|PORTC|PORTD|PORTE|PORTF|PORTG|RAMPZ|SFIOR|SPCR|SPDR|SPH|SPL|SPMCR|SPMCSR|SPSR|SREG|TCCR0|TCCR1A|TCCR1B|TCCR1C|TCCR2|TCCR3A|TCCR3B|TCCR3C|TCNT0|TCNT1H|TCNT1L|TCNT2|TCNT3H|TCNT3L|TIFR|TIMSK|TWAR|TWBR|TWCR|TWDR|TWSR|UBRR0H|UBRR0L|UBRR1H|UBRR1L|UBRRH|UBRRL|UCSR0A|UCSR0B|UCSR0C|UCSR1A|UCSR1B|UCSR1C|UCSRA|UCSRB|UCSRC|UDR|UDR0|UDR1|WDTCR|XDIV|XMCRA|XMCRB)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
3 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'registers' => '/^(ACSR|ADCH|ADCL|ADCSRA|ADMUX|ASSR|DDRA|DDRB|DDRC|DDRD|DDRE|DDRF|DDRG|EEARH|EEARL|EECR|EEDR|EICRA|EICRB|EIFR|EIMSK|ETIFR|ETIMSK|GICR|GIFR|ICR1H|ICR1L|ICR3H|ICR3L|MCUCR|MCUCSR|OCDR|OCR0|OCR1AH|OCR1AL|OCR1BH|OCR1BL|OCR1CH|OCR1CL|OCR2|OCR3AH|OCR3AL|OCR3BH|OCR3BL|OCR3CH|OCR3CL|OSCCAL|PINA|PINB|PINC|PIND|PINE|PINF|PING|PORTA|PORTB|PORTC|PORTD|PORTE|PORTF|PORTG|RAMPZ|SFIOR|SPCR|SPDR|SPH|SPL|SPMCR|SPMCSR|SPSR|SREG|TCCR0|TCCR1A|TCCR1B|TCCR1C|TCCR2|TCCR3A|TCCR3B|TCCR3C|TCNT0|TCNT1H|TCNT1L|TCNT2|TCNT3H|TCNT3L|TIFR|TIMSK|TWAR|TWBR|TWCR|TWDR|TWSR|UBRR0H|UBRR0L|UBRR1H|UBRR1L|UBRRH|UBRRL|UCSR0A|UCSR0B|UCSR0C|UCSR1A|UCSR1B|UCSR1C|UCSRA|UCSRB|UCSRC|UDR|UDR0|UDR1|WDTCR|XDIV|XMCRA|XMCRB)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
4 =>
array (
),
5 =>
array (
0 => -1,
1 => -1,
),
6 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'registers' => '/^(ACSR|ADCH|ADCL|ADCSRA|ADMUX|ASSR|DDRA|DDRB|DDRC|DDRD|DDRE|DDRF|DDRG|EEARH|EEARL|EECR|EEDR|EICRA|EICRB|EIFR|EIMSK|ETIFR|ETIMSK|GICR|GIFR|ICR1H|ICR1L|ICR3H|ICR3L|MCUCR|MCUCSR|OCDR|OCR0|OCR1AH|OCR1AL|OCR1BH|OCR1BL|OCR1CH|OCR1CL|OCR2|OCR3AH|OCR3AL|OCR3BH|OCR3BL|OCR3CH|OCR3CL|OSCCAL|PINA|PINB|PINC|PIND|PINE|PINF|PING|PORTA|PORTB|PORTC|PORTD|PORTE|PORTF|PORTG|RAMPZ|SFIOR|SPCR|SPDR|SPH|SPL|SPMCR|SPMCSR|SPSR|SREG|TCCR0|TCCR1A|TCCR1B|TCCR1C|TCCR2|TCCR3A|TCCR3B|TCCR3C|TCNT0|TCNT1H|TCNT1L|TCNT2|TCNT3H|TCNT3L|TIFR|TIMSK|TWAR|TWBR|TWCR|TWDR|TWSR|UBRR0H|UBRR0L|UBRR1H|UBRR1L|UBRRH|UBRRL|UCSR0A|UCSR0B|UCSR0C|UCSR1A|UCSR1B|UCSR1C|UCSRA|UCSRB|UCSRC|UDR|UDR0|UDR1|WDTCR|XDIV|XMCRA|XMCRB)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
4 =>
array (
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 => -1,
9 => -1,
),
7 =>
array (
0 =>
array (
),
),
8 =>
array (
0 =>
array (
),
),
);
$this->_parts = array (
0 =>
array (
0 => NULL,
),
1 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
10 => NULL,
11 => NULL,
12 => NULL,
13 => NULL,
),
2 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
10 => NULL,
11 => NULL,
12 => NULL,
13 => NULL,
),
3 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
10 => NULL,
11 => NULL,
12 => NULL,
13 => NULL,
),
4 =>
array (
),
5 =>
array (
0 => NULL,
1 => NULL,
),
6 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
),
7 =>
array (
0 => NULL,
),
8 =>
array (
0 => NULL,
),
);
$this->_subst = array (
-1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
0 =>
array (
0 => false,
),
1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
2 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
3 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
4 =>
array (
),
5 =>
array (
0 => false,
1 => false,
),
6 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
),
7 =>
array (
0 => false,
),
8 =>
array (
0 => false,
),
);
$this->_conditions = array (
);
$this->_kwmap = array (
'reserved' => 'reserved',
'registers' => 'reserved',
'types' => 'types',
'Common Macros' => 'prepro',
);
$this->_defClass = 'code';
$this->_checkDefines();
}
}

View file

@ -0,0 +1,891 @@
<?php
/**
* Auto-generated class. CPP syntax highlighting
*
*
* Thanks to Aaron Kalin for initial
* implementation of this highlighter
*
*
* PHP version 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @link http://pear.php.net/package/Text_Highlighter
* @category Text
* @package Text_Highlighter
* @version generated from: cpp.xml
* @author Aaron Kalin
* @author Andrey Demenev <demenev@gmail.com>
*
*/
/**
* @ignore
*/
require_once 'Text/Highlighter.php';
/**
* Auto-generated class. CPP syntax highlighting
*
* @author Aaron Kalin
* @author Andrey Demenev <demenev@gmail.com>
* @category Text
* @package Text_Highlighter
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: 0.7.0
* @link http://pear.php.net/package/Text_Highlighter
*/
class Text_Highlighter_CPP extends Text_Highlighter
{
var $_language = 'cpp';
/**
* PHP4 Compatible Constructor
*
* @param array $options
* @access public
*/
function Text_Highlighter_CPP($options=array())
{
$this->__construct($options);
}
/**
* Constructor
*
* @param array $options
* @access public
*/
function __construct($options=array())
{
$this->_options = $options;
$this->_regs = array (
-1 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
0 => '/((?i)\\\\)/',
1 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
2 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
3 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)\\[)|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?mi)^[ \\t]*#include)|((?mii)^[ \\t]*#[ \\t]*[a-z]+)|((?i)\\d*\\.?\\d+)|((?i)\\/\\*)|((?i)\\/\\/.+)/',
4 => '//',
5 => '/((?i)")|((?i)<)/',
6 => '/((?i)")|((?i)\\{)|((?i)\\()|((?i)[a-z_]\\w*)|((?i)\\b0[xX][\\da-f]+)|((?i)\\b\\d\\d*|\\b0\\b)|((?i)\\b0[0-7]+)|((?i)\\b(\\d*\\.\\d+)|(\\d+\\.\\d*))|((?i)\\/\\*)|((?i)\\/\\/.+)/',
7 => '/((?i)\\$\\w+\\s*:.+\\$)/',
8 => '/((?i)\\$\\w+\\s*:.+\\$)/',
);
$this->_counts = array (
-1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
0 =>
array (
0 => 0,
),
1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
2 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
3 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 2,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
),
4 =>
array (
),
5 =>
array (
0 => 0,
1 => 0,
),
6 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 2,
8 => 0,
9 => 0,
),
7 =>
array (
0 => 0,
),
8 =>
array (
0 => 0,
),
);
$this->_delim = array (
-1 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
0 =>
array (
0 => '',
),
1 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
2 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
3 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => 'brackets',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => 'prepro',
10 => 'prepro',
11 => '',
12 => 'mlcomment',
13 => 'comment',
),
4 =>
array (
),
5 =>
array (
0 => 'quotes',
1 => 'quotes',
),
6 =>
array (
0 => 'quotes',
1 => 'brackets',
2 => 'brackets',
3 => '',
4 => '',
5 => '',
6 => '',
7 => '',
8 => 'mlcomment',
9 => 'comment',
),
7 =>
array (
0 => '',
),
8 =>
array (
0 => '',
),
);
$this->_inner = array (
-1 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
0 =>
array (
0 => 'special',
),
1 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
2 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
3 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'code',
4 => 'identifier',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'number',
9 => 'prepro',
10 => 'code',
11 => 'number',
12 => 'mlcomment',
13 => 'comment',
),
4 =>
array (
),
5 =>
array (
0 => 'string',
1 => 'string',
),
6 =>
array (
0 => 'string',
1 => 'code',
2 => 'code',
3 => 'identifier',
4 => 'number',
5 => 'number',
6 => 'number',
7 => 'number',
8 => 'mlcomment',
9 => 'comment',
),
7 =>
array (
0 => 'inlinedoc',
),
8 =>
array (
0 => 'inlinedoc',
),
);
$this->_end = array (
0 => '/(?i)"/',
1 => '/(?i)\\}/',
2 => '/(?i)\\)/',
3 => '/(?i)\\]/',
4 => '/(?i)>/',
5 => '/(?mi)(?<!\\\\)$/',
6 => '/(?mi)(?<!\\\\)$/',
7 => '/(?i)\\*\\//',
8 => '/(?mi)$/',
);
$this->_states = array (
-1 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
0 =>
array (
0 => -1,
),
1 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
2 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
3 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => 5,
10 => 6,
11 => -1,
12 => 7,
13 => 8,
),
4 =>
array (
),
5 =>
array (
0 => 0,
1 => 4,
),
6 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => -1,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => 7,
9 => 8,
),
7 =>
array (
0 => -1,
),
8 =>
array (
0 => -1,
),
);
$this->_keywords = array (
-1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
0 =>
array (
0 =>
array (
),
),
1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
2 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
3 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 => -1,
10 => -1,
11 =>
array (
),
12 => -1,
13 => -1,
),
4 =>
array (
),
5 =>
array (
0 => -1,
1 => -1,
),
6 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 =>
array (
'reserved' => '/^(and|and_eq|asm|bitand|bitor|break|case|catch|compl|const_cast|continue|default|delete|do|dynamic_cast|else|for|fortran|friend|goto|if|new|not|not_eq|operator|or|or_eq|private|protected|public|reinterpret_cast|return|sizeof|static_cast|switch|this|throw|try|typeid|using|while|xor|xor_eq|false|true)$/',
'types' => '/^(auto|bool|char|class|const|double|enum|explicit|export|extern|float|inline|int|long|mutable|namespace|register|short|signed|static|struct|template|typedef|typename|union|unsigned|virtual|void|volatile|wchar_t)$/',
'Common Macros' => '/^(NULL|TRUE|FALSE|MAX|MIN|__LINE__|__DATA__|__FILE__|__TIME__|__STDC__)$/',
),
4 =>
array (
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 => -1,
9 => -1,
),
7 =>
array (
0 =>
array (
),
),
8 =>
array (
0 =>
array (
),
),
);
$this->_parts = array (
0 =>
array (
0 => NULL,
),
1 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
10 => NULL,
11 => NULL,
12 => NULL,
13 => NULL,
),
2 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
10 => NULL,
11 => NULL,
12 => NULL,
13 => NULL,
),
3 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
10 => NULL,
11 => NULL,
12 => NULL,
13 => NULL,
),
4 =>
array (
),
5 =>
array (
0 => NULL,
1 => NULL,
),
6 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
9 => NULL,
),
7 =>
array (
0 => NULL,
),
8 =>
array (
0 => NULL,
),
);
$this->_subst = array (
-1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
0 =>
array (
0 => false,
),
1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
2 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
3 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
),
4 =>
array (
),
5 =>
array (
0 => false,
1 => false,
),
6 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
),
7 =>
array (
0 => false,
),
8 =>
array (
0 => false,
),
);
$this->_conditions = array (
);
$this->_kwmap = array (
'reserved' => 'reserved',
'types' => 'types',
'Common Macros' => 'prepro',
);
$this->_defClass = 'code';
$this->_checkDefines();
}
}

View file

@ -0,0 +1,437 @@
<?php
/**
* Auto-generated class. CSS syntax highlighting
*
* PHP version 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @link http://pear.php.net/package/Text_Highlighter
* @category Text
* @package Text_Highlighter
* @version generated from: css.xml
* @author Andrey Demenev <demenev@gmail.com>
*
*/
/**
* @ignore
*/
require_once 'Text/Highlighter.php';
/**
* Auto-generated class. CSS syntax highlighting
*
* @author Andrey Demenev <demenev@gmail.com>
* @category Text
* @package Text_Highlighter
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: 0.7.0
* @link http://pear.php.net/package/Text_Highlighter
*/
class Text_Highlighter_CSS extends Text_Highlighter
{
var $_language = 'css';
/**
* PHP4 Compatible Constructor
*
* @param array $options
* @access public
*/
function Text_Highlighter_CSS($options=array())
{
$this->__construct($options);
}
/**
* Constructor
*
* @param array $options
* @access public
*/
function __construct($options=array())
{
$this->_options = $options;
$this->_regs = array (
-1 => '/((?i)\\/\\*)|((?i)(@[a-z\\d]+))|((?i)(((\\.|#)?[a-z]+[a-z\\d\\-]*(?![a-z\\d\\-]))|(\\*))(?!\\s*:\\s*[\\s\\{]))|((?i):[a-z][a-z\\d\\-]*)|((?i)\\[)|((?i)\\{)/',
0 => '//',
1 => '/((?i)\\d*\\.?\\d+(\\%|em|ex|pc|pt|px|in|mm|cm))|((?i)\\d*\\.?\\d+)|((?i)[a-z][a-z\\d\\-]*)|((?i)#([\\da-f]{6}|[\\da-f]{3})\\b)/',
2 => '/((?i)\')|((?i)")|((?i)[\\w\\-\\:]+)/',
3 => '/((?i)\\/\\*)|((?i)[a-z][a-z\\d\\-]*\\s*:)|((?i)(((\\.|#)?[a-z]+[a-z\\d\\-]*(?![a-z\\d\\-]))|(\\*))(?!\\s*:\\s*[\\s\\{]))|((?i)\\{)/',
4 => '/((?i)\\\\[\\\\(\\\\)\\\\])/',
5 => '/((?i)\\\\\\\\|\\\\"|\\\\\'|\\\\`)/',
6 => '/((?i)\\\\\\\\|\\\\"|\\\\\'|\\\\`|\\\\t|\\\\n|\\\\r)/',
);
$this->_counts = array (
-1 =>
array (
0 => 0,
1 => 1,
2 => 4,
3 => 0,
4 => 0,
5 => 0,
),
0 =>
array (
),
1 =>
array (
0 => 1,
1 => 0,
2 => 0,
3 => 1,
),
2 =>
array (
0 => 0,
1 => 0,
2 => 0,
),
3 =>
array (
0 => 0,
1 => 0,
2 => 4,
3 => 0,
),
4 =>
array (
0 => 0,
),
5 =>
array (
0 => 0,
),
6 =>
array (
0 => 0,
),
);
$this->_delim = array (
-1 =>
array (
0 => 'comment',
1 => '',
2 => '',
3 => '',
4 => 'brackets',
5 => 'brackets',
),
0 =>
array (
),
1 =>
array (
0 => '',
1 => '',
2 => '',
3 => '',
),
2 =>
array (
0 => 'quotes',
1 => 'quotes',
2 => '',
),
3 =>
array (
0 => 'comment',
1 => 'reserved',
2 => '',
3 => 'brackets',
),
4 =>
array (
0 => '',
),
5 =>
array (
0 => '',
),
6 =>
array (
0 => '',
),
);
$this->_inner = array (
-1 =>
array (
0 => 'comment',
1 => 'var',
2 => 'identifier',
3 => 'special',
4 => 'code',
5 => 'code',
),
0 =>
array (
),
1 =>
array (
0 => 'number',
1 => 'number',
2 => 'code',
3 => 'var',
),
2 =>
array (
0 => 'string',
1 => 'string',
2 => 'var',
),
3 =>
array (
0 => 'comment',
1 => 'code',
2 => 'identifier',
3 => 'code',
),
4 =>
array (
0 => 'string',
),
5 =>
array (
0 => 'special',
),
6 =>
array (
0 => 'special',
),
);
$this->_end = array (
0 => '/(?i)\\*\\//',
1 => '/(?i)(?=;|\\})/',
2 => '/(?i)\\]/',
3 => '/(?i)\\}/',
4 => '/(?i)\\)/',
5 => '/(?i)\'/',
6 => '/(?i)"/',
);
$this->_states = array (
-1 =>
array (
0 => 0,
1 => -1,
2 => -1,
3 => -1,
4 => 2,
5 => 3,
),
0 =>
array (
),
1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
),
2 =>
array (
0 => 5,
1 => 6,
2 => -1,
),
3 =>
array (
0 => 0,
1 => 1,
2 => -1,
3 => 3,
),
4 =>
array (
0 => -1,
),
5 =>
array (
0 => -1,
),
6 =>
array (
0 => -1,
),
);
$this->_keywords = array (
-1 =>
array (
0 => -1,
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 => -1,
5 => -1,
),
0 =>
array (
),
1 =>
array (
0 =>
array (
),
1 =>
array (
),
2 =>
array (
'propertyValue' => '/^((?i)far-left|left|center-left|center-right|center|far-right|right-side|right|behind|leftwards|rightwards|inherit|scroll|fixed|transparent|none|repeat-x|repeat-y|repeat|no-repeat|collapse|separate|auto|top|bottom|both|open-quote|close-quote|no-open-quote|no-close-quote|crosshair|default|pointer|move|e-resize|ne-resize|nw-resize|n-resize|se-resize|sw-resize|s-resize|text|wait|help|ltr|rtl|inline|block|list-item|run-in|compact|marker|table|inline-table|table-row-group|table-header-group|table-footer-group|table-row|table-column-group|table-column|table-cell|table-caption|below|level|above|higher|lower|show|hide|caption|icon|menu|message-box|small-caption|status-bar|normal|wider|narrower|ultra-condensed|extra-condensed|condensed|semi-condensed|semi-expanded|expanded|extra-expanded|ultra-expanded|italic|oblique|small-caps|bold|bolder|lighter|inside|outside|disc|circle|square|decimal|decimal-leading-zero|lower-roman|upper-roman|lower-greek|lower-alpha|lower-latin|upper-alpha|upper-latin|hebrew|armenian|georgian|cjk-ideographic|hiragana|katakana|hiragana-iroha|katakana-iroha|crop|cross|invert|visible|hidden|always|avoid|x-low|low|medium|high|x-high|mix?|repeat?|static|relative|absolute|portrait|landscape|spell-out|once|digits|continuous|code|x-slow|slow|fast|x-fast|faster|slower|justify|underline|overline|line-through|blink|capitalize|uppercase|lowercase|embed|bidi-override|baseline|sub|super|text-top|middle|text-bottom|silent|x-soft|soft|loud|x-loud|pre|nowrap|serif|sans-serif|cursive|fantasy|monospace|empty|string|strict|loose|char|true|false|dotted|dashed|solid|double|groove|ridge|inset|outset|larger|smaller|xx-small|x-small|small|large|x-large|xx-large|all|newspaper|distribute|distribute-all-lines|distribute-center-last|inter-word|inter-ideograph|inter-cluster|kashida|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|keep-all|break-all|break-word|lr-tb|tb-rl|thin|thick|inline-block|w-resize|hand|distribute-letter|distribute-space|whitespace|male|female|child)$/',
'namedcolor' => '/^((?i)aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow|activeborder|activecaption|appworkspace|background|buttonface|buttonhighlight|buttonshadow|buttontext|captiontext|graytext|highlight|highlighttext|inactiveborder|inactivecaption|inactivecaptiontext|infobackground|infotext|menu|menutext|scrollbar|threeddarkshadow|threedface|threedhighlight|threedlightshadow|threedshadow|window|windowframe|windowtext)$/',
),
3 =>
array (
),
),
2 =>
array (
0 => -1,
1 => -1,
2 =>
array (
),
),
3 =>
array (
0 => -1,
1 => -1,
2 =>
array (
),
3 => -1,
),
4 =>
array (
0 =>
array (
),
),
5 =>
array (
0 =>
array (
),
),
6 =>
array (
0 =>
array (
),
),
);
$this->_parts = array (
0 =>
array (
),
1 =>
array (
0 =>
array (
1 => 'string',
),
1 => NULL,
2 => NULL,
3 => NULL,
),
2 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
),
3 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
),
4 =>
array (
0 => NULL,
),
5 =>
array (
0 => NULL,
),
6 =>
array (
0 => NULL,
),
);
$this->_subst = array (
-1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
),
0 =>
array (
),
1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
),
2 =>
array (
0 => false,
1 => false,
2 => false,
),
3 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
),
4 =>
array (
0 => false,
),
5 =>
array (
0 => false,
),
6 =>
array (
0 => false,
),
);
$this->_conditions = array (
);
$this->_kwmap = array (
'propertyValue' => 'string',
'namedcolor' => 'var',
);
$this->_defClass = 'code';
$this->_checkDefines();
}
}

View file

@ -0,0 +1,384 @@
<?php
/**
* Auto-generated class. DIFF syntax highlighting
*
* PHP version 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @link http://pear.php.net/package/Text_Highlighter
* @category Text
* @package Text_Highlighter
* @version generated from: : diff.xml,v 1.1 2007/06/03 02:35:28 ssttoo Exp
* @author Andrey Demenev <demenev@gmail.com>
*
*/
/**
* @ignore
*/
require_once 'Text/Highlighter.php';
/**
* Auto-generated class. DIFF syntax highlighting
*
* @author Andrey Demenev <demenev@gmail.com>
* @category Text
* @package Text_Highlighter
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: @package_version@
* @link http://pear.php.net/package/Text_Highlighter
*/
class Text_Highlighter_DIFF extends Text_Highlighter
{
var $_language = 'diff';
/**
* PHP4 Compatible Constructor
*
* @param array $options
* @access public
*/
function Text_Highlighter_DIFF($options=array())
{
$this->__construct($options);
}
/**
* Constructor
*
* @param array $options
* @access public
*/
function __construct($options=array())
{
$this->_options = $options;
$this->_regs = array (
-1 => '/((?m)^\\\\\\sNo\\snewline.+$)|((?m)^\\-\\-\\-$)|((?m)^(diff\\s+\\-|Only\\s+|Index).*$)|((?m)^(\\-\\-\\-|\\+\\+\\+)\\s.+$)|((?m)^\\*.*$)|((?m)^\\+.*$)|((?m)^!.*$)|((?m)^\\<\\s.*$)|((?m)^\\>\\s.*$)|((?m)^\\d+(\\,\\d+)?[acd]\\d+(,\\d+)?$)|((?m)^\\-.*$)|((?m)^\\+.*$)|((?m)^@@.+@@$)|((?m)^d\\d+\\s\\d+$)|((?m)^a\\d+\\s\\d+$)|((?m)^(\\d+)(,\\d+)?(a)$)|((?m)^(\\d+)(,\\d+)?(c)$)|((?m)^(\\d+)(,\\d+)?(d)$)|((?m)^a(\\d+)(\\s\\d+)?$)|((?m)^c(\\d+)(\\s\\d+)?$)|((?m)^d(\\d+)(\\s\\d+)?$)/',
0 => '//',
1 => '//',
2 => '//',
3 => '//',
4 => '//',
);
$this->_counts = array (
-1 =>
array (
0 => 0,
1 => 0,
2 => 1,
3 => 1,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 2,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
14 => 0,
15 => 3,
16 => 3,
17 => 3,
18 => 2,
19 => 2,
20 => 2,
),
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
);
$this->_delim = array (
-1 =>
array (
0 => '',
1 => '',
2 => '',
3 => '',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
9 => '',
10 => '',
11 => '',
12 => '',
13 => '',
14 => 'code',
15 => 'code',
16 => 'code',
17 => '',
18 => 'code',
19 => 'code',
20 => '',
),
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
);
$this->_inner = array (
-1 =>
array (
0 => 'special',
1 => 'code',
2 => 'var',
3 => 'reserved',
4 => 'quotes',
5 => 'string',
6 => 'inlinedoc',
7 => 'quotes',
8 => 'string',
9 => 'code',
10 => 'quotes',
11 => 'string',
12 => 'code',
13 => 'code',
14 => 'var',
15 => 'string',
16 => 'inlinedoc',
17 => 'code',
18 => 'string',
19 => 'inlinedoc',
20 => 'code',
),
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
);
$this->_end = array (
0 => '/(?m)(?=^[ad]\\d+\\s\\d+)/',
1 => '/(?m)^(\\.)$/',
2 => '/(?m)^(\\.)$/',
3 => '/(?m)^(\\.)$/',
4 => '/(?m)^(\\.)$/',
);
$this->_states = array (
-1 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
9 => -1,
10 => -1,
11 => -1,
12 => -1,
13 => -1,
14 => 0,
15 => 1,
16 => 2,
17 => -1,
18 => 3,
19 => 4,
20 => -1,
),
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
);
$this->_keywords = array (
-1 =>
array (
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
9 =>
array (
),
10 =>
array (
),
11 =>
array (
),
12 =>
array (
),
13 =>
array (
),
14 => -1,
15 => -1,
16 => -1,
17 =>
array (
),
18 => -1,
19 => -1,
20 =>
array (
),
),
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
);
$this->_parts = array (
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
);
$this->_subst = array (
-1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
9 => false,
10 => false,
11 => false,
12 => false,
13 => false,
14 => false,
15 => false,
16 => false,
17 => false,
18 => false,
19 => false,
20 => false,
),
0 =>
array (
),
1 =>
array (
),
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
);
$this->_conditions = array (
);
$this->_kwmap = array (
);
$this->_defClass = 'default';
$this->_checkDefines();
}
}

View file

@ -0,0 +1,426 @@
<?php
/**
* Auto-generated class. DTD syntax highlighting
*
* PHP version 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @link http://pear.php.net/package/Text_Highlighter
* @category Text
* @package Text_Highlighter
* @version generated from: : dtd.xml,v 1.1 2007/06/03 02:35:28 ssttoo Exp
* @author Andrey Demenev <demenev@gmail.com>
*
*/
/**
* @ignore
*/
require_once 'Text/Highlighter.php';
/**
* Auto-generated class. DTD syntax highlighting
*
* @author Andrey Demenev <demenev@gmail.com>
* @category Text
* @package Text_Highlighter
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: @package_version@
* @link http://pear.php.net/package/Text_Highlighter
*/
class Text_Highlighter_DTD extends Text_Highlighter
{
var $_language = 'dtd';
/**
* PHP4 Compatible Constructor
*
* @param array $options
* @access public
*/
function Text_Highlighter_DTD($options=array())
{
$this->__construct($options);
}
/**
* Constructor
*
* @param array $options
* @access public
*/
function __construct($options=array())
{
$this->_options = $options;
$this->_regs = array (
-1 => '/(\\<!--)|(\\<\\!\\[)|((\\&|\\%)[\\w\\-\\.]+;)/',
0 => '//',
1 => '/(\\<!--)|(\\<)|(#PCDATA\\b)|((\\&|\\%)[\\w\\-\\.]+;)|((?i)[a-z][a-z\\d\\-\\,:]+)/',
2 => '/(\\<!--)|(\\()|(\')|(")|((?<=\\<)!(ENTITY|ATTLIST|ELEMENT|NOTATION)\\b)|(\\s(#(IMPLIED|REQUIRED|FIXED))|CDATA|ENTITY|NOTATION|NMTOKENS?|PUBLIC|SYSTEM\\b)|(#PCDATA\\b)|((\\&|\\%)[\\w\\-\\.]+;)|((?i)[a-z][a-z\\d\\-\\,:]+)/',
3 => '/(\\()|((\\&|\\%)[\\w\\-\\.]+;)|((?i)[a-z][a-z\\d\\-\\,:]+)/',
4 => '/((\\&|\\%)[\\w\\-\\.]+;)/',
5 => '/((\\&|\\%)[\\w\\-\\.]+;)/',
);
$this->_counts = array (
-1 =>
array (
0 => 0,
1 => 0,
2 => 1,
),
0 =>
array (
),
1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 1,
4 => 0,
),
2 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 1,
5 => 2,
6 => 0,
7 => 1,
8 => 0,
),
3 =>
array (
0 => 0,
1 => 1,
2 => 0,
),
4 =>
array (
0 => 1,
),
5 =>
array (
0 => 1,
),
);
$this->_delim = array (
-1 =>
array (
0 => 'comment',
1 => 'brackets',
2 => '',
),
0 =>
array (
),
1 =>
array (
0 => 'comment',
1 => 'brackets',
2 => '',
3 => '',
4 => '',
),
2 =>
array (
0 => 'comment',
1 => 'brackets',
2 => 'quotes',
3 => 'quotes',
4 => '',
5 => '',
6 => '',
7 => '',
8 => '',
),
3 =>
array (
0 => 'brackets',
1 => '',
2 => '',
),
4 =>
array (
0 => '',
),
5 =>
array (
0 => '',
),
);
$this->_inner = array (
-1 =>
array (
0 => 'comment',
1 => 'code',
2 => 'special',
),
0 =>
array (
),
1 =>
array (
0 => 'comment',
1 => 'code',
2 => 'reserved',
3 => 'special',
4 => 'identifier',
),
2 =>
array (
0 => 'comment',
1 => 'code',
2 => 'string',
3 => 'string',
4 => 'var',
5 => 'reserved',
6 => 'reserved',
7 => 'special',
8 => 'identifier',
),
3 =>
array (
0 => 'code',
1 => 'special',
2 => 'identifier',
),
4 =>
array (
0 => 'special',
),
5 =>
array (
0 => 'special',
),
);
$this->_end = array (
0 => '/--\\>/',
1 => '/\\]\\]\\>/',
2 => '/\\>/',
3 => '/\\)/',
4 => '/\'/',
5 => '/"/',
);
$this->_states = array (
-1 =>
array (
0 => 0,
1 => 1,
2 => -1,
),
0 =>
array (
),
1 =>
array (
0 => 0,
1 => 2,
2 => -1,
3 => -1,
4 => -1,
),
2 =>
array (
0 => 0,
1 => 3,
2 => 4,
3 => 5,
4 => -1,
5 => -1,
6 => -1,
7 => -1,
8 => -1,
),
3 =>
array (
0 => 3,
1 => -1,
2 => -1,
),
4 =>
array (
0 => -1,
),
5 =>
array (
0 => -1,
),
);
$this->_keywords = array (
-1 =>
array (
0 => -1,
1 => -1,
2 =>
array (
),
),
0 =>
array (
),
1 =>
array (
0 => -1,
1 => -1,
2 =>
array (
),
3 =>
array (
),
4 =>
array (
),
),
2 =>
array (
0 => -1,
1 => -1,
2 => -1,
3 => -1,
4 =>
array (
),
5 =>
array (
),
6 =>
array (
),
7 =>
array (
),
8 =>
array (
),
),
3 =>
array (
0 => -1,
1 =>
array (
),
2 =>
array (
),
),
4 =>
array (
0 =>
array (
),
),
5 =>
array (
0 =>
array (
),
),
);
$this->_parts = array (
0 =>
array (
),
1 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
),
2 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
3 => NULL,
4 => NULL,
5 => NULL,
6 => NULL,
7 => NULL,
8 => NULL,
),
3 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
),
4 =>
array (
0 => NULL,
),
5 =>
array (
0 => NULL,
),
);
$this->_subst = array (
-1 =>
array (
0 => false,
1 => false,
2 => false,
),
0 =>
array (
),
1 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
),
2 =>
array (
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => false,
8 => false,
),
3 =>
array (
0 => false,
1 => false,
2 => false,
),
4 =>
array (
0 => false,
),
5 =>
array (
0 => false,
),
);
$this->_conditions = array (
);
$this->_kwmap = array (
);
$this->_defClass = 'code';
$this->_checkDefines();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,234 @@
<?php
/**
* Auto-generated class. HTML syntax highlighting
*
* PHP version 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @link http://pear.php.net/package/Text_Highlighter
* @category Text
* @package Text_Highlighter
* @version generated from: : html.xml,v 1.1 2007/06/03 02:35:28 ssttoo Exp
* @author Andrey Demenev <demenev@gmail.com>
*
*/
/**
* @ignore
*/
require_once 'Text/Highlighter.php';
/**
* Auto-generated class. HTML syntax highlighting
*
* @author Andrey Demenev <demenev@gmail.com>
* @category Text
* @package Text_Highlighter
* @copyright 2004-2006 Andrey Demenev
* @license http://www.php.net/license/3_0.txt PHP License
* @version Release: @package_version@
* @link http://pear.php.net/package/Text_Highlighter
*/
class Text_Highlighter_HTML extends Text_Highlighter
{
var $_language = 'html';
/**
* PHP4 Compatible Constructor
*
* @param array $options
* @access public
*/
function Text_Highlighter_HTML($options=array())
{
$this->__construct($options);
}
/**
* Constructor
*
* @param array $options
* @access public
*/
function __construct($options=array())
{
$this->_options = $options;
$this->_regs = array (
-1 => '/((?i)\\<!--)|((?i)\\<[\\?\\/]?)|((?i)(&)[\\w\\-\\.]+;)/',
0 => '//',
1 => '/((?i)(?<=[\\<\\/?])[\\w\\-\\:]+)|((?i)[\\w\\-\\:]+)|((?i)")/',
2 => '/((?i)(&)[\\w\\-\\.]+;)/',
);
$this->_counts = array (
-1 =>
array (
0 => 0,
1 => 0,
2 => 1,
),
0 =>
array (
),
1 =>
array (
0 => 0,
1 => 0,
2 => 0,
),
2 =>
array (
0 => 1,
),
);
$this->_delim = array (
-1 =>
array (
0 => 'comment',
1 => 'brackets',
2 => '',
),
0 =>
array (
),
1 =>
array (
0 => '',
1 => '',
2 => 'quotes',
),
2 =>
array (
0 => '',
),
);
$this->_inner = array (
-1 =>
array (
0 => 'comment',
1 => 'code',
2 => 'special',
),
0 =>
array (
),
1 =>
array (
0 => 'reserved',
1 => 'var',
2 => 'string',
),
2 =>
array (
0 => 'special',
),
);
$this->_end = array (
0 => '/(?i)--\\>/',
1 => '/(?i)[\\/\\?]?\\>/',
2 => '/(?i)"/',
);
$this->_states = array (
-1 =>
array (
0 => 0,
1 => 1,
2 => -1,
),
0 =>
array (
),
1 =>
array (
0 => -1,
1 => -1,
2 => 2,
),
2 =>
array (
0 => -1,
),
);
$this->_keywords = array (
-1 =>
array (
0 => -1,
1 => -1,
2 =>
array (
),
),
0 =>
array (
),
1 =>
array (
0 =>
array (
),
1 =>
array (
),
2 => -1,
),
2 =>
array (
0 =>
array (
),
),
);
$this->_parts = array (
0 =>
array (
),
1 =>
array (
0 => NULL,
1 => NULL,
2 => NULL,
),
2 =>
array (
0 => NULL,
),
);
$this->_subst = array (
-1 =>
array (
0 => false,
1 => false,
2 => false,
),
0 =>
array (
),
1 =>
array (
0 => false,
1 => false,
2 => false,
),
2 =>
array (
0 => false,
),
);
$this->_conditions = array (
);
$this->_kwmap = array (
);
$this->_defClass = 'code';
$this->_checkDefines();
}
}

Some files were not shown because too many files have changed in this diff Show more